Skip to content

Commit 38a18d4

Browse files
committed
Add JFR monitor enter event
This change adds support for the JFR monitor enter event. Signed-off-by: Adrian Popescu <adpopescu@ibm.com>
1 parent eb5b49d commit 38a18d4

8 files changed

+171
-3
lines changed

runtime/oti/j9consts.h

+1
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,7 @@ extern "C" {
955955
#define J9JFR_EVENT_TYPE_THREAD_CONTEXT_SWITCH_RATE 8
956956
#define J9JFR_EVENT_TYPE_THREAD_PARK 9
957957
#define J9JFR_EVENT_TYPE_THREAD_STATISTICS 10
958+
#define J9JFR_EVENT_TYPE_MONITOR_ENTER 11
958959

959960
/* JFR thread states */
960961

runtime/oti/j9nonbuilder.h

+11
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,17 @@ typedef struct J9JFRThreadParked {
441441

442442
#define J9JFRTHREADPARKED_STACKTRACE(jfrEvent) ((UDATA*)(((J9JFRThreadParked*)(jfrEvent)) + 1))
443443

444+
typedef struct J9JFRMonitorEntered {
445+
J9JFR_EVENT_WITH_STACKTRACE_FIELDS
446+
I_64 duration;
447+
struct J9VMThread *thread;
448+
struct J9Class *monitorClass;
449+
struct J9VMThread *previousOwner;
450+
UDATA monitorAddress;
451+
} J9JFRMonitorEntered;
452+
453+
#define J9JFRMONITORENTERED_STACKTRACE(jfrEvent) ((UDATA *)(((J9JFRMonitorEntered *)(jfrEvent)) + 1))
454+
444455
typedef struct J9JFRCPULoad {
445456
J9JFR_EVENT_COMMON_FIELDS
446457
float jvmUser;

runtime/oti/j9vm.hdf

+3
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ typedef UDATA (* lookupNativeAddressCallback)(struct J9VMThread *currentThread,
229229
<struct>J9VMMonitorContendedEnteredEvent</struct>
230230
<data type="struct J9VMThread*" name="currentThread" description="current thread" />
231231
<data type="omrthread_monitor_t" name="monitor" description="the contended monitor" />
232+
<data type="I_64" name="startTicks" description="current ticks when wait began" />
233+
<data type="struct J9Class*" name="monitorClass" description="object monitor class" />
234+
<data type="struct J9VMThread*" name="previousOwner" description="previous owner thread" />
232235
</event>
233236

234237
<event>

runtime/vm/JFRChunkWriter.hpp

+47
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ enum MetadataTypeID {
6666
ThreadEndID = 3,
6767
ThreadSleepID = 4,
6868
ThreadParkID = 5,
69+
MonitorEnterID = 6,
6970
MonitorWaitID = 7,
7071
JVMInformationID = 87,
7172
OSInformationID = 88,
@@ -140,6 +141,8 @@ class VM_JFRChunkWriter {
140141
static constexpr int JFR_CHUNK_HEADER_SIZE = 68;
141142

142143
/* conservative sizing for JFR chunk */
144+
static constexpr int LEB128_32_SIZE = 5;
145+
static constexpr int LEB128_64_SIZE = 9;
143146
static constexpr int STRING_HEADER_LENGTH = sizeof(U_64);
144147
static constexpr int CHECKPOINT_EVENT_HEADER_AND_FOOTER = 68;
145148
static constexpr int STRING_CONSTANT_SIZE = 128;
@@ -159,6 +162,7 @@ class VM_JFRChunkWriter {
159162
static constexpr int THREAD_END_EVENT_SIZE = (4 * sizeof(U_64)) + sizeof(U_32);
160163
static constexpr int THREAD_SLEEP_EVENT_SIZE = (7 * sizeof(U_64)) + sizeof(U_32);
161164
static constexpr int MONITOR_WAIT_EVENT_SIZE = (9 * sizeof(U_64)) + sizeof(U_32);
165+
static constexpr int MONITOR_ENTER_EVENT_SIZE = sizeof(U_32) + (3 * LEB128_64_SIZE) + (5 * LEB128_32_SIZE);
162166
static constexpr int THREAD_PARK_EVENT_SIZE = (9 * sizeof(U_64)) + sizeof(U_32);
163167
static constexpr int JVM_INFORMATION_EVENT_SIZE = 3000;
164168
static constexpr int PHYSICAL_MEMORY_EVENT_SIZE = (4 * sizeof(U_64)) + sizeof(U_32);
@@ -366,6 +370,8 @@ class VM_JFRChunkWriter {
366370

367371
pool_do(_constantPoolTypes.getMonitorWaitTable(), &writeMonitorWaitEvent, _bufferWriter);
368372

373+
pool_do(_constantPoolTypes.getMonitorEnterTable(), &writeMonitorEnterEvent, _bufferWriter);
374+
369375
pool_do(_constantPoolTypes.getThreadParkTable(), &writeThreadParkEvent, _bufferWriter);
370376

371377
pool_do(_constantPoolTypes.getCPULoadTable(), &writeCPULoadEvent, _bufferWriter);
@@ -583,6 +589,45 @@ class VM_JFRChunkWriter {
583589
writeEventSize(_bufferWriter, dataStart);
584590
}
585591

592+
static void
593+
writeMonitorEnterEvent(void *anElement, void *userData)
594+
{
595+
MonitorEnterEntry *entry = (MonitorEnterEntry *)anElement;
596+
VM_BufferWriter *_bufferWriter = (VM_BufferWriter *)userData;
597+
598+
/* reserve size field */
599+
U_8 *dataStart = _bufferWriter->getAndIncCursor(sizeof(U_32));
600+
601+
/* write event type */
602+
_bufferWriter->writeLEB128(MonitorEnterID);
603+
604+
/* write start time - this is when the sleep started not when it ended so we
605+
* need to subtract the duration since the event is emitted when the sleep ends.
606+
*/
607+
_bufferWriter->writeLEB128(entry->ticks - entry->duration);
608+
609+
/* write duration time which is always in ticks, in our case nanos */
610+
_bufferWriter->writeLEB128(entry->duration);
611+
612+
/* write event thread index */
613+
_bufferWriter->writeLEB128(entry->eventThreadIndex);
614+
615+
/* stacktrace index */
616+
_bufferWriter->writeLEB128(entry->stackTraceIndex);
617+
618+
/* monitor class index */
619+
_bufferWriter->writeLEB128(entry->monitorClass);
620+
621+
/* notifier thread index */
622+
_bufferWriter->writeLEB128(entry->previousOwnerThread);
623+
624+
/* address of monitor */
625+
_bufferWriter->writeLEB128(entry->monitorAddress);
626+
627+
/* write size */
628+
writeEventSize(_bufferWriter, dataStart);
629+
}
630+
586631
static void
587632
writeThreadParkEvent(void *anElement, void *userData)
588633
{
@@ -797,6 +842,8 @@ class VM_JFRChunkWriter {
797842

798843
requiredBufferSize += (_constantPoolTypes.getMonitorWaitCount() * MONITOR_WAIT_EVENT_SIZE);
799844

845+
requiredBufferSize += (_constantPoolTypes.getMonitorEnterCount() * MONITOR_ENTER_EVENT_SIZE);
846+
800847
requiredBufferSize += (_constantPoolTypes.getThreadParkCount() * THREAD_PARK_EVENT_SIZE);
801848

802849
requiredBufferSize += JVM_INFORMATION_EVENT_SIZE;

runtime/vm/JFRConstantPoolTypes.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,37 @@ VM_JFRConstantPoolTypes::addMonitorWaitEntry(J9JFRMonitorWaited* threadWaitData)
10861086
return;
10871087
}
10881088

1089+
void
1090+
VM_JFRConstantPoolTypes::addMonitorEnterEntry(J9JFRMonitorEntered *monitorEnterData)
1091+
{
1092+
MonitorEnterEntry *entry = (MonitorEnterEntry *)pool_newElement(_monitorEnterTable);
1093+
1094+
if (NULL == entry) {
1095+
_buildResult = OutOfMemory;
1096+
goto done;
1097+
}
1098+
entry->ticks = monitorEnterData->startTicks;
1099+
entry->duration = monitorEnterData->duration;
1100+
entry->monitorAddress = monitorEnterData->monitorAddress;
1101+
1102+
entry->threadIndex = addThreadEntry(monitorEnterData->vmThread);
1103+
if (isResultNotOKay()) goto done;
1104+
1105+
entry->eventThreadIndex = addThreadEntry(monitorEnterData->vmThread);
1106+
if (isResultNotOKay()) goto done;
1107+
1108+
entry->stackTraceIndex = consumeStackTrace(monitorEnterData->vmThread, J9JFRMONITORENTERED_STACKTRACE(monitorEnterData), monitorEnterData->stackTraceSize);
1109+
if (isResultNotOKay()) goto done;
1110+
1111+
entry->monitorClass = getClassEntry(monitorEnterData->monitorClass);
1112+
if (isResultNotOKay()) goto done;
1113+
1114+
_monitorEnterCount += 1;
1115+
1116+
done:
1117+
return;
1118+
}
1119+
10891120
void
10901121
VM_JFRConstantPoolTypes::addThreadParkEntry(J9JFRThreadParked* threadParkData)
10911122
{

runtime/vm/JFRConstantPoolTypes.hpp

+37
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,17 @@ struct MonitorWaitEntry {
204204
BOOLEAN timedOut;
205205
};
206206

207+
struct MonitorEnterEntry {
208+
I_64 ticks;
209+
I_64 duration;
210+
I_64 monitorAddress;
211+
U_32 monitorClass;
212+
U_32 previousOwnerThread;
213+
U_32 threadIndex;
214+
U_32 eventThreadIndex;
215+
U_32 stackTraceIndex;
216+
};
217+
207218
struct ThreadParkEntry {
208219
I_64 ticks;
209220
I_64 duration;
@@ -336,6 +347,8 @@ class VM_JFRConstantPoolTypes {
336347
UDATA _threadSleepCount;
337348
J9Pool *_monitorWaitTable;
338349
UDATA _monitorWaitCount;
350+
J9Pool *_monitorEnterTable;
351+
UDATA _monitorEnterCount;
339352
J9Pool *_threadParkTable;
340353
UDATA _threadParkCount;
341354
J9Pool *_cpuLoadTable;
@@ -611,6 +624,8 @@ class VM_JFRConstantPoolTypes {
611624

612625
void addMonitorWaitEntry(J9JFRMonitorWaited* threadWaitData);
613626

627+
void addMonitorEnterEntry(J9JFRMonitorEntered *monitorEnterData);
628+
614629
void addThreadParkEntry(J9JFRThreadParked* threadParkData);
615630

616631
void addCPULoadEntry(J9JFRCPULoad *cpuLoadData);
@@ -648,6 +663,11 @@ class VM_JFRConstantPoolTypes {
648663
return _monitorWaitTable;
649664
}
650665

666+
J9Pool *getMonitorEnterTable()
667+
{
668+
return _monitorEnterTable;
669+
}
670+
651671
J9Pool *getThreadParkTable()
652672
{
653673
return _threadParkTable;
@@ -703,6 +723,11 @@ class VM_JFRConstantPoolTypes {
703723
return _monitorWaitCount;
704724
}
705725

726+
UDATA getMonitorEnterCount()
727+
{
728+
return _monitorEnterCount;
729+
}
730+
706731
UDATA getThreadParkCount()
707732
{
708733
return _threadParkCount;
@@ -876,6 +901,9 @@ class VM_JFRConstantPoolTypes {
876901
case J9JFR_EVENT_TYPE_OBJECT_WAIT:
877902
addMonitorWaitEntry((J9JFRMonitorWaited*) event);
878903
break;
904+
case J9JFR_EVENT_TYPE_MONITOR_ENTER:
905+
addMonitorEnterEntry((J9JFRMonitorEntered *) event);
906+
break;
879907
case J9JFR_EVENT_TYPE_THREAD_PARK:
880908
addThreadParkEntry((J9JFRThreadParked*) event);
881909
break;
@@ -1216,6 +1244,8 @@ class VM_JFRConstantPoolTypes {
12161244
, _threadSleepCount(0)
12171245
, _monitorWaitTable(NULL)
12181246
, _monitorWaitCount(0)
1247+
, _monitorEnterTable(NULL)
1248+
, _monitorEnterCount(0)
12191249
, _threadParkTable(NULL)
12201250
, _threadParkCount(0)
12211251
, _cpuLoadTable(NULL)
@@ -1330,6 +1360,12 @@ class VM_JFRConstantPoolTypes {
13301360
goto done;
13311361
}
13321362

1363+
_monitorEnterTable = pool_new(sizeof(MonitorEnterEntry), 0, sizeof(U_64), 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM, POOL_FOR_PORT(privatePortLibrary));
1364+
if (NULL == _monitorEnterTable) {
1365+
_buildResult = OutOfMemory;
1366+
goto done;
1367+
}
1368+
13331369
_threadParkTable = pool_new(sizeof(ThreadParkEntry), 0, sizeof(U_64), 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM, POOL_FOR_PORT(privatePortLibrary));
13341370
if (NULL == _threadParkTable) {
13351371
_buildResult = OutOfMemory;
@@ -1452,6 +1488,7 @@ class VM_JFRConstantPoolTypes {
14521488
pool_kill(_threadEndTable);
14531489
pool_kill(_threadSleepTable);
14541490
pool_kill(_monitorWaitTable);
1491+
pool_kill(_monitorEnterTable);
14551492
pool_kill(_threadParkTable);
14561493
pool_kill(_cpuLoadTable);
14571494
pool_kill(_threadCPULoadTable);

runtime/vm/ObjectMonitor.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ objectMonitorEnterBlocking(J9VMThread *currentThread)
140140
UDATA result = 0;
141141
j9object_t object = J9VMTHREAD_BLOCKINGENTEROBJECT(currentThread, currentThread);
142142
J9Class *ramClass = J9OBJECT_CLAZZ(currentThread, object);
143+
J9JavaVM *vm = currentThread->javaVM;
144+
PORT_ACCESS_FROM_JAVAVM(vm);
145+
I_64 startTicks = j9time_nano_time();
143146
/* Throughout this function, note that inlineGetLockAddress cannot run into out of memory case because
144147
* an entry in monitor table will have been created by the earlier call in objectMonitorEnterNonBlocking.
145148
*/
@@ -159,7 +162,6 @@ objectMonitorEnterBlocking(J9VMThread *currentThread)
159162
}
160163
#endif /* J9VM_THR_LOCK_RESERVATION */
161164
{
162-
J9JavaVM *vm = currentThread->javaVM;
163165
J9ObjectMonitor *objectMonitor = monitorTableAt(currentThread, object);
164166
/* Table entry was created by the nonblocking case, so this peek cannot fail */
165167
Assert_VM_notNull(objectMonitor);
@@ -289,8 +291,9 @@ objectMonitorEnterBlocking(J9VMThread *currentThread)
289291
((J9ThreadMonitor*)monitor)->flags &= ~(UDATA)J9THREAD_MONITOR_SUPPRESS_CONTENDED_EXIT;
290292
VM_AtomicSupport::subtract(&monitor->pinCount, 1);
291293
if (J9_EVENT_IS_HOOKED(vm->hookInterface, J9HOOK_VM_MONITOR_CONTENDED_ENTERED)) {
294+
J9VMThread *ownerThread = getVMThreadFromOMRThread(vm, ((J9ThreadMonitor *)monitor)->owner);
292295
bool frameBuilt = saveBlockingEnterObject(currentThread);
293-
ALWAYS_TRIGGER_J9HOOK_VM_MONITOR_CONTENDED_ENTERED(vm->hookInterface, currentThread, monitor);
296+
ALWAYS_TRIGGER_J9HOOK_VM_MONITOR_CONTENDED_ENTERED(vm->hookInterface, currentThread, monitor, startTicks, ramClass, ownerThread);
294297
restoreBlockingEnterObject(currentThread, frameBuilt);
295298
}
296299
}

runtime/vm/jfr.cpp

+36-1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ jfrEventSize(J9JFREvent *jfrEvent)
9393
case J9JFR_EVENT_TYPE_OBJECT_WAIT:
9494
size = sizeof(J9JFRMonitorWaited) + (((J9JFRMonitorWaited*)jfrEvent)->stackTraceSize * sizeof(UDATA));
9595
break;
96+
case J9JFR_EVENT_TYPE_MONITOR_ENTER:
97+
size = sizeof(J9JFRMonitorEntered) + (((J9JFRMonitorEntered *)jfrEvent)->stackTraceSize * sizeof(UDATA));
98+
break;
9699
case J9JFR_EVENT_TYPE_THREAD_PARK:
97100
size = sizeof(J9JFRThreadParked) + (((J9JFRThreadParked*)jfrEvent)->stackTraceSize * sizeof(UDATA));
98101
break;
@@ -650,6 +653,35 @@ jfrVMMonitorWaited(J9HookInterface **hook, UDATA eventNum, void *eventData, void
650653
}
651654
}
652655

656+
/**
657+
* Hook for VM monitor entered. Called without VM access.
658+
*
659+
* @param hook[in] the VM hook interface
660+
* @param eventNum[in] the event number
661+
* @param eventData[in] the event data
662+
* @param userData[in] the registered user data
663+
*/
664+
static void
665+
jfrVMMonitorEntered(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)
666+
{
667+
J9VMMonitorContendedEnteredEvent *event = (J9VMMonitorContendedEnteredEvent *)eventData;
668+
J9VMThread *currentThread = event->currentThread;
669+
PORT_ACCESS_FROM_VMC(currentThread);
670+
671+
#if defined(DEBUG)
672+
j9tty_printf(PORTLIB, "\n!!! VM monitor entered %p\n", currentThread);
673+
#endif /* defined(DEBUG) */
674+
675+
J9JFRMonitorEntered *jfrEvent = (J9JFRMonitorEntered *)reserveBufferWithStackTrace(currentThread, currentThread, J9JFR_EVENT_TYPE_MONITOR_ENTER, sizeof(*jfrEvent));
676+
if (NULL != jfrEvent) {
677+
initializeEventFields(currentThread, (J9JFREvent *)jfrEvent, J9JFR_EVENT_TYPE_MONITOR_ENTER);
678+
679+
jfrEvent->duration = j9time_nano_time() - event->startTicks;
680+
jfrEvent->monitorClass = event->monitorClass;
681+
jfrEvent->monitorAddress = (UDATA)event->monitor;
682+
}
683+
}
684+
653685
/**
654686
* Hook for VM thread parked. Called without VM access.
655687
*
@@ -732,7 +764,9 @@ initializeJFR(J9JavaVM *vm, BOOLEAN lateInit)
732764
if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_MONITOR_WAITED, jfrVMMonitorWaited, OMR_GET_CALLSITE(), NULL)) {
733765
goto fail;
734766
}
735-
767+
if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_MONITOR_CONTENDED_ENTERED, jfrVMMonitorEntered, OMR_GET_CALLSITE(), NULL)) {
768+
goto fail;
769+
}
736770
if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_UNPARKED, jfrVMThreadParked, OMR_GET_CALLSITE(), NULL)) {
737771
goto fail;
738772
}
@@ -867,6 +901,7 @@ tearDownJFR(J9JavaVM *vm)
867901
/* Unregister it anyway even it wasn't registered for initializeJFR(vm, TRUE). */
868902
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_INITIALIZED, jfrVMInitialized, NULL);
869903
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_MONITOR_WAITED, jfrVMMonitorWaited, NULL);
904+
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_MONITOR_CONTENDED_ENTERED, jfrVMMonitorEntered, NULL);
870905
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_UNPARKED, jfrVMThreadParked, NULL);
871906

872907
/* Free global data */

0 commit comments

Comments
 (0)