diff --git a/jcl/src/java.base/share/classes/java/lang/Thread.java b/jcl/src/java.base/share/classes/java/lang/Thread.java index d54a3c0eb0c..47b374c297c 100644 --- a/jcl/src/java.base/share/classes/java/lang/Thread.java +++ b/jcl/src/java.base/share/classes/java/lang/Thread.java @@ -790,9 +790,9 @@ public final boolean isDaemon() { * @see Thread#interrupted */ public boolean isInterrupted() { - synchronized(lock) { + //synchronized(lock) { return isInterruptedImpl(); - } + //} } private native boolean isInterruptedImpl(); @@ -1496,7 +1496,7 @@ public static enum State { * @see State */ public State getState() { - synchronized(lock) { + //synchronized(lock) { if (threadRef == NO_REF) { if (isDead()) { return State.TERMINATED; @@ -1504,7 +1504,7 @@ public State getState() { return State.NEW; } return State.values()[getStateImpl(threadRef)]; - } + //} } private native int getStateImpl(long threadRef); diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index dafc7c6fcd6..797850fccef 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -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 @@ -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; diff --git a/runtime/vm/FastJNI_java_lang_Thread.cpp b/runtime/vm/FastJNI_java_lang_Thread.cpp index 0c19e908cb4..be7e439959d 100644 --- a/runtime/vm/FastJNI_java_lang_Thread.cpp +++ b/runtime/vm/FastJNI_java_lang_Thread.cpp @@ -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) { @@ -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; } diff --git a/runtime/vm/j9vm.tdf b/runtime/vm/j9vm.tdf index 319699919e0..ff0d103fa03 100644 --- a/runtime/vm/j9vm.tdf +++ b/runtime/vm/j9vm.tdf @@ -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" diff --git a/runtime/vm/threadhelp.cpp b/runtime/vm/threadhelp.cpp index 3adc40da463..e522529f0ae 100644 --- a/runtime/vm/threadhelp.cpp +++ b/runtime/vm/threadhelp.cpp @@ -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); @@ -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. diff --git a/runtime/vm/threadpark.cpp b/runtime/vm/threadpark.cpp index 14c5dcce63b..b8f9ff34b51 100644 --- a/runtime/vm/threadpark.cpp +++ b/runtime/vm/threadpark.cpp @@ -28,6 +28,7 @@ #include "omrthread.h" #include "ut_j9vm.h" +#include "AtomicSupport.hpp" #include "VMHelpers.hpp" #include @@ -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 */ @@ -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); @@ -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);*/ } } diff --git a/runtime/vm/vmthinit.c b/runtime/vm/vmthinit.c index e7ea6fe7db3..ab4df1a51f5 100644 --- a/runtime/vm/vmthinit.c +++ b/runtime/vm/vmthinit.c @@ -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); diff --git a/runtime/vm/vmthread.cpp b/runtime/vm/vmthread.cpp index c18d4980374..56d31a9628f 100644 --- a/runtime/vm/vmthread.cpp +++ b/runtime/vm/vmthread.cpp @@ -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 */ @@ -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) @@ -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; @@ -1209,6 +1271,8 @@ threadParseArguments(J9JavaVM *vm, char *optArg) goto _error; } **(UDATA**)omrthread_global((char*)"yieldUsleepMultiplier") = yieldUsleepMultiplier; + + vm->yieldUsleepMultiplier = yieldUsleepMultiplier; continue; }