8214180: Need better granularity for sleeping
authorrehn
Thu, 20 Dec 2018 10:05:19 +0100
changeset 53077 33b8f6f4cdf5
parent 53076 dd5d7ba5b539
child 53078 90909cac17f7
8214180: Need better granularity for sleeping Reviewed-by: eosterlund, dcubed, dholmes
src/hotspot/os/aix/os_aix.cpp
src/hotspot/os/bsd/os_bsd.cpp
src/hotspot/os/linux/os_linux.cpp
src/hotspot/os/posix/os_posix.cpp
src/hotspot/os/solaris/os_solaris.cpp
src/hotspot/os/windows/os_windows.cpp
src/hotspot/share/runtime/os.hpp
src/hotspot/share/utilities/spinYield.cpp
src/hotspot/share/utilities/spinYield.hpp
--- 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() {