Skip to content

Commit f438da4

Browse files
authored
Merge pull request #21882 from thallium/jfr-gc-event
Add JFR SystemGC event
2 parents 8d665f6 + bcb2c23 commit f438da4

File tree

11 files changed

+161
-3
lines changed

11 files changed

+161
-3
lines changed

runtime/oti/j9consts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,7 @@ extern "C" {
958958
#define J9JFR_EVENT_TYPE_THREAD_PARK 9
959959
#define J9JFR_EVENT_TYPE_THREAD_STATISTICS 10
960960
#define J9JFR_EVENT_TYPE_MONITOR_ENTER 11
961+
#define J9JFR_EVENT_TYPE_SYSTEM_GC 12
961962

962963
/* JFR thread states */
963964

runtime/oti/j9nonbuilder.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,13 @@ typedef struct J9JFRThreadContextSwitchRate {
498498
float switchRate;
499499
} J9JFRThreadContextSwitchRate;
500500

501+
typedef struct J9JFRSystemGC {
502+
J9JFR_EVENT_WITH_STACKTRACE_FIELDS
503+
I_64 duration;
504+
} J9JFRSystemGC;
505+
506+
#define J9JFRSYSTEMGC_STACKTRACE(jfrEvent) ((UDATA *)(((J9JFRSystemGC *)(jfrEvent)) + 1))
507+
501508
#endif /* defined(J9VM_OPT_JFR) */
502509

503510
/* @ddr_namespace: map_to_type=J9CfrError */

runtime/oti/j9vm.hdf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,4 +1421,12 @@ typedef UDATA (* lookupNativeAddressCallback)(struct J9VMThread *currentThread,
14211421
<struct>J9VMCRIURestoreEvent</struct>
14221422
<data type="struct J9VMThread*" name="vmThread" description="current thread" />
14231423
</event>
1424+
1425+
<event>
1426+
<name>J9HOOK_SYSTEM_GC_CALLED</name>
1427+
<description>Triggered after GC is done</description>
1428+
<struct>J9VMSystemGCEvent</struct>
1429+
<data type="struct J9VMThread*" name="currentThread" description="current thread" />
1430+
<data type="I_64" name="startTicks" description="current ticks when GC began" />
1431+
</event>
14241432
</interface>

runtime/sunvmi/sunvmi.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -614,9 +614,12 @@ getClassContextIterator(J9VMThread * currentThread, J9StackWalkState * walkState
614614
JNIEXPORT void JNICALL
615615
JVM_GC_Impl(void)
616616
{
617-
J9InternalVMFunctions *vmFuncs = VM.javaVM->internalVMFunctions;
618-
J9VMThread *currentThread = vmFuncs->currentVMThread(VM.javaVM);
619-
J9MemoryManagerFunctions *mmFuncs = VM.javaVM->memoryManagerFunctions;
617+
J9JavaVM *vm = VM.javaVM;
618+
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
619+
J9VMThread *currentThread = vmFuncs->currentVMThread(vm);
620+
J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;
621+
I_64 startTicks = 0;
622+
PORT_ACCESS_FROM_JAVAVM(vm);
620623

621624
Trc_SunVMI_GC_Entry(currentThread);
622625

@@ -626,9 +629,14 @@ JVM_GC_Impl(void)
626629
vmFuncs->internalAcquireVMAccess(currentThread);
627630
#endif /* J9VM_INTERP_ATOMIC_FREE_JNI */
628631

632+
if (J9_EVENT_IS_HOOKED(vm->hookInterface, J9HOOK_SYSTEM_GC_CALLED)) {
633+
startTicks = j9time_nano_time();
634+
}
635+
629636
/* Two GC requests are required to guarantee a GC actually occurs. */
630637
mmFuncs->j9gc_modron_global_collect(currentThread);
631638
mmFuncs->j9gc_modron_global_collect(currentThread);
639+
TRIGGER_J9HOOK_SYSTEM_GC_CALLED(vm->hookInterface, currentThread, startTicks);
632640

633641
/* make sure we actually release VMAccess as finalization cannot be run with it */
634642
vmFuncs->internalReleaseVMAccess(currentThread);

runtime/vm/JFRChunkWriter.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,4 +1367,35 @@ VM_JFRChunkWriter::writeSystemProcessEvent(void *anElement, void *userData)
13671367
entry->commandLine = NULL;
13681368
}
13691369

1370+
void
1371+
VM_JFRChunkWriter::writeSystemGCEvent(void *anElement, void *userData)
1372+
{
1373+
SystemGCEntry *entry = (SystemGCEntry *)anElement;
1374+
VM_BufferWriter *bufferWriter = (VM_BufferWriter *)userData;
1375+
1376+
/* Reserve size field */
1377+
U_8 *dataStart = reserveEventSize(bufferWriter);
1378+
1379+
/* Write event type */
1380+
bufferWriter->writeLEB128(SystemGCID);
1381+
1382+
/* Write start time */
1383+
bufferWriter->writeLEB128(entry->ticks);
1384+
1385+
/* Write duration time which is always in ticks, in our case nanos */
1386+
bufferWriter->writeLEB128(entry->duration);
1387+
1388+
/* Write event thread index */
1389+
bufferWriter->writeLEB128(entry->eventThreadIndex);
1390+
1391+
/* Wtacktrace index */
1392+
bufferWriter->writeLEB128(entry->stackTraceIndex);
1393+
1394+
/* Write invokedConcurrent which is always false for OpenJ9 */
1395+
bufferWriter->writeBoolean(false);
1396+
1397+
/* Write size */
1398+
writeEventSize(bufferWriter, dataStart);
1399+
}
1400+
13701401
#endif /* defined(J9VM_OPT_JFR) */

runtime/vm/JFRChunkWriter.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ enum MetadataTypeID {
7272
ThreadParkID = 5,
7373
MonitorEnterID = 6,
7474
MonitorWaitID = 7,
75+
SystemGCID = 36,
7576
JVMInformationID = 87,
7677
OSInformationID = 88,
7778
VirtualizationInformationID = 89,
@@ -190,6 +191,7 @@ class VM_JFRChunkWriter {
190191
static constexpr int THREAD_DUMP_EVENT_SIZE_PER_THREAD = 1000;
191192
static constexpr int SYSTEM_PROCESS_EVENT_SIZE = (4 * sizeof(U_64)) + 32 /* pid string */;
192193
static constexpr int NATIVE_LIBRARY_ADDRESS_SIZE = (4 * sizeof(U_64)) + (2 * sizeof(UDATA)) + sizeof(U_8);
194+
static constexpr int SYSTEM_GC_EVENT_SIZE = (2 * LEB128_64_SIZE) + (3 * LEB128_32_SIZE) + sizeof(U_8);
193195

194196
static constexpr int METADATA_ID = 1;
195197

@@ -402,6 +404,8 @@ class VM_JFRChunkWriter {
402404

403405
pool_do(_constantPoolTypes.getThreadStatisticsTable(), &writeThreadStatisticsEvent, _bufferWriter);
404406

407+
pool_do(_constantPoolTypes.getSystemGCTable(), &writeSystemGCEvent, _bufferWriter);
408+
405409
/* Only write constant events in first chunk */
406410
if (0 == _vm->jfrState.jfrChunkCount) {
407411
writeJVMInformationEvent();
@@ -842,6 +846,8 @@ class VM_JFRChunkWriter {
842846

843847
static void writeNativeLibraryEvent(void *anElement, void *userData);
844848

849+
static void writeSystemGCEvent(void *anElement, void *userData);
850+
845851
UDATA
846852
calculateRequiredBufferSize()
847853
{
@@ -920,6 +926,8 @@ class VM_JFRChunkWriter {
920926
requiredBufferSize += (_constantPoolTypes.getNativeLibraryCount() * NATIVE_LIBRARY_ADDRESS_SIZE)
921927
+ _constantPoolTypes.getNativeLibraryPathSizeTotal();
922928

929+
requiredBufferSize += (_constantPoolTypes.getsystemGCCount() * SYSTEM_GC_EVENT_SIZE);
930+
923931
return requiredBufferSize;
924932
}
925933

runtime/vm/JFRConstantPoolTypes.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,32 @@ VM_JFRConstantPoolTypes::addThreadStatisticsEntry(J9JFRThreadStatistics *threadS
12721272
return;
12731273
}
12741274

1275+
void
1276+
VM_JFRConstantPoolTypes::addSystemGCEntry(J9JFRSystemGC *systemGCData)
1277+
{
1278+
SystemGCEntry *entry = (SystemGCEntry *)pool_newElement(_systemGCTable);
1279+
1280+
if (NULL == entry) {
1281+
_buildResult = OutOfMemory;
1282+
goto done;
1283+
}
1284+
1285+
entry->ticks = systemGCData->startTicks;
1286+
entry->duration = systemGCData->duration;
1287+
1288+
entry->eventThreadIndex = addThreadEntry(systemGCData->vmThread);
1289+
if (isResultNotOKay()) goto done;
1290+
1291+
entry->stackTraceIndex = consumeStackTrace(systemGCData->vmThread, J9JFRSYSTEMGC_STACKTRACE(systemGCData), systemGCData->stackTraceSize);
1292+
if (isResultNotOKay()) goto done;
1293+
1294+
_systemGCCount += 1;
1295+
1296+
done:
1297+
return;
1298+
1299+
}
1300+
12751301
void
12761302
VM_JFRConstantPoolTypes::printTables()
12771303
{

runtime/vm/JFRConstantPoolTypes.hpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,13 @@ struct ThreadStatisticsEntry {
275275
U_64 peakThreadCount;
276276
};
277277

278+
struct SystemGCEntry {
279+
I_64 ticks;
280+
I_64 duration;
281+
U_32 eventThreadIndex;
282+
U_32 stackTraceIndex;
283+
};
284+
278285
struct JVMInformationEntry {
279286
const char *jvmName;
280287
const char *jvmVersion;
@@ -402,6 +409,8 @@ class VM_JFRConstantPoolTypes {
402409
J9Pool *_nativeLibrariesTable;
403410
UDATA _nativeLibrariesCount;
404411
UDATA _nativeLibraryPathSizeTotal;
412+
J9Pool *_systemGCTable;
413+
UDATA _systemGCCount;
405414

406415
/* Processing buffers */
407416
StackFrame *_currentStackFrameBuffer;
@@ -679,6 +688,8 @@ class VM_JFRConstantPoolTypes {
679688

680689
void addThreadStatisticsEntry(J9JFRThreadStatistics *threadStatisticsData);
681690

691+
void addSystemGCEntry(J9JFRSystemGC *systemGCData);
692+
682693
J9Pool *getExecutionSampleTable()
683694
{
684695
return _executionSampleTable;
@@ -754,6 +765,16 @@ class VM_JFRConstantPoolTypes {
754765
return _executionSampleCount;
755766
}
756767

768+
J9Pool *getSystemGCTable()
769+
{
770+
return _systemGCTable;
771+
}
772+
773+
UDATA getsystemGCCount()
774+
{
775+
return _systemGCCount;
776+
}
777+
757778
UDATA getThreadStartCount()
758779
{
759780
return _threadStartCount;
@@ -995,6 +1016,9 @@ class VM_JFRConstantPoolTypes {
9951016
case J9JFR_EVENT_TYPE_THREAD_STATISTICS:
9961017
addThreadStatisticsEntry((J9JFRThreadStatistics *)event);
9971018
break;
1019+
case J9JFR_EVENT_TYPE_SYSTEM_GC:
1020+
addSystemGCEntry((J9JFRSystemGC *)event);
1021+
break;
9981022
default:
9991023
Assert_VM_unreachable();
10001024
break;
@@ -1471,6 +1495,8 @@ class VM_JFRConstantPoolTypes {
14711495
, _nativeLibrariesTable(NULL)
14721496
, _nativeLibrariesCount(0)
14731497
, _nativeLibraryPathSizeTotal(0)
1498+
, _systemGCTable(NULL)
1499+
, _systemGCCount(0)
14741500
, _previousStackTraceEntry(NULL)
14751501
, _firstStackTraceEntry(NULL)
14761502
, _previousThreadEntry(NULL)
@@ -1629,6 +1655,12 @@ class VM_JFRConstantPoolTypes {
16291655
goto done;
16301656
}
16311657

1658+
_systemGCTable = pool_new(sizeof(SystemGCEntry), 0, sizeof(U_64), 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM, POOL_FOR_PORT(privatePortLibrary));
1659+
if (NULL == _systemGCTable) {
1660+
_buildResult = OutOfMemory;
1661+
goto done;
1662+
}
1663+
16321664
/* Add reserved index for default entries. For strings zero is the empty or NUll string.
16331665
* For package zero is the deafult package, for Module zero is the unnamed module. ThreadGroup
16341666
* zero is NULL threadGroup.
@@ -1724,6 +1756,7 @@ class VM_JFRConstantPoolTypes {
17241756
pool_kill(_threadStatisticsTable);
17251757
pool_kill(_systemProcessTable);
17261758
pool_kill(_nativeLibrariesTable);
1759+
pool_kill(_systemGCTable);
17271760
j9mem_free_memory(_globalStringTable);
17281761
}
17291762

runtime/vm/jfr.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ jfrEventSize(J9JFREvent *jfrEvent)
114114
case J9JFR_EVENT_TYPE_THREAD_STATISTICS:
115115
size = sizeof(J9JFRThreadStatistics);
116116
break;
117+
case J9JFR_EVENT_TYPE_SYSTEM_GC:
118+
size = sizeof(J9JFRSystemGC) + (((J9JFRSystemGC *)jfrEvent)->stackTraceSize * sizeof(UDATA));
119+
break;
117120
default:
118121
Assert_VM_unreachable();
119122
break;
@@ -714,6 +717,27 @@ jfrVMThreadParked(J9HookInterface **hook, UDATA eventNum, void *eventData, void*
714717
}
715718
}
716719

720+
/**
721+
* Hook for system GC. Called without VM access.
722+
*
723+
* @param hook[in] the VM hook interface
724+
* @param eventNum[in] the event number
725+
* @param eventData[in] the event data
726+
* @param userData[in] the registered user data
727+
*/
728+
static void
729+
jfrSystemGC(J9HookInterface **hook, UDATA eventNum, void *eventData, void* userData)
730+
{
731+
J9VMSystemGCEvent *event = (J9VMSystemGCEvent *)eventData;
732+
J9VMThread *currentThread = event->currentThread;
733+
PORT_ACCESS_FROM_VMC(currentThread);
734+
735+
J9JFRSystemGC *jfrEvent = (J9JFRSystemGC *)reserveBufferWithStackTrace(currentThread, currentThread, J9JFR_EVENT_TYPE_SYSTEM_GC, sizeof(*jfrEvent));
736+
if (NULL != jfrEvent) {
737+
jfrEvent->startTicks = event->startTicks;
738+
jfrEvent->duration = j9time_nano_time() - event->startTicks;
739+
}
740+
}
717741

718742
jint
719743
initializeJFR(J9JavaVM *vm, BOOLEAN lateInit)
@@ -773,6 +797,9 @@ initializeJFR(J9JavaVM *vm, BOOLEAN lateInit)
773797
if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_UNPARKED, jfrVMThreadParked, OMR_GET_CALLSITE(), NULL)) {
774798
goto fail;
775799
}
800+
if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_SYSTEM_GC_CALLED, jfrSystemGC, OMR_GET_CALLSITE(), NULL)) {
801+
goto fail;
802+
}
776803

777804
/* Allocate constantEvents. */
778805
vm->jfrState.constantEvents = j9mem_allocate_memory(sizeof(JFRConstantEvents), J9MEM_CATEGORY_VM);
@@ -906,6 +933,7 @@ tearDownJFR(J9JavaVM *vm)
906933
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_MONITOR_WAITED, jfrVMMonitorWaited, NULL);
907934
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_MONITOR_CONTENDED_ENTERED, jfrVMMonitorEntered, NULL);
908935
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_UNPARKED, jfrVMThreadParked, NULL);
936+
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_SYSTEM_GC_CALLED, jfrSystemGC, NULL);
909937

910938
/* Free global data */
911939
VM_JFRConstantPoolTypes::freeJFRConstantEvents(vm);

test/functional/cmdLineTests/jfr/jfrevents.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,11 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex
104104
<output type="required" caseSensitive="yes" regex="no">topAddress</output>
105105
<output type="failure" caseSensitive="yes" regex="no">jfr print: could not read recording</output>
106106
</test>
107+
<test id="test jfr SystemGC - approx 30 seconds">
108+
<command>$JFR_EXE$ print --xml --events "SystemGC" defaultJ9recording.jfr</command>
109+
<output type="required" caseSensitive="yes" regex="no">http://www.w3.org/2001/XMLSchema-instance</output>
110+
<output type="success" caseSensitive="yes" regex="no">jdk.SystemGC</output>
111+
<output type="required" caseSensitive="yes" regex="no">invokedConcurrent</output>
112+
<output type="failure" caseSensitive="yes" regex="no">jfr print: could not read recording</output>
113+
</test>
107114
</suite>

0 commit comments

Comments
 (0)