On Wed, 29 Mar 2023 11:28:53 GMT, Aleksey Shipilev <sh...@openjdk.org> wrote:
> Java API has the `Thread.sleep(millis, nanos)` method exposed to users. The > documentation for that method clearly says the precision and accuracy are > dependent on the underlying system behavior. However, it always rounds up > `nanos` to 1ms when doing the actual sleep. This means users cannot do the > micro-second precision sleeps, even when the underlying platform allows it. > Sub-millisecond sleeps are useful to build interesting primitives, like the > rate limiters that run with >1000 RPS. > > When faced with this, some users reach for more awkward APIs like > `java.util.concurrent.locks.LockSupport.parkNanos`. The use of that API for > sleeps is not in line with its intent, and while it "seems to work", it might > have interesting interactions with other uses of `LockSupport`. Additionally, > these "sleeps" are no longer visible to monitoring tools as "normal sleeps", > e.g. as `Thread.sleep` events. Therefore, it would be prudent to improve > current `Thread.sleep(millis, nanos)` for sub-millisecond granularity. > > Fortunately, the underlying code is almost ready for this, at least on POSIX > side. I skipped Windows paths, because its timers are still no good. Note > that on both Linux and MacOS timers oversleep by about 50us. I have a few > ideas how to improve the accuracy for them, which would be a topic for a > separate PR. > > Motivational improvements on new benchmark below: > > m6g.9xlarge (Linux, Xeon, x86_64): > > > Benchmark (sleep) Mode Cnt Score Error > Units > > # ========= no regressions for Thread.sleep(millis) > > # Baseline > ThreadSleep.millis 0 avgt 5 463.606 ± 8.256 ns/op > ThreadSleep.millis 1 avgt 5 459.434 ± 0.453 ns/op > ThreadSleep.millis 10 avgt 5 462.828 ± 1.283 ns/op > ThreadSleep.millis 100 avgt 5 459.495 ± 3.244 ns/op > ThreadSleep.millis 1000 avgt 5 457.962 ± 5.769 ns/op > ThreadSleep.millis 10000 avgt 5 457.960 ± 1.195 ns/op > ThreadSleep.millis 100000 avgt 5 459.197 ± 3.054 ns/op > ThreadSleep.millis 1000000 avgt 5 1058342.873 ± 304.169 ns/op > ThreadSleep.millis 10000000 avgt 5 10059945.148 ± 1642.411 ns/op > ThreadSleep.millis 100000000 avgt 5 100062181.340 ± 1863.186 ns/op > ThreadSleep.millis 1000000000 avgt 5 1000070015.600 ± 11379.631 ns/op > > # Patched > ThreadSleep.millis 0 avgt 5 461.295 ± 6.700 ns/op > ThreadSleep.millis 1 avgt 5 463.383 ± 3.065 ns/op > ThreadSleep.millis 10 avgt 5 468.109 ± 1.607 ns/op > ThreadSleep.millis 100 avgt 5 467.316 ± 0.270 ns/op > ThreadSleep.millis 1000 avgt 5 461.999 ± 2.341 ns/op > ThreadSleep.millis 10000 avgt 5 465.075 ± 0.324 ns/op > ThreadSleep.millis 100000 avgt 5 462.588 ± 5.321 ns/op > ThreadSleep.millis 1000000 avgt 5 1058285.440 ± 409.376 ns/op > ThreadSleep.millis 10000000 avgt 5 10060437.490 ± 177.754 ns/op > ThreadSleep.millis 100000000 avgt 5 100060665.980 ± 1167.514 ns/op > ThreadSleep.millis 1000000000 avgt 5 1000071917.300 ± 17438.906 ns/op > > # ========= Significant improvements for Thread.sleep(millis, nanos) > > # Baseline > ThreadSleep.millisNanos 0 avgt 5 462.831 ± 0.251 > ns/op > ThreadSleep.millisNanos 1 avgt 5 1058708.668 ± 960.683 > ns/op > ThreadSleep.millisNanos 10 avgt 5 1058364.414 ± 197.700 > ns/op > ThreadSleep.millisNanos 100 avgt 5 1058451.889 ± 561.979 > ns/op > ThreadSleep.millisNanos 1000 avgt 5 1058372.010 ± 96.867 > ns/op > ThreadSleep.millisNanos 10000 avgt 5 1058354.100 ± 297.148 > ns/op > ThreadSleep.millisNanos 100000 avgt 5 1058485.092 ± 1093.340 > ns/op > ThreadSleep.millisNanos 1000000 avgt 5 1059004.036 ± 1899.950 > ns/op > ThreadSleep.millisNanos 10000000 avgt 5 10059733.302 ± 1725.908 > ns/op > ThreadSleep.millisNanos 100000000 avgt 5 100063327.840 ± 6244.805 > ns/op > ThreadSleep.millisNanos 1000000000 avgt 5 1000074542.300 ± 17898.173 > ns/op > > # Patched > ThreadSleep.millisNanos 0 avgt 5 467.968 ± 9.202 > ns/op > ThreadSleep.millisNanos 1 avgt 5 579.448 ± 1.363 > ns/op > ThreadSleep.millisNanos 10 avgt 5 577.656 ± 0.278 > ns/op > ThreadSleep.millisNanos 100 avgt 5 58092.815 ± 2410.401 > ns/op > ThreadSleep.millisNanos 1000 avgt 5 58592.249 ± 189.232 > ns/op > ThreadSleep.millisNanos 10000 avgt 5 67668.688 ± 591.365 > ns/op > ThreadSleep.millisNanos 100000 avgt 5 158143.164 ± 2281.540 > ns/op > ThreadSleep.millisNanos 1000000 avgt 5 1058508.682 ± 155.767 > ns/op > ThreadSleep.millisNanos 10000000 avgt 5 10059979.272 ± 1095.207 > ns/op > ThreadSleep.millisNanos 100000000 avgt 5 100066844.180 ± 4287.440 > ns/op > ThreadSleep.millisNanos 1000000000 avgt 5 1000075313.100 ± 9665.656 > ns/op > > > m6g.4xlarge (Linux, Graviton, AArch64): > > > # ========= no regressions for Thread.sleep(millis) > > # Baseline > ThreadSleep.millis 0 avgt 5 429.403 ± 24.947 ns/op > ThreadSleep.millis 1 avgt 5 427.533 ± 7.969 ns/op > ThreadSleep.millis 10 avgt 5 438.464 ± 10.277 ns/op > ThreadSleep.millis 100 avgt 5 425.626 ± 3.371 ns/op > ThreadSleep.millis 1000 avgt 5 426.465 ± 4.501 ns/op > ThreadSleep.millis 10000 avgt 5 427.235 ± 6.916 ns/op > ThreadSleep.millis 100000 avgt 5 430.311 ± 4.073 ns/op > ThreadSleep.millis 1000000 avgt 5 1054808.881 ± 469.409 ns/op > ThreadSleep.millis 10000000 avgt 5 10055497.206 ± 2123.591 ns/op > ThreadSleep.millis 100000000 avgt 5 100059355.520 ± 11597.426 ns/op > ThreadSleep.millis 1000000000 avgt 5 1000073145.400 ± 7659.244 ns/op > > # Patched > ThreadSleep.millis 0 avgt 5 429.535 ± 2.597 ns/op > ThreadSleep.millis 1 avgt 5 425.209 ± 3.620 ns/op > ThreadSleep.millis 10 avgt 5 432.416 ± 9.350 ns/op > ThreadSleep.millis 100 avgt 5 432.867 ± 3.978 ns/op > ThreadSleep.millis 1000 avgt 5 426.627 ± 1.064 ns/op > ThreadSleep.millis 10000 avgt 5 427.180 ± 4.691 ns/op > ThreadSleep.millis 100000 avgt 5 438.554 ± 4.271 ns/op > ThreadSleep.millis 1000000 avgt 5 1054693.226 ± 323.240 ns/op > ThreadSleep.millis 10000000 avgt 5 10056408.240 ± 1759.211 ns/op > ThreadSleep.millis 100000000 avgt 5 100062449.780 ± 15133.808 ns/op > ThreadSleep.millis 1000000000 avgt 5 1000066918.500 ± 15817.822 ns/op > > # ========= Significant improvements for Thread.sleep(millis, nanos) > > # Baseline > ThreadSleep.millisNanos 0 avgt 5 439.163 ± 5.559 > ns/op > ThreadSleep.millisNanos 1 avgt 5 1054751.231 ± 431.842 > ns/op > ThreadSleep.millisNanos 10 avgt 5 1054640.725 ± 525.901 > ns/op > ThreadSleep.millisNanos 100 avgt 5 1054807.619 ± 1009.104 > ns/op > ThreadSleep.millisNanos 1000 avgt 5 1054894.829 ± 1946.551 > ns/op > ThreadSleep.millisNanos 10000 avgt 5 1054765.444 ± 701.873 > ns/op > ThreadSleep.millisNanos 100000 avgt 5 1054707.758 ± 619.054 > ns/op > ThreadSleep.millisNanos 1000000 avgt 5 1054802.230 ± 1294.035 > ns/op > ThreadSleep.millisNanos 10000000 avgt 5 10055265.430 ± 1184.281 > ns/op > ThreadSleep.millisNanos 100000000 avgt 5 100057484.300 ± 7960.939 > ns/op > ThreadSleep.millisNanos 1000000000 avgt 5 1000062244.700 ± 20244.067 > ns/op > > # Patched > ThreadSleep.millisNanos 0 avgt 5 426.482 ± 10.284 > ns/op > ThreadSleep.millisNanos 1 avgt 5 565.819 ± 1.098 > ns/op > ThreadSleep.millisNanos 10 avgt 5 564.108 ± 3.493 > ns/op > ThreadSleep.millisNanos 100 avgt 5 53698.839 ± 942.506 > ns/op > ThreadSleep.millisNanos 1000 avgt 5 55205.929 ± 416.951 > ns/op > ThreadSleep.millisNanos 10000 avgt 5 64206.709 ± 382.213 > ns/op > ThreadSleep.millisNanos 100000 avgt 5 154477.045 ± 125.316 > ns/op > ThreadSleep.millisNanos 1000000 avgt 5 1054889.472 ± 2152.765 > ns/op > ThreadSleep.millisNanos 10000000 avgt 5 10055273.582 ± 691.628 > ns/op > ThreadSleep.millisNanos 100000000 avgt 5 100058261.300 ± 5222.946 > ns/op > ThreadSleep.millisNanos 1000000000 avgt 5 1000065434.000 ± 30213.137 > ns/op > > > MacBook 2021 (MacOS X, M1, AArch64): > > > # ========= no regressions for Thread.sleep(millis) > > # Baseline > Benchmark (sleep) Mode Cnt Score Error > Units > ThreadSleep.millis 0 avgt 5 555,871 ± 525,544 > ns/op > ThreadSleep.millis 1 avgt 5 405,761 ± 153,981 > ns/op > ThreadSleep.millis 10 avgt 5 403,906 ± 279,245 > ns/op > ThreadSleep.millis 100 avgt 5 402,787 ± 223,658 > ns/op > ThreadSleep.millis 1000 avgt 5 439,250 ± 374,150 > ns/op > ThreadSleep.millis 10000 avgt 5 435,769 ± 352,067 > ns/op > ThreadSleep.millis 100000 avgt 5 1853,664 ± 7254,716 > ns/op > ThreadSleep.millis 1000000 avgt 5 1364788,214 ± 66446,869 > ns/op > ThreadSleep.millis 10000000 avgt 5 11819681,019 ± 473810,685 > ns/op > ThreadSleep.millis 100000000 avgt 5 103536901,660 ± 1423282,032 > ns/op > ThreadSleep.millis 1000000000 avgt 5 1002995262,600 ± 6576388,880 > ns/op > > # Patched > ThreadSleep.millis 0 avgt 5 662,597 ± 459,888 > ns/op > ThreadSleep.millis 1 avgt 5 433,561 ± 214,850 > ns/op > ThreadSleep.millis 10 avgt 5 388,614 ± 65,199 > ns/op > ThreadSleep.millis 100 avgt 5 436,823 ± 636,901 > ns/op > ThreadSleep.millis 1000 avgt 5 337,046 ± 129,440 > ns/op > ThreadSleep.millis 10000 avgt 5 366,557 ± 510,494 > ns/op > ThreadSleep.millis 100000 avgt 5 278,339 ± 102,443 > ns/op > ThreadSleep.millis 1000000 avgt 5 1520092,133 ± 26217,972 > ns/op > ThreadSleep.millis 10000000 avgt 5 13116509,001 ± 855508,621 > ns/op > ThreadSleep.millis 100000000 avgt 5 107010708,340 ± 1667080,292 > ns/op > ThreadSleep.millis 1000000000 avgt 5 1005412095,700 ± 6141267,753 > ns/op > > # ========= Significant improvements for Thread.sleep(millis, nanos) > > # Baseline > ThreadSleep.millisNanos 0 avgt 5 245,942 ± 44,338 > ns/op > ThreadSleep.millisNanos 1 avgt 5 1313354,886 ± 71820,989 > ns/op > ThreadSleep.millisNanos 10 avgt 5 1310358,568 ± 42731,583 > ns/op > ThreadSleep.millisNanos 100 avgt 5 1335221,078 ± 122031,471 > ns/op > ThreadSleep.millisNanos 1000 avgt 5 1313977,625 ± 30683,810 > ns/op > ThreadSleep.millisNanos 10000 avgt 5 1553321,472 ± 75181,324 > ns/op > ThreadSleep.millisNanos 100000 avgt 5 1553317,573 ± 132998,558 > ns/op > ThreadSleep.millisNanos 1000000 avgt 5 1544944,015 ± 41587,129 > ns/op > ThreadSleep.millisNanos 10000000 avgt 5 13228565,376 ± 902384,381 > ns/op > ThreadSleep.millisNanos 100000000 avgt 5 106866740,840 ± 2518606,524 > ns/op > ThreadSleep.millisNanos 1000000000 avgt 5 1006669020,800 ± 10961093,568 > ns/op > > # Patched > ThreadSleep.millisNanos 0 avgt 5 394,716 ± 310,886 > ns/op > ThreadSleep.millisNanos 1 avgt 5 9945,543 ± 905,136 > ns/op > ThreadSleep.millisNanos 10 avgt 5 9863,605 ± 557,909 > ns/op > ThreadSleep.millisNanos 100 avgt 5 2454,862 ± 323,279 > ns/op > ThreadSleep.millisNanos 1000 avgt 5 3834,507 ± 2427,033 > ns/op > ThreadSleep.millisNanos 10000 avgt 5 16667,415 ± 508,814 > ns/op > ThreadSleep.millisNanos 100000 avgt 5 154202,589 ± 258,406 > ns/op > ThreadSleep.millisNanos 1000000 avgt 5 1557886,136 ± 192080,832 > ns/op > ThreadSleep.millisNanos 10000000 avgt 5 13077385,237 ± 887650,194 > ns/op > ThreadSleep.millisNanos 100000000 avgt 5 106225257,480 ± 3288589,410 > ns/op > ThreadSleep.millisNanos 1000000000 avgt 5 1006589558,200 ± 3677828,811 > ns/op > > > Additional testing: > - [x] New regression test > - [x] New benchmark > - [x] Linux x86_64 `tier1` > - [x] Linux AArch64 `tier1` Are there specific factors which would make it unreasonable to implement `sleep` in terms of `parkNanos`? ------------- PR Comment: https://git.openjdk.org/jdk/pull/13225#issuecomment-1488952226