8214180: Need better granularity for sleeping
Reviewed-by: eosterlund, dcubed, dholmes
--- 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 ...
--- 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 ...
--- 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();
}
--- 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
--- 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 ...
--- 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 ...
--- 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);
--- 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;
}
}
--- 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() {