diff --git a/runtime/oti/j9consts.h b/runtime/oti/j9consts.h index 972ebe274a9..9c416f3f2f6 100644 --- a/runtime/oti/j9consts.h +++ b/runtime/oti/j9consts.h @@ -934,6 +934,8 @@ extern "C" { #define J9JFR_EVENT_TYPE_THREAD_END 2 #define J9JFR_EVENT_TYPE_THREAD_SLEEP 3 #define J9JFR_EVENT_TYPE_OBJECT_WAIT 4 +#define J9JFR_EVENT_TYPE_CPU_LOAD 5 +#define J9JFR_EVENT_TYPE_THREAD_CPU_LOAD 6 /* JFR thread states */ diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index aabe4b36594..c0b461cf56c 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -346,6 +346,11 @@ struct J9VMContinuation; #if defined(J9VM_OPT_JFR) +typedef struct J9ThreadJFRState { + omrthread_thread_time_t prevThreadCPUTimes; + int64_t prevTimestamp; +} J9ThreadJFRState; + typedef struct J9JFRBufferWalkState { U_8 *current; U_8 *end; @@ -416,6 +421,19 @@ typedef struct J9JFRMonitorWaited { #define J9JFRMonitorWaitedED_STACKTRACE(jfrEvent) ((UDATA*)(((J9JFRMonitorWaited*)(jfrEvent)) + 1)) +typedef struct J9JFRCPULoad { + J9JFR_EVENT_COMMON_FIELDS + float jvmUser; + float jvmSystem; + float machineTotal; +} J9JFRCPULoad; + +typedef struct J9JFRThreadCPULoad { + J9JFR_EVENT_COMMON_FIELDS + float user; + float system; +} J9JFRThreadCPULoad; + #endif /* defined(J9VM_OPT_JFR) */ /* @ddr_namespace: map_to_type=J9CfrError */ @@ -5600,6 +5618,9 @@ typedef struct J9VMThread { j9object_t closeScopeObj; #endif /* JAVA_SPEC_VERSION >= 22 */ UDATA unsafeIndexableHeaderSize; +#if defined(J9VM_OPT_JFR) + J9ThreadJFRState threadJfrState; +#endif /* defined(J9VM_OPT_JFR) */ } J9VMThread; #define J9VMTHREAD_ALIGNMENT 0x100 @@ -5678,6 +5699,9 @@ typedef struct JFRState { BOOLEAN isConstantEventsInitialized; BOOLEAN isStarted; omrthread_monitor_t isConstantEventsInitializedMutex; + J9SysinfoCPUTime prevSysCPUTime; + omrthread_process_time_t prevProcCPUTimes; + int64_t prevProcTimestamp; } JFRState; typedef struct J9ReflectFunctionTable { @@ -6218,6 +6242,7 @@ typedef struct J9JavaVM { omrthread_t jfrSamplerThread; UDATA jfrSamplerState; IDATA jfrAsyncKey; + IDATA jfrThreadCPULoadAsyncKey; #endif /* defined(J9VM_OPT_JFR) */ #if JAVA_SPEC_VERSION >= 22 omrthread_monitor_t closeScopeMutex; diff --git a/runtime/vm/BufferWriter.hpp b/runtime/vm/BufferWriter.hpp index 76c79c6ec89..ed6d0c58f52 100644 --- a/runtime/vm/BufferWriter.hpp +++ b/runtime/vm/BufferWriter.hpp @@ -336,6 +336,13 @@ class VM_BufferWriter { } } + void + writeFloat(float val) + { + U_32 newVal = *(U_32 *)&val; + writeU32(newVal); + } + static U_32 convertFromLEB128ToU32(U_8 *start) { diff --git a/runtime/vm/JFRChunkWriter.hpp b/runtime/vm/JFRChunkWriter.hpp index d968a07ec54..b85a395009d 100644 --- a/runtime/vm/JFRChunkWriter.hpp +++ b/runtime/vm/JFRChunkWriter.hpp @@ -71,6 +71,8 @@ enum MetadataTypeID { VirtualizationInformationID = 88, InitialSystemPropertyID = 89, CPUInformationID = 92, + CPULoadID = 94, + ThreadCPULoadID = 95, PhysicalMemoryID = 107, ExecutionSampleID = 108, ThreadID = 163, @@ -158,6 +160,8 @@ class VM_JFRChunkWriter { static constexpr int CPU_INFORMATION_EVENT_SIZE = 600; static constexpr int OS_INFORMATION_EVENT_SIZE = 100; static constexpr int INITIAL_SYSTEM_PROPERTY_EVENT_SIZE = 6000; + static constexpr int CPU_LOAD_EVENT_SIZE = (3 * sizeof(float)) + (3 * sizeof(I_64)); + static constexpr int THREAD_CPU_LOAD_EVENT_SIZE = (2 * sizeof(float)) + (4 * sizeof(I_64)); static constexpr int METADATA_ID = 1; @@ -328,6 +332,10 @@ class VM_JFRChunkWriter { pool_do(_constantPoolTypes.getMonitorWaitTable(), &writeMonitorWaitEvent, _bufferWriter); + pool_do(_constantPoolTypes.getCPULoadTable(), &writeCPULoadEvent, _bufferWriter); + + pool_do(_constantPoolTypes.getThreadCPULoadTable(), &writeThreadCPULoadEvent, _bufferWriter); + /* Only write constant events in first chunk */ if (0 == _vm->jfrState.jfrChunkCount) { writeJVMInformationEvent(); @@ -531,6 +539,62 @@ class VM_JFRChunkWriter { _bufferWriter->writeLEB128PaddedU32(dataStart, _bufferWriter->getCursor() - dataStart); } + static void + writeCPULoadEvent(void *anElement, void *userData) + { + CPULoadEntry *entry = (CPULoadEntry *)anElement; + VM_BufferWriter *_bufferWriter = (VM_BufferWriter *)userData; + + /* reserve size field */ + U_8 *dataStart = _bufferWriter->getAndIncCursor(sizeof(U_32)); + + /* write event type */ + _bufferWriter->writeLEB128(CPULoadID); + + /* write start time */ + _bufferWriter->writeLEB128(entry->ticks); + + /* write user CPU load */ + _bufferWriter->writeFloat(entry->jvmUser); + + /* write system CPU load */ + _bufferWriter->writeFloat(entry->jvmSystem); + + /* write machine total CPU load */ + _bufferWriter->writeFloat(entry->machineTotal); + + /* write size */ + _bufferWriter->writeLEB128PaddedU32(dataStart, _bufferWriter->getCursor() - dataStart); + } + + static void + writeThreadCPULoadEvent(void *anElement, void *userData) + { + ThreadCPULoadEntry *entry = (ThreadCPULoadEntry *)anElement; + VM_BufferWriter *_bufferWriter = (VM_BufferWriter *)userData; + + /* reserve size field */ + U_8 *dataStart = _bufferWriter->getAndIncCursor(sizeof(U_32)); + + /* write event type */ + _bufferWriter->writeLEB128(ThreadCPULoadID); + + /* write start time */ + _bufferWriter->writeLEB128(entry->ticks); + + /* write thread index */ + _bufferWriter->writeLEB128(entry->threadIndex); + + /* write user thread CPU load */ + _bufferWriter->writeFloat(entry->user); + + /* write system thread CPU load */ + _bufferWriter->writeFloat(entry->system); + + /* write size */ + _bufferWriter->writeLEB128PaddedU32(dataStart, _bufferWriter->getCursor() - dataStart); + } + void writeJFRChunkToFile() { @@ -648,6 +712,11 @@ class VM_JFRChunkWriter { requiredBufferSize += CPU_INFORMATION_EVENT_SIZE; requiredBufferSize += INITIAL_SYSTEM_PROPERTY_EVENT_SIZE; + + requiredBufferSize += _constantPoolTypes.getCPULoadCount() * CPU_LOAD_EVENT_SIZE; + + requiredBufferSize += _constantPoolTypes.getThreadCPULoadCount() * THREAD_CPU_LOAD_EVENT_SIZE; + return requiredBufferSize; } @@ -655,5 +724,7 @@ class VM_JFRChunkWriter { { } }; + #endif /* defined(J9VM_OPT_JFR) */ -#endif /* JFRCHUNKWRITER_HPP_ */ + +#endif /* !defined(JFRCHUNKWRITER_HPP_) */ diff --git a/runtime/vm/JFRConstantPoolTypes.cpp b/runtime/vm/JFRConstantPoolTypes.cpp index a0a3ec28c34..5d8bf49559a 100644 --- a/runtime/vm/JFRConstantPoolTypes.cpp +++ b/runtime/vm/JFRConstantPoolTypes.cpp @@ -970,7 +970,8 @@ VM_JFRConstantPoolTypes::addThreadStartEntry(J9JFRThreadStart *threadStartData) entry->stackTraceIndex = consumeStackTrace(threadStartData->parentThread, J9JFRTHREADSTART_STACKTRACE(threadStartData), threadStartData->stackTraceSize); if (isResultNotOKay()) goto done; - index = _threadStartCount++; + index = _threadStartCount; + _threadStartCount += 1; done: return index; @@ -995,7 +996,8 @@ VM_JFRConstantPoolTypes::addThreadEndEntry(J9JFREvent *threadEndData) entry->eventThreadIndex = addThreadEntry(threadEndData->vmThread); if (isResultNotOKay()) goto done; - index = _threadEndCount++; + index = _threadEndCount; + _threadEndCount += 1; done: return index; @@ -1025,7 +1027,8 @@ VM_JFRConstantPoolTypes::addThreadSleepEntry(J9JFRThreadSlept *threadSleepData) entry->stackTraceIndex = consumeStackTrace(threadSleepData->vmThread, J9JFRTHREADSLEPT_STACKTRACE(threadSleepData), threadSleepData->stackTraceSize); if (isResultNotOKay()) goto done; - index = _threadEndCount++; + index = _threadEndCount; + _threadEndCount += 1; done: return index; @@ -1062,12 +1065,62 @@ VM_JFRConstantPoolTypes::addMonitorWaitEntry(J9JFRMonitorWaited* threadWaitData) entry->notifierThread = 0; //Need a way to find the notifiying thread - index = _threadEndCount++; + index = _threadEndCount; + _threadEndCount += 1; done: return index; } +U_32 +VM_JFRConstantPoolTypes::addCPULoadEntry(J9JFRCPULoad *cpuLoadData) +{ + CPULoadEntry *entry = (CPULoadEntry *)pool_newElement(_cpuLoadTable); + U_32 index = U_32_MAX; + + if (NULL == entry) { + _buildResult = OutOfMemory; + goto done; + } + + entry->ticks = cpuLoadData->startTicks; + entry->jvmUser = cpuLoadData->jvmUser; + entry->jvmSystem = cpuLoadData->jvmSystem; + entry->machineTotal = cpuLoadData->machineTotal; + + index = _cpuLoadCount; + _cpuLoadCount += 1; + +done: + return index; +} + +U_32 +VM_JFRConstantPoolTypes::addThreadCPULoadEntry(J9JFRThreadCPULoad *threadCPULoadData) +{ + ThreadCPULoadEntry *entry = (ThreadCPULoadEntry *)pool_newElement(_threadCPULoadTable); + U_32 index = U_32_MAX; + + if (NULL == entry) { + _buildResult = OutOfMemory; + goto done; + } + + entry->ticks = threadCPULoadData->startTicks; + entry->user = threadCPULoadData->user; + entry->system = threadCPULoadData->system; + + entry->threadIndex = addThreadEntry(threadCPULoadData->vmThread); + if (isResultNotOKay()) { + goto done; + } + + index = _threadCPULoadCount; + _threadCPULoadCount += 1; + +done: + return index; +} void VM_JFRConstantPoolTypes::printTables() diff --git a/runtime/vm/JFRConstantPoolTypes.hpp b/runtime/vm/JFRConstantPoolTypes.hpp index 8a043eb0211..6693e20aed7 100644 --- a/runtime/vm/JFRConstantPoolTypes.hpp +++ b/runtime/vm/JFRConstantPoolTypes.hpp @@ -212,6 +212,20 @@ struct StackTraceEntry { StackTraceEntry *next; }; +struct CPULoadEntry { + I_64 ticks; + float jvmUser; + float jvmSystem; + float machineTotal; +}; + +struct ThreadCPULoadEntry { + I_64 ticks; + U_32 threadIndex; + float user; + float system; +}; + struct JVMInformationEntry { const char *jvmName; const char *jvmVersion; @@ -289,6 +303,10 @@ class VM_JFRConstantPoolTypes { UDATA _threadSleepCount; J9Pool *_monitorWaitTable; UDATA _monitorWaitCount; + J9Pool *_cpuLoadTable; + UDATA _cpuLoadCount; + J9Pool *_threadCPULoadTable; + UDATA _threadCPULoadCount; /* Processing buffers */ StackFrame *_currentStackFrameBuffer; @@ -535,6 +553,10 @@ class VM_JFRConstantPoolTypes { U_32 addMonitorWaitEntry(J9JFRMonitorWaited* threadWaitData); + U_32 addCPULoadEntry(J9JFRCPULoad *cpuLoadData); + + U_32 addThreadCPULoadEntry(J9JFRThreadCPULoad *threadCPULoadData); + J9Pool *getExecutionSampleTable() { return _executionSampleTable; @@ -560,6 +582,16 @@ class VM_JFRConstantPoolTypes { return _monitorWaitTable; } + J9Pool *getCPULoadTable() + { + return _cpuLoadTable; + } + + J9Pool *getThreadCPULoadTable() + { + return _threadCPULoadTable; + } + UDATA getExecutionSampleCount() { return _executionSampleCount; @@ -585,6 +617,16 @@ class VM_JFRConstantPoolTypes { return _monitorWaitCount; } + UDATA getCPULoadCount() + { + return _cpuLoadCount; + } + + UDATA getThreadCPULoadCount() + { + return _threadCPULoadCount; + } + ClassloaderEntry *getClassloaderEntry() { return _firstClassloaderEntry; @@ -727,9 +769,15 @@ class VM_JFRConstantPoolTypes { case J9JFR_EVENT_TYPE_OBJECT_WAIT: addMonitorWaitEntry((J9JFRMonitorWaited*) event); break; + case J9JFR_EVENT_TYPE_CPU_LOAD: + addCPULoadEntry((J9JFRCPULoad *)event); + break; + case J9JFR_EVENT_TYPE_THREAD_CPU_LOAD: + addThreadCPULoadEntry((J9JFRThreadCPULoad *)event); + break; default: Assert_VM_unreachable(); - break; + break; } event = jfrBufferNextDo(&walkstate); } @@ -1029,6 +1077,10 @@ class VM_JFRConstantPoolTypes { , _threadSleepCount(0) , _monitorWaitTable(NULL) , _monitorWaitCount(0) + , _cpuLoadTable(NULL) + , _cpuLoadCount(0) + , _threadCPULoadTable(NULL) + , _threadCPULoadCount(0) , _previousStackTraceEntry(NULL) , _firstStackTraceEntry(NULL) , _previousThreadEntry(NULL) @@ -1131,6 +1183,18 @@ class VM_JFRConstantPoolTypes { goto done; } + _cpuLoadTable = pool_new(sizeof(CPULoadEntry), 0, sizeof(U_64), 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM, POOL_FOR_PORT(privatePortLibrary)); + if (NULL == _cpuLoadTable) { + _buildResult = OutOfMemory; + goto done; + } + + _threadCPULoadTable = pool_new(sizeof(ThreadCPULoadEntry), 0, sizeof(U_64), 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM, POOL_FOR_PORT(privatePortLibrary)); + if (NULL == _threadCPULoadTable) { + _buildResult = OutOfMemory; + goto done; + } + /* Add reserved index for default entries. For strings zero is the empty or NUll string. * For package zero is the deafult package, for Module zero is the unnamed module. ThreadGroup * zero is NULL threadGroup. @@ -1216,6 +1280,8 @@ class VM_JFRConstantPoolTypes { pool_kill(_threadEndTable); pool_kill(_threadSleepTable); pool_kill(_monitorWaitTable); + pool_kill(_cpuLoadTable); + pool_kill(_threadCPULoadTable); j9mem_free_memory(_globalStringTable); } diff --git a/runtime/vm/jfr.cpp b/runtime/vm/jfr.cpp index 53603a926ee..6e7f42370ae 100644 --- a/runtime/vm/jfr.cpp +++ b/runtime/vm/jfr.cpp @@ -22,6 +22,7 @@ #include "JFRConstantPoolTypes.hpp" #include "j9protos.h" #include "omrlinkedlist.h" +#include "thread_api.h" #include "ut_j9vm.h" #include "vm_internal.h" @@ -56,6 +57,7 @@ static void jfrStartSamplingThread(J9JavaVM *vm); static void initializeEventFields(J9VMThread *currentThread, J9JFREvent *jfrEvent, UDATA eventType); static int J9THREAD_PROC jfrSamplingThreadProc(void *entryArg); static void jfrExecutionSampleCallback(J9VMThread *currentThread, IDATA handlerKey, void *userData); +static void jfrThreadCPULoadCallback(J9VMThread *currentThread, IDATA handlerKey, void *userData); /** * Calculate the size in bytes of a JFR event. @@ -84,6 +86,12 @@ jfrEventSize(J9JFREvent *jfrEvent) case J9JFR_EVENT_TYPE_OBJECT_WAIT: size = sizeof(J9JFRMonitorWaited) + (((J9JFRMonitorWaited*)jfrEvent)->stackTraceSize * sizeof(UDATA)); break; + case J9JFR_EVENT_TYPE_CPU_LOAD: + size = sizeof(J9JFRCPULoad); + break; + case J9JFR_EVENT_TYPE_THREAD_CPU_LOAD: + size = sizeof(J9JFRThreadCPULoad); + break; default: Assert_VM_unreachable(); break; @@ -601,6 +609,11 @@ initializeJFR(J9JavaVM *vm, BOOLEAN lateInit) goto fail; } + vm->jfrThreadCPULoadAsyncKey = J9RegisterAsyncEvent(vm, jfrThreadCPULoadCallback, NULL); + if (vm->jfrThreadCPULoadAsyncKey < 0) { + goto fail; + } + if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_THREAD_CREATED, jfrThreadCreated, OMR_GET_CALLSITE(), NULL)) { goto fail; } @@ -656,6 +669,8 @@ initializeJFR(J9JavaVM *vm, BOOLEAN lateInit) goto fail; } + vm->jfrState.prevSysCPUTime.timestamp = -1; + vm->jfrState.prevProcTimestamp = -1; if (omrthread_monitor_init_with_name(&vm->jfrBufferMutex, 0, "JFR global buffer mutex")) { goto fail; } @@ -759,6 +774,10 @@ tearDownJFR(J9JavaVM *vm) J9UnregisterAsyncEvent(vm, vm->jfrAsyncKey); vm->jfrAsyncKey = -1; } + if (vm->jfrThreadCPULoadAsyncKey >= 0) { + J9UnregisterAsyncEvent(vm, vm->jfrThreadCPULoadAsyncKey); + vm->jfrThreadCPULoadAsyncKey = -1; + } } /** @@ -804,6 +823,86 @@ jfrExecutionSampleCallback(J9VMThread *currentThread, IDATA handlerKey, void *us jfrExecutionSample(currentThread, currentThread); } +void +jfrCPULoad(J9VMThread *currentThread) +{ + PORT_ACCESS_FROM_VMC(currentThread); + OMRPORT_ACCESS_FROM_J9PORT(PORTLIB); + + omrthread_process_time_t currentProcCPUTimes = {0}; + intptr_t processTimeRC = omrthread_get_process_times(¤tProcCPUTimes); + + J9SysinfoCPUTime currentSysCPUTime = {0}; + intptr_t sysTimeRC = omrsysinfo_get_CPU_utilization(¤tSysCPUTime); + + if ((0 == processTimeRC) && (0 == sysTimeRC)) { + J9JFRCPULoad *jfrEvent = (J9JFRCPULoad *)reserveBuffer(currentThread, sizeof(J9JFRCPULoad)); + if (NULL != jfrEvent) { + initializeEventFields(currentThread, (J9JFREvent *)jfrEvent, J9JFR_EVENT_TYPE_CPU_LOAD); + + JFRState *jfrState = ¤tThread->javaVM->jfrState; + uintptr_t numberOfCpus = j9sysinfo_get_number_CPUs_by_type(J9PORT_CPU_ONLINE); + int64_t currentTime = j9time_nano_time(); + + if (-1 == jfrState->prevProcTimestamp) { + jfrEvent->jvmUser = 0; + jfrEvent->jvmSystem = 0; + } else { + int64_t timeDelta = currentTime - jfrState->prevProcTimestamp; + jfrEvent->jvmUser = OMR_MIN((currentProcCPUTimes._userTime - jfrState->prevProcCPUTimes._userTime) / ((double)numberOfCpus * timeDelta), 1.0); + jfrEvent->jvmSystem = OMR_MIN((currentProcCPUTimes._systemTime - jfrState->prevProcCPUTimes._systemTime) / ((double)numberOfCpus * timeDelta), 1.0); + } + jfrState->prevProcCPUTimes = currentProcCPUTimes; + jfrState->prevProcTimestamp = currentTime; + + if (-1 == jfrState->prevSysCPUTime.timestamp) { + jfrEvent->machineTotal = 0; + } else { + jfrEvent->machineTotal = OMR_MIN((currentSysCPUTime.cpuTime - jfrState->prevSysCPUTime.cpuTime) / ((double)numberOfCpus * (currentSysCPUTime.timestamp - jfrState->prevSysCPUTime.timestamp)), 1.0); + } + jfrState->prevSysCPUTime = currentSysCPUTime; + } + } +} + +void +jfrThreadCPULoad(J9VMThread *currentThread, J9VMThread *sampleThread) +{ + PORT_ACCESS_FROM_VMC(currentThread); + + omrthread_thread_time_t threadTimes; + memset(&threadTimes, 0, sizeof(threadTimes)); + + intptr_t rc = omrthread_get_thread_times(&threadTimes); + + if (-1 != rc) { + J9JFRThreadCPULoad *jfrEvent = (J9JFRThreadCPULoad *)reserveBuffer(currentThread, sizeof(*jfrEvent)); + if (NULL != jfrEvent) { + initializeEventFields(currentThread, (J9JFREvent *)jfrEvent, J9JFR_EVENT_TYPE_THREAD_CPU_LOAD); + + J9ThreadJFRState *jfrState = &sampleThread->threadJfrState; + int64_t currentTime = j9time_nano_time(); + + if (-1 == jfrState->prevTimestamp) { + jfrEvent->user = 0; + jfrEvent->system = 0; + } else { + int64_t timeDelta = currentTime - jfrState->prevTimestamp; + jfrEvent->user = OMR_MIN((threadTimes.userTime - jfrState->prevThreadCPUTimes.userTime) / (double)timeDelta, 1.0); + jfrEvent->system = OMR_MIN((threadTimes.sysTime - jfrState->prevThreadCPUTimes.sysTime) / (double)timeDelta, 1.0); + } + jfrState->prevTimestamp = currentTime; + jfrState->prevThreadCPUTimes = threadTimes; + } + } +} + +static void +jfrThreadCPULoadCallback(J9VMThread *currentThread, IDATA handlerKey, void *userData) +{ + jfrThreadCPULoad(currentThread, currentThread); +} + static int J9THREAD_PROC jfrSamplingThreadProc(void *entryArg) { @@ -814,8 +913,16 @@ jfrSamplingThreadProc(void *entryArg) omrthread_monitor_enter(vm->jfrSamplerMutex); vm->jfrSamplerState = J9JFR_SAMPLER_STATE_RUNNING; omrthread_monitor_notify_all(vm->jfrSamplerMutex); + UDATA count = 0; while (J9JFR_SAMPLER_STATE_STOP != vm->jfrSamplerState) { J9SignalAsyncEvent(vm, NULL, vm->jfrAsyncKey); + if (0 == (count % 100)) { // 1 second + jfrCPULoad(currentThread); + if (0 == (count % 1000)) { // 10 seconds + J9SignalAsyncEvent(vm, NULL, vm->jfrThreadCPULoadAsyncKey); + } + } + count += 1; omrthread_monitor_wait_timed(vm->jfrSamplerMutex, J9JFR_SAMPLING_RATE, 0); } omrthread_monitor_exit(vm->jfrSamplerMutex); diff --git a/runtime/vm/vmthread.cpp b/runtime/vm/vmthread.cpp index 92c87004964..c18d4980374 100644 --- a/runtime/vm/vmthread.cpp +++ b/runtime/vm/vmthread.cpp @@ -298,6 +298,10 @@ allocateVMThread(J9JavaVM *vm, omrthread_t osThread, UDATA privateFlags, void *m newThread->scopedValueCache = NULL; #endif /* JAVA_SPEC_VERSION >= 19 */ +#if defined(J9VM_OPT_JFR) + newThread->threadJfrState.prevTimestamp = -1; +#endif /* defined(J9VM_OPT_JFR) */ + /* If an exclusive access request is in progress, mark this thread */ omrthread_monitor_enter(vm->exclusiveAccessMutex);