mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 17:44:40 +02:00
8220795: Rework naked_short_nanosleep on Windows to improve time-to-safepoint
Reviewed-by: dholmes, rehn
This commit is contained in:
parent
2998236d83
commit
37281369f0
2 changed files with 27 additions and 44 deletions
|
@ -3558,41 +3558,19 @@ void os::naked_short_sleep(jlong ms) {
|
||||||
Sleep(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) {
|
void os::naked_short_nanosleep(jlong ns) {
|
||||||
assert(ns > -1 && ns < NANOUNITS, "Un-interruptable sleep, short time use only");
|
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.
|
int64_t start = os::javaTimeNanos();
|
||||||
ns = ns > 100 ? ns : 100;
|
do {
|
||||||
|
if (SwitchToThread() == 0) {
|
||||||
// Round ns to the nearst hundred of nanos.
|
// Nothing else is ready to run on this cpu, spin a little
|
||||||
// Negative values indicate relative time.
|
SpinPause();
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
} while (os::javaTimeNanos() - start < ns);
|
||||||
::CloseHandle(wait_timer /* handle */);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sleep forever; naked call to OS-specific sleep; use with CAUTION
|
// 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
|
#endif // ASSERT
|
||||||
|
|
||||||
static void back_off(int iteration) {
|
static void back_off(int64_t start_time) {
|
||||||
// iteration will be 1 the first time we enter this spin back-off.
|
// We start with fine-grained nanosleeping until a millisecond has
|
||||||
// naked_short_nanosleep takes tenths of micros which means that
|
// passed, at which point we resort to plain naked_short_sleep.
|
||||||
// number of nanoseconds is irrelevant if it's below that. We do
|
if (os::javaTimeNanos() - start_time < NANOSECS_PER_MILLISEC) {
|
||||||
// 20 1 ns sleeps with a total cost of ~1 ms, then we do 1 ms sleeps.
|
os::naked_short_nanosleep(10 * (NANOUNITS / MICROUNITS));
|
||||||
jlong sleep_ns = 1;
|
} else {
|
||||||
if (iteration > 20) {
|
os::naked_short_sleep(1);
|
||||||
sleep_ns = NANOUNITS / MILLIUNITS; // 1 ms
|
|
||||||
}
|
}
|
||||||
os::naked_short_nanosleep(sleep_ns);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SafepointSynchronize::synchronize_threads(jlong safepoint_limit_time, int nof_threads, int* initial_running)
|
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;
|
*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:
|
// Check if this has taken too long:
|
||||||
if (SafepointTimeout && safepoint_limit_time < os::javaTimeNanos()) {
|
if (SafepointTimeout && safepoint_limit_time < os::javaTimeNanos()) {
|
||||||
print_safepoint_timeout();
|
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);)
|
DEBUG_ONLY(assert_list_is_valid(tss_head, still_running);)
|
||||||
|
|
||||||
if (still_running > 0) {
|
if (still_running > 0) {
|
||||||
back_off(iterations);
|
back_off(start_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
iterations++;
|
iterations++;
|
||||||
}
|
} while (still_running > 0);
|
||||||
|
|
||||||
assert(tss_head == NULL, "Must be empty");
|
assert(tss_head == NULL, "Must be empty");
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue