# HG changeset patch # User rwestberg # Date 1556107400 -7200 # Node ID 0b6dc5b93306b91e210864f9651e31cebc94bf77 # Parent 13b67c1420b8757ea0b643f5baa5cf2afab3b4a8 8220795: Rework naked_short_nanosleep on Windows to improve time-to-safepoint Reviewed-by: dholmes, rehn diff -r 13b67c1420b8 -r 0b6dc5b93306 src/hotspot/os/windows/os_windows.cpp --- a/src/hotspot/os/windows/os_windows.cpp Thu Apr 25 10:41:49 2019 +0100 +++ b/src/hotspot/os/windows/os_windows.cpp Wed Apr 24 14:03:20 2019 +0200 @@ -3558,41 +3558,19 @@ Sleep(ms); } +// Windows does not provide sleep functionality with nanosecond resolution, so we +// try to approximate this with spinning combined with yielding if another thread +// is ready to run on the current processor. 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"); - } + + int64_t start = os::javaTimeNanos(); + do { + if (SwitchToThread() == 0) { + // Nothing else is ready to run on this cpu, spin a little + SpinPause(); } - } - ::CloseHandle(wait_timer /* handle */); + } while (os::javaTimeNanos() - start < ns); } // Sleep forever; naked call to OS-specific sleep; use with CAUTION diff -r 13b67c1420b8 -r 0b6dc5b93306 src/hotspot/share/runtime/safepoint.cpp --- a/src/hotspot/share/runtime/safepoint.cpp Thu Apr 25 10:41:49 2019 +0100 +++ b/src/hotspot/share/runtime/safepoint.cpp Wed Apr 24 14:03:20 2019 +0200 @@ -186,16 +186,14 @@ } #endif // ASSERT -static void back_off(int iteration) { - // iteration will be 1 the first time we enter this spin back-off. - // naked_short_nanosleep takes tenths of micros which means that - // number of nanoseconds is irrelevant if it's below that. We do - // 20 1 ns sleeps with a total cost of ~1 ms, then we do 1 ms sleeps. - jlong sleep_ns = 1; - if (iteration > 20) { - sleep_ns = NANOUNITS / MILLIUNITS; // 1 ms +static void back_off(int64_t start_time) { + // We start with fine-grained nanosleeping until a millisecond has + // passed, at which point we resort to plain naked_short_sleep. + if (os::javaTimeNanos() - start_time < NANOSECS_PER_MILLISEC) { + os::naked_short_nanosleep(10 * (NANOUNITS / MICROUNITS)); + } else { + os::naked_short_sleep(1); } - os::naked_short_nanosleep(sleep_ns); } int SafepointSynchronize::synchronize_threads(jlong safepoint_limit_time, int nof_threads, int* initial_running) @@ -229,9 +227,16 @@ *initial_running = still_running; - int iterations = 1; // The first iteration is above. + // If there is no thread still running, we are already done. + if (still_running <= 0) { + assert(tss_head == NULL, "Must be empty"); + return 1; + } - while (still_running > 0) { + int iterations = 1; // The first iteration is above. + int64_t start_time = os::javaTimeNanos(); + + do { // Check if this has taken too long: if (SafepointTimeout && safepoint_limit_time < os::javaTimeNanos()) { print_safepoint_timeout(); @@ -264,11 +269,11 @@ DEBUG_ONLY(assert_list_is_valid(tss_head, still_running);) if (still_running > 0) { - back_off(iterations); + back_off(start_time); } iterations++; - } + } while (still_running > 0); assert(tss_head == NULL, "Must be empty");