# HG changeset patch # User rehn # Date 1545296719 -3600 # Node ID 33b8f6f4cdf51aac4d6a459656d7c2ecade65150 # Parent dd5d7ba5b539eada7cb6389815b0e13139c96790 8214180: Need better granularity for sleeping Reviewed-by: eosterlund, dcubed, dholmes diff -r dd5d7ba5b539 -r 33b8f6f4cdf5 src/hotspot/os/aix/os_aix.cpp --- a/src/hotspot/os/aix/os_aix.cpp Thu Dec 20 02:51:01 2018 +0100 +++ b/src/hotspot/os/aix/os_aix.cpp Thu Dec 20 10:05:19 2018 +0100 @@ -2602,23 +2602,6 @@ return ::pread(fd, buf, nBytes, offset); } -void os::naked_short_sleep(jlong ms) { - struct timespec req; - - assert(ms < 1000, "Un-interruptable sleep, short time use only"); - req.tv_sec = 0; - if (ms > 0) { - req.tv_nsec = (ms % 1000) * 1000000; - } - else { - req.tv_nsec = 1; - } - - nanosleep(&req, NULL); - - return; -} - // Sleep forever; naked call to OS-specific sleep; use with CAUTION void os::infinite_sleep() { while (true) { // sleep forever ... diff -r dd5d7ba5b539 -r 33b8f6f4cdf5 src/hotspot/os/bsd/os_bsd.cpp --- a/src/hotspot/os/bsd/os_bsd.cpp Thu Dec 20 02:51:01 2018 +0100 +++ b/src/hotspot/os/bsd/os_bsd.cpp Thu Dec 20 10:05:19 2018 +0100 @@ -2225,22 +2225,6 @@ RESTARTABLE_RETURN_INT(::pread(fd, buf, nBytes, offset)); } -void os::naked_short_sleep(jlong ms) { - struct timespec req; - - assert(ms < 1000, "Un-interruptable sleep, short time use only"); - req.tv_sec = 0; - if (ms > 0) { - req.tv_nsec = (ms % 1000) * 1000000; - } else { - req.tv_nsec = 1; - } - - nanosleep(&req, NULL); - - return; -} - // Sleep forever; naked call to OS-specific sleep; use with CAUTION void os::infinite_sleep() { while (true) { // sleep forever ... diff -r dd5d7ba5b539 -r 33b8f6f4cdf5 src/hotspot/os/linux/os_linux.cpp --- a/src/hotspot/os/linux/os_linux.cpp Thu Dec 20 02:51:01 2018 +0100 +++ b/src/hotspot/os/linux/os_linux.cpp Thu Dec 20 10:05:19 2018 +0100 @@ -4033,33 +4033,6 @@ return ::pread(fd, buf, nBytes, offset); } -// Short sleep, direct OS call. -// -// Note: certain versions of Linux CFS scheduler (since 2.6.23) do not guarantee -// sched_yield(2) will actually give up the CPU: -// -// * Alone on this pariticular CPU, keeps running. -// * Before the introduction of "skip_buddy" with "compat_yield" disabled -// (pre 2.6.39). -// -// So calling this with 0 is an alternative. -// -void os::naked_short_sleep(jlong ms) { - struct timespec req; - - assert(ms < 1000, "Un-interruptable sleep, short time use only"); - req.tv_sec = 0; - if (ms > 0) { - req.tv_nsec = (ms % 1000) * 1000000; - } else { - req.tv_nsec = 1; - } - - nanosleep(&req, NULL); - - return; -} - // Sleep forever; naked call to OS-specific sleep; use with CAUTION void os::infinite_sleep() { while (true) { // sleep forever ... @@ -4072,6 +4045,16 @@ return DontYieldALot; } +// Linux CFS scheduler (since 2.6.23) does not guarantee sched_yield(2) will +// actually give up the CPU. Since skip buddy (v2.6.28): +// +// * Sets the yielding task as skip buddy for current CPU's run queue. +// * Picks next from run queue, if empty, picks a skip buddy (can be the yielding task). +// * Clears skip buddies for this run queue (yielding task no longer a skip buddy). +// +// An alternative is calling os::naked_short_nanosleep with a small number to avoid +// getting re-scheduled immediately. +// void os::naked_yield() { sched_yield(); } diff -r dd5d7ba5b539 -r 33b8f6f4cdf5 src/hotspot/os/posix/os_posix.cpp --- a/src/hotspot/os/posix/os_posix.cpp Thu Dec 20 02:51:01 2018 +0100 +++ b/src/hotspot/os/posix/os_posix.cpp Thu Dec 20 10:05:19 2018 +0100 @@ -695,6 +695,21 @@ } } +void os::naked_short_nanosleep(jlong ns) { + struct timespec req; + assert(ns > -1 && ns < NANOUNITS, "Un-interruptable sleep, short time use only"); + req.tv_sec = 0; + req.tv_nsec = ns; + ::nanosleep(&req, NULL); + return; +} + +void os::naked_short_sleep(jlong ms) { + assert(ms < MILLIUNITS, "Un-interruptable sleep, short time use only"); + os::naked_short_nanosleep(ms * (NANOUNITS / MILLIUNITS)); + return; +} + //////////////////////////////////////////////////////////////////////////////// // interrupt support diff -r dd5d7ba5b539 -r 33b8f6f4cdf5 src/hotspot/os/solaris/os_solaris.cpp --- a/src/hotspot/os/solaris/os_solaris.cpp Thu Dec 20 02:51:01 2018 +0100 +++ b/src/hotspot/os/solaris/os_solaris.cpp Thu Dec 20 10:05:19 2018 +0100 @@ -2871,16 +2871,6 @@ return res; } -void os::naked_short_sleep(jlong ms) { - assert(ms < 1000, "Un-interruptable sleep, short time use only"); - - // usleep is deprecated and removed from POSIX, in favour of nanosleep, but - // Solaris requires -lrt for this. - usleep((ms * 1000)); - - return; -} - // Sleep forever; naked call to OS-specific sleep; use with CAUTION void os::infinite_sleep() { while (true) { // sleep forever ... diff -r dd5d7ba5b539 -r 33b8f6f4cdf5 src/hotspot/os/windows/os_windows.cpp --- a/src/hotspot/os/windows/os_windows.cpp Thu Dec 20 02:51:01 2018 +0100 +++ b/src/hotspot/os/windows/os_windows.cpp Thu Dec 20 10:05:19 2018 +0100 @@ -3512,6 +3512,43 @@ Sleep(ms); } +void os::naked_short_nanosleep(jlong ns) { + assert(ns > -1 && ns < NANOUNITS, "Un-interruptable sleep, short time use only"); + LARGE_INTEGER hundreds_nanos = { 0 }; + HANDLE wait_timer = ::CreateWaitableTimer(NULL /* attributes*/, + true /* manual reset */, + NULL /* name */ ); + if (wait_timer == NULL) { + log_warning(os)("Failed to CreateWaitableTimer: %u", GetLastError()); + return; + } + + // We need a minimum of one hundred nanos. + ns = ns > 100 ? ns : 100; + + // Round ns to the nearst hundred of nanos. + // Negative values indicate relative time. + hundreds_nanos.QuadPart = -((ns + 50) / 100); + + if (::SetWaitableTimer(wait_timer /* handle */, + &hundreds_nanos /* due time */, + 0 /* period */, + NULL /* comp func */, + NULL /* comp func args */, + FALSE /* resume */)) { + DWORD res = ::WaitForSingleObject(wait_timer /* handle */, INFINITE /* timeout */); + if (res != WAIT_OBJECT_0) { + if (res == WAIT_FAILED) { + log_warning(os)("Failed to WaitForSingleObject: %u", GetLastError()); + } else { + log_warning(os)("Unexpected return from WaitForSingleObject: %s", + res == WAIT_ABANDONED ? "WAIT_ABANDONED" : "WAIT_TIMEOUT"); + } + } + } + ::CloseHandle(wait_timer /* handle */); +} + // Sleep forever; naked call to OS-specific sleep; use with CAUTION void os::infinite_sleep() { while (true) { // sleep forever ... diff -r dd5d7ba5b539 -r 33b8f6f4cdf5 src/hotspot/share/runtime/os.hpp --- a/src/hotspot/share/runtime/os.hpp Thu Dec 20 02:51:01 2018 +0100 +++ b/src/hotspot/share/runtime/os.hpp Thu Dec 20 10:05:19 2018 +0100 @@ -474,6 +474,7 @@ // Ignores Thread.interrupt() (so keep it short). // ms = 0, will sleep for the least amount of time allowed by the OS. static void naked_short_sleep(jlong ms); + static void naked_short_nanosleep(jlong ns); static void infinite_sleep(); // never returns, use with CAUTION static void naked_yield () ; static OSReturn set_priority(Thread* thread, ThreadPriority priority); diff -r dd5d7ba5b539 -r 33b8f6f4cdf5 src/hotspot/share/utilities/spinYield.cpp --- a/src/hotspot/share/utilities/spinYield.cpp Thu Dec 20 02:51:01 2018 +0100 +++ b/src/hotspot/share/utilities/spinYield.cpp Thu Dec 20 10:05:19 2018 +0100 @@ -27,12 +27,13 @@ #include "utilities/ostream.hpp" #include "utilities/spinYield.hpp" -SpinYield::SpinYield(uint spin_limit, uint yield_limit) : +SpinYield::SpinYield(uint spin_limit, uint yield_limit, uint sleep_ns) : _sleep_time(), _spins(0), _yields(0), _spin_limit(os::is_MP() ? spin_limit : 0), - _yield_limit(yield_limit) + _yield_limit(yield_limit), + _sleep_ns(sleep_ns) {} void SpinYield::yield_or_sleep() { @@ -41,7 +42,7 @@ os::naked_yield(); } else { Ticks sleep_start = Ticks::now(); - os::naked_short_sleep(1); + os::naked_short_nanosleep(_sleep_ns); _sleep_time += Ticks::now() - sleep_start; } } diff -r dd5d7ba5b539 -r 33b8f6f4cdf5 src/hotspot/share/utilities/spinYield.hpp --- a/src/hotspot/share/utilities/spinYield.hpp Thu Dec 20 02:51:01 2018 +0100 +++ b/src/hotspot/share/utilities/spinYield.hpp Thu Dec 20 10:05:19 2018 +0100 @@ -39,16 +39,19 @@ uint _yields; uint _spin_limit; uint _yield_limit; + uint _sleep_ns; void yield_or_sleep(); public: static const uint default_spin_limit = 4096; static const uint default_yield_limit = 64; + static const uint default_sleep_ns = 1000; // spin_limit is ignored (treated as zero) when !os::is_MP(). explicit SpinYield(uint spin_limit = default_spin_limit, - uint yield_limit = default_yield_limit); + uint yield_limit = default_yield_limit, + uint sleep_ns = default_sleep_ns); // Perform next round of delay. void wait() {