Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support or optional spin on park #20443

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions jcl/src/java.base/share/classes/java/lang/Thread.java
Original file line number Diff line number Diff line change
Expand Up @@ -790,9 +790,9 @@ public final boolean isDaemon() {
* @see Thread#interrupted
*/
public boolean isInterrupted() {
synchronized(lock) {
//synchronized(lock) {
return isInterruptedImpl();
}
//}
}

private native boolean isInterruptedImpl();
Expand Down Expand Up @@ -1496,15 +1496,15 @@ public static enum State {
* @see State
*/
public State getState() {
synchronized(lock) {
//synchronized(lock) {
if (threadRef == NO_REF) {
if (isDead()) {
return State.TERMINATED;
}
return State.NEW;
}
return State.values()[getStateImpl(threadRef)];
}
//}
}

private native int getStateImpl(long threadRef);
Expand Down
14 changes: 14 additions & 0 deletions runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -5645,6 +5645,11 @@ typedef struct J9VMThread {
#if defined(J9VM_OPT_JFR)
J9ThreadJFRState threadJfrState;
#endif /* defined(J9VM_OPT_JFR) */
U_64 parkWaitTime;
U_64 parkCount;
U_64 parkWaitSlidingWindowIndex;
U_64 *parkWaitSlidingWindow;
volatile UDATA prePark;
} J9VMThread;

#define J9VMTHREAD_ALIGNMENT 0x100
Expand Down Expand Up @@ -5927,6 +5932,15 @@ typedef struct J9JavaVM {
UDATA thrNestedSpinning;
UDATA thrTryEnterNestedSpinning;
UDATA thrDeflationPolicy;
UDATA thrParkSpinCount1;
UDATA thrParkSpinCount2;
U_64 parkSpinWaitThreshold;
U_64 parkWaitSlidingWindowSize;
double parkSpinRatioOfAvgWait;
UDATA parkYield;
UDATA parkLock;
U_64 parkSleepMultiplier;
U_64 yieldUsleepMultiplier;
UDATA gcOptions;
UDATA ( *unhookVMEvent)(struct J9JavaVM *javaVM, UDATA eventNumber, void * currentHandler, void * oldHandler) ;
UDATA classLoadingMaxStack;
Expand Down
16 changes: 8 additions & 8 deletions runtime/vm/FastJNI_java_lang_Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ Fast_java_lang_Thread_interruptedImpl(J9VMThread *currentThread)
jboolean rc = JNI_FALSE;
#if defined(WIN32)
/* Synchronize on the thread lock around interrupted() on windows */
j9object_t threadLock = J9VMJAVALANGTHREAD_LOCK(currentThread, currentThread->threadObject);
threadLock = (j9object_t)objectMonitorEnter(currentThread, threadLock);
if (J9_OBJECT_MONITOR_ENTER_FAILED(threadLock)) {
setNativeOutOfMemoryError(currentThread, J9NLS_VM_FAILED_TO_ALLOCATE_MONITOR);
goto done;
}
// j9object_t threadLock = J9VMJAVALANGTHREAD_LOCK(currentThread, currentThread->threadObject);
// threadLock = (j9object_t)objectMonitorEnter(currentThread, threadLock);
// if (J9_OBJECT_MONITOR_ENTER_FAILED(threadLock)) {
// setNativeOutOfMemoryError(currentThread, J9NLS_VM_FAILED_TO_ALLOCATE_MONITOR);
// goto done;
// }
/* This field is only initialized on windows */
J9JavaVM * const vm = currentThread->javaVM;
if (NULL != vm->sidecarClearInterruptFunction) {
Expand All @@ -81,8 +81,8 @@ Fast_java_lang_Thread_interruptedImpl(J9VMThread *currentThread)
rc = JNI_TRUE;
}
#if defined(WIN32)
objectMonitorExit(currentThread, threadLock);
done:
// objectMonitorExit(currentThread, threadLock);
// done:
#endif /* WIN32 */
return rc;
}
Expand Down
4 changes: 4 additions & 0 deletions runtime/vm/j9vm.tdf
Original file line number Diff line number Diff line change
Expand Up @@ -1012,3 +1012,7 @@ TraceEntry=Trc_VM_snapshot_subAllocateSnapshotMemory_Entry NoEnv Overhead=1 Leve
TraceExit=Trc_VM_snapshot_subAllocateSnapshotMemory_Exit NoEnv Overhead=1 Level=1 Template="subAllocateMemory() Memory allocated = %p."
TraceEvent=Trc_VM_snapshot_loadWarmClassFromSnapshot_ClassLoadHookFailed Overhead=1 Level=1 Template="loadWarmClassFromSnapshot() Warm class load hook failed class=%p, %s"
TraceEvent=Trc_VM_snapshot_loadWarmClassFromSnapshot_ClassInfo Overhead=1 Level=1 Template="loadWarmClassFromSnapshot() LoadClass clazz=%p, %s"

TraceEvent=Trc_VM_ThreadHelp_timeCompensationHelper_parkWait Env Overhead=1 Level=5 Template="Park early break average=%zu spinTime=%zu osYield=%zu cpuYield=%zu data=%zu parkWait=%zu vmthread=%p"
TraceEvent=Trc_VM_ThreadHelp_timeCompensationHelper_parkWaitSpinElapsed Env Overhead=1 Level=5 Template="Park spin elapsed average=%zu spinTime=%zu parkWait=%zu osYield=%zu cpuYield=%zu vmthread=%p"
TraceEvent=Trc_VM_ThreadHelp_timeCompensationHelper_parkWaitNoSpin Env Overhead=1 Level=5 Template="After park no spin average=%zu average=%zu parkWait=%zu vmthread=%p"
76 changes: 73 additions & 3 deletions runtime/vm/threadhelp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,9 @@ IDATA
timeCompensationHelper(J9VMThread *vmThread, U_8 threadHelperType, omrthread_monitor_t monitor, I_64 millis, I_32 nanos)
{
IDATA rc = 0;
J9JavaVM *vm = vmThread->javaVM;

#if defined(J9VM_OPT_CRIU_SUPPORT)
J9JavaVM *vm = vmThread->javaVM;
/* Time compensation only supports CRIURestoreNonPortableMode which is default mode. */
bool waitTimed = (millis > 0) || (nanos > 0);
bool compensationMightBeRequired = waitTimed && !J9_IS_CRIU_RESTORED(vm);
Expand All @@ -452,8 +452,78 @@ timeCompensationHelper(J9VMThread *vmThread, U_8 threadHelperType, omrthread_mon
rc = omrthread_monitor_wait_timed(monitor, millis, nanos);
break;
case HELPER_TYPE_THREAD_PARK:
rc = omrthread_park(millis, nanos);
break;
{
PORT_ACCESS_FROM_VMC(vmThread);
U_64 parkStart = j9time_nano_time();
U_64 slidingWindowSize = vm->parkWaitSlidingWindowSize;
U_64 avgWait = 0;
U_64 cpuYields = 0;
U_64 osYields = 0;
bool noSpin = true;
bool shouldYield = vm->parkYield > 0;
UDATA data = 0;
if (0 != slidingWindowSize) {
if (vmThread->parkWaitSlidingWindowIndex > slidingWindowSize) {
U_64 totalWait = 0;
vmThread->prePark = 1;

for (U_64 i = 0; i < slidingWindowSize; i++) {
totalWait += vmThread->parkWaitSlidingWindow[i];

}
avgWait = totalWait/slidingWindowSize;
bool spinElapsed = true;
//Trc_VM_ThreadHelp_timeCompensationHelper_parkWait(vmThread, avgWait, vmThread->parkCount, vmThread);

if (avgWait < vm->parkSpinWaitThreshold) {
noSpin = false;
for (IDATA spinCount2 = vm->thrParkSpinCount2; spinCount2 > 0; --spinCount2) {
U_64 spinTime = j9time_nano_time() - parkStart;

if ((vmThread->prePark == 0) || (spinTime > vm->parkSpinWaitThreshold)) {
data++;
Trc_VM_ThreadHelp_timeCompensationHelper_parkWait(vmThread, avgWait, spinTime, osYields, cpuYields, data, vmThread->prePark, vmThread);
spinElapsed = false;
break;
}

for (IDATA spinCount1 = vm->thrParkSpinCount1; spinCount1 > 0; --spinCount1) {
VM_AtomicSupport::yieldCPU();
cpuYields++;
if (vmThread->prePark == 0) {
data++;
spinElapsed = false;
break;
}
}
if (shouldYield) {
if (vmThread->prePark != 0) {
usleep(((osYields * vm->parkSleepMultiplier) + 1) * vm->yieldUsleepMultiplier);
//omrthread_yield_new(vm->thrParkSpinCount2 - spinCount2);
osYields++;
}
}
}

if (spinElapsed) {
Trc_VM_ThreadHelp_timeCompensationHelper_parkWaitSpinElapsed(vmThread, avgWait, j9time_nano_time() - parkStart, vmThread->prePark, osYields, cpuYields, vmThread);
}
}
}
rc = omrthread_park(millis, nanos);
U_64 parkEnd = j9time_nano_time();
vmThread->parkWaitSlidingWindow[vmThread->parkWaitSlidingWindowIndex % slidingWindowSize] = parkEnd - parkStart;
vmThread->parkWaitSlidingWindowIndex += 1;
vmThread->prePark = 0;
if (noSpin) {
Trc_VM_ThreadHelp_timeCompensationHelper_parkWaitNoSpin(vmThread, avgWait, parkEnd - parkStart, vmThread->prePark, vmThread);
}

} else {
rc = omrthread_park(millis, nanos);
}
break;
}
case HELPER_TYPE_THREAD_SLEEP:
/* Returns 0 when the timeout specified passed.
* A timeout of 0 (0ms, 0ns) indicates an immediate return.
Expand Down
14 changes: 11 additions & 3 deletions runtime/vm/threadpark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "omrthread.h"
#include "ut_j9vm.h"

#include "AtomicSupport.hpp"
#include "VMHelpers.hpp"

#include <string.h>
Expand Down Expand Up @@ -127,6 +128,7 @@ void
threadUnparkImpl(J9VMThread *vmThread, j9object_t threadObject)
{
j9object_t threadLock = J9VMJAVALANGTHREAD_LOCK(vmThread, threadObject);
J9JavaVM *vm = vmThread->javaVM;

if (NULL == threadLock) {
/* thread not fully set up yet so we cannot really need to unpark, just return */
Expand All @@ -136,8 +138,10 @@ threadUnparkImpl(J9VMThread *vmThread, j9object_t threadObject)
* the enter and the gc could move the targetThreadObject we have to push/pop on a special frame so that
* we will have the updated value if the object is moved */
PUSH_OBJECT_IN_SPECIAL_FRAME(vmThread, threadObject);
threadLock = (j9object_t)objectMonitorEnter(vmThread, threadLock);
if (J9_OBJECT_MONITOR_ENTER_FAILED(threadLock)) {
if (vm->parkLock == 1) {
threadLock = (j9object_t)objectMonitorEnter(vmThread, threadLock);
}
if ((vm->parkLock == 1) && J9_OBJECT_MONITOR_ENTER_FAILED(threadLock)) {
#if defined(J9VM_OPT_CRIU_SUPPORT)
if (J9_OBJECT_MONITOR_CRIU_SINGLE_THREAD_MODE_THROW == (UDATA)threadLock) {
setCRIUSingleThreadModeJVMCRIUException(vmThread, 0, 0);
Expand All @@ -157,8 +161,12 @@ threadUnparkImpl(J9VMThread *vmThread, j9object_t threadObject)
if (NULL != otherVmThread) {
/* in this case the thread is already dead so we don't need to unpark */
omrthread_unpark(otherVmThread->osThread);
VM_AtomicSupport::writeBarrier();
otherVmThread->prePark = 0;
}
if (vm->parkLock == 1) {
objectMonitorExit(vmThread, threadLock);
}
objectMonitorExit(vmThread, threadLock);
/*Trc_JCL_unpark_Exit(vmThread);*/
}
}
Expand Down
2 changes: 2 additions & 0 deletions runtime/vm/vmthinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ void freeVMThread(J9JavaVM *vm, J9VMThread *vmThread)
/* Free J9RIParameters. */
j9mem_free_memory(vmThread->riParameters);
}
j9mem_free_memory(vmThread->parkWaitSlidingWindow);

#endif /* defined(J9VM_PORT_RUNTIME_INSTRUMENTATION) */
if (J9JAVAVM_COMPRESS_OBJECT_REFERENCES(vm)) {
j9mem_free_memory32(vmThread->startOfMemoryBlock);
Expand Down
64 changes: 64 additions & 0 deletions runtime/vm/vmthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ allocateVMThread(J9JavaVM *vm, omrthread_t osThread, UDATA privateFlags, void *m
#if defined(J9VM_OPT_JFR)
newThread->threadJfrState.prevTimestamp = -1;
#endif /* defined(J9VM_OPT_JFR) */
newThread->parkWaitSlidingWindow = (U_64*) j9mem_allocate_memory(vm->parkWaitSlidingWindowSize * sizeof(U_64), OMRMEM_CATEGORY_VM);
if (NULL == newThread->parkWaitSlidingWindow) {
goto fail;
}

/* If an exclusive access request is in progress, mark this thread */

Expand Down Expand Up @@ -571,6 +575,15 @@ threadParseArguments(J9JavaVM *vm, char *optArg)
vm->thrNestedSpinning = 1;
vm->thrTryEnterNestedSpinning = 1;
vm->thrDeflationPolicy = J9VM_DEFLATION_POLICY_ASAP;
vm->thrParkSpinCount1 = 0;
vm->thrParkSpinCount2 = 0;
vm->parkSpinWaitThreshold = 0;
vm->parkWaitSlidingWindowSize = 0;
vm->parkSpinRatioOfAvgWait = 0.95;
vm->parkLock = 0;
vm->parkYield = 0;
vm->parkSleepMultiplier = 0;
vm->yieldUsleepMultiplier = 0;

if (cpus > 1) {
#if (defined(LINUXPPC)) && !defined(J9VM_ENV_LITTLE_ENDIAN)
Expand Down Expand Up @@ -828,6 +841,55 @@ threadParseArguments(J9JavaVM *vm, char *optArg)
continue;
}

if (try_scan(&scan_start, "parkSpinCount1=")) {
if (scan_udata(&scan_start, &vm->thrParkSpinCount1)) {
goto _error;
}
continue;
}
if (try_scan(&scan_start, "parkSpinCount2=")) {
if (scan_udata(&scan_start, &vm->thrParkSpinCount2)) {
goto _error;
}
continue;
}
if (try_scan(&scan_start, "parkSpinWaitThreshold=")) {
if (scan_udata(&scan_start, &vm->parkSpinWaitThreshold)) {
goto _error;
}
continue;
}
if (try_scan(&scan_start, "parkWaitSlidingWindowSize=")) {
if (scan_udata(&scan_start, &vm->parkWaitSlidingWindowSize)) {
goto _error;
}
continue;
}
if (try_scan(&scan_start, "parkSpinRatioOfAvgWait=")) {
if (scan_double(&scan_start, &vm->parkSpinRatioOfAvgWait)) {
goto _error;
}
continue;
}
if (try_scan(&scan_start, "parkYield=")) {
if (scan_udata(&scan_start, &vm->parkYield)) {
goto _error;
}
continue;
}
if (try_scan(&scan_start, "parkLock=")) {
if (scan_udata(&scan_start, &vm->parkLock)) {
goto _error;
}
continue;
}
if (try_scan(&scan_start, "parkSleepMultiplier=")) {
if (scan_udata(&scan_start, &vm->parkSleepMultiplier)) {
goto _error;
}
continue;
}

#if !defined(WIN32) && defined(OMR_NOTIFY_POLICY_CONTROL)
if (try_scan(&scan_start, "notifyPolicy=")) {
char *oldScanStart = scan_start;
Expand Down Expand Up @@ -1209,6 +1271,8 @@ threadParseArguments(J9JavaVM *vm, char *optArg)
goto _error;
}
**(UDATA**)omrthread_global((char*)"yieldUsleepMultiplier") = yieldUsleepMultiplier;

vm->yieldUsleepMultiplier = yieldUsleepMultiplier;
continue;
}

Expand Down