Go Reference

powernap

A more precise sleep for Go.

time.Sleep only promises to sleep for at least the duration specified. The amount of overshooting can be quite large and totally random. When microsecond precision is needed, powernap can be the solution you need. Depending on your system, it becomes relatively precise above 1-10 µs.

powernap was created for the cases, where you’re willing to give up CPU cycles for precision.

When possible, a safe part of the duration is done with time.Sleep, which probably happens around 1-10 ms, the rest is done by looping until the total duration has elapsed.

WARNING!

powernap can undershoot and makes no promises of sleeping “at least” for the duration given. The promise is: Spend CPU cycles to get as close as possible to the wanted duration, but be smart about it.

Benchmark

It can be hard to describe the precise effect, so the following benchmark will show you the differences. You can run this benchmark yourself with go test -bench . The last value ns/op should be as close as possible to the test names, e.g.: 100ns.

Concurrently on 8 cores:

$ go test -run none -bench Sleep
goos: darwin
goarch: amd64
pkg: github.com/flowstack/powernap
cpu: Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
BenchmarkNativeSleep/1ns-8         	 3536488	       326.6 ns/op
BenchmarkNativeSleep/10ns-8        	 3689028	       381.6 ns/op
BenchmarkNativeSleep/100ns-8       	 3190173	       375.6 ns/op
BenchmarkNativeSleep/1µs-8         	  247800	      4774 ns/op
BenchmarkNativeSleep/10µs-8        	   68730	     17550 ns/op
BenchmarkNativeSleep/100µs-8       	   10000	    123087 ns/op
BenchmarkNativeSleep/1ms-8         	     990	   1224108 ns/op
BenchmarkNativeSleep/10ms-8        	     100	  10725712 ns/op
BenchmarkNativeSleep/100ms-8       	      10	 100716765 ns/op
BenchmarkNativeSleep/1s-8          	       1	1001166003 ns/op
BenchmarkSleep/1ns-8               	629736540	         1.702 ns/op
BenchmarkSleep/10ns-8              	709374637	         1.702 ns/op
BenchmarkSleep/100ns-8             	704617651	         1.750 ns/op
BenchmarkSleep/1µs-8               	 1258404	       955.8 ns/op
BenchmarkSleep/10µs-8              	  118515	     10071 ns/op
BenchmarkSleep/100µs-8             	   10000	    100369 ns/op
BenchmarkSleep/1ms-8               	    1195	   1001152 ns/op
BenchmarkSleep/10ms-8              	     100	  10001149 ns/op
BenchmarkSleep/100ms-8             	      10	 100001272 ns/op
BenchmarkSleep/1s-8                	       1	1000001705 ns/op
BenchmarkSleepTight/1ns-8          	849490861	         1.334 ns/op
BenchmarkSleepTight/10ns-8         	894458509	         1.329 ns/op
BenchmarkSleepTight/100ns-8        	889052098	         1.338 ns/op
BenchmarkSleepTight/1µs-8          	 1261166	       951.8 ns/op
BenchmarkSleepTight/10µs-8         	  119665	     10063 ns/op
BenchmarkSleepTight/100µs-8        	   10000	    100284 ns/op
BenchmarkSleepTight/1ms-8          	    1198	   1000986 ns/op
BenchmarkSleepTight/10ms-8         	     100	  10001330 ns/op
BenchmarkSleepTight/100ms-8        	      10	 100001676 ns/op
BenchmarkSleepTight/1s-8           	       1	1000001133 ns/op

Single core:

[email protected] powernap % go test -run none -bench Sleep -cpu 1
goos: darwin
goarch: amd64
pkg: github.com/flowstack/powernap
cpu: Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
BenchmarkNativeSleep/1ns         	 5085195	       233.6 ns/op
BenchmarkNativeSleep/10ns        	 5142007	       236.5 ns/op
BenchmarkNativeSleep/100ns       	 4457294	       270.4 ns/op
BenchmarkNativeSleep/1µs         	  180474	      7996 ns/op
BenchmarkNativeSleep/10µs        	   75409	     17928 ns/op
BenchmarkNativeSleep/100µs       	    9898	    122517 ns/op
BenchmarkNativeSleep/1ms         	    1003	   1199280 ns/op
BenchmarkNativeSleep/10ms        	     100	  10689748 ns/op
BenchmarkNativeSleep/100ms       	      10	 100724174 ns/op
BenchmarkNativeSleep/1s          	       1	1000857441 ns/op
BenchmarkSleep/1ns               	648314174	         1.727 ns/op
BenchmarkSleep/10ns              	711528026	         1.711 ns/op
BenchmarkSleep/100ns             	709085366	         1.697 ns/op
BenchmarkSleep/1µs               	 1205494	       995.1 ns/op
BenchmarkSleep/10µs              	  118809	     10088 ns/op
BenchmarkSleep/100µs             	   10000	    100476 ns/op
BenchmarkSleep/1ms               	    1198	   1001545 ns/op
BenchmarkSleep/10ms              	     100	  10050768 ns/op
BenchmarkSleep/100ms             	      10	 100001051 ns/op
BenchmarkSleep/1s                	       1	1000001569 ns/op
BenchmarkSleepTight/1ns          	850477741	         1.333 ns/op
BenchmarkSleepTight/10ns         	902038443	         1.376 ns/op
BenchmarkSleepTight/100ns        	865685815	         1.364 ns/op
BenchmarkSleepTight/1µs          	 1000000	      1004 ns/op
BenchmarkSleepTight/10µs         	  118332	     10241 ns/op
BenchmarkSleepTight/100µs        	   10000	    100610 ns/op
BenchmarkSleepTight/1ms          	    1198	   1000424 ns/op
BenchmarkSleepTight/10ms         	     100	  10000950 ns/op
BenchmarkSleepTight/100ms        	      10	 100000714 ns/op
BenchmarkSleepTight/1s           	       1	1000001179 ns/op

Acknowledgement

The basic idea came from the Rust crate (library) spin_sleep.

GitHub

View Github