8220795: Rework naked_short_nanosleep on Windows to improve time-to-safepoint

Reviewed-by: dholmes, rehn
This commit is contained in:
Robin Westberg 2019-04-24 14:03:20 +02:00
parent 2998236d83
commit 37281369f0
2 changed files with 27 additions and 44 deletions
src/hotspot
os/windows
share/runtime

@ -3558,41 +3558,19 @@ void os::naked_short_sleep(jlong ms) {
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

@ -186,16 +186,14 @@ static void assert_list_is_valid(const ThreadSafepointState* tss_head, int still
}
#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 @@ int SafepointSynchronize::synchronize_threads(jlong safepoint_limit_time, int no
*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 @@ int SafepointSynchronize::synchronize_threads(jlong safepoint_limit_time, int no
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");