Skip to content

Commit a4e63a7

Browse files
authored
Merge pull request #20765 from thallium/jfr-class-loading-stats-0.49
(0.49) Add JFR ClassLoadingStatistics support
2 parents e0b3d55 + a2c5277 commit a4e63a7

File tree

9 files changed

+141
-0
lines changed

9 files changed

+141
-0
lines changed

runtime/oti/j9consts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,7 @@ extern "C" {
942942
#define J9JFR_EVENT_TYPE_OBJECT_WAIT 4
943943
#define J9JFR_EVENT_TYPE_CPU_LOAD 5
944944
#define J9JFR_EVENT_TYPE_THREAD_CPU_LOAD 6
945+
#define J9JFR_EVENT_TYPE_CLASS_LOADING_STATISTICS 7
945946

946947
/* JFR thread states */
947948

runtime/oti/j9nonbuilder.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,12 @@ typedef struct J9JFRThreadCPULoad {
434434
float system;
435435
} J9JFRThreadCPULoad;
436436

437+
typedef struct J9JFRClassLoadingStatistics {
438+
J9JFR_EVENT_COMMON_FIELDS
439+
I_64 loadedClassCount;
440+
I_64 unloadedClassCount;
441+
} J9JFRClassLoadingStatistics;
442+
437443
#endif /* defined(J9VM_OPT_JFR) */
438444

439445
/* @ddr_namespace: map_to_type=J9CfrError */
@@ -3601,6 +3607,9 @@ typedef struct J9ClassLoader {
36013607
omrthread_rwmutex_t cpEntriesMutex;
36023608
UDATA initClassPathEntryCount;
36033609
UDATA asyncGetCallTraceUsed;
3610+
#if defined(J9VM_OPT_JFR)
3611+
UDATA loadedClassCount;
3612+
#endif /* defined(J9VM_OPT_JFR) */
36043613
} J9ClassLoader;
36053614

36063615
#define J9CLASSLOADER_SHARED_CLASSES_ENABLED 8

runtime/vm/JFRChunkWriter.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,4 +863,29 @@ VM_JFRChunkWriter::writeInitialEnvironmentVariableEvents()
863863
}
864864
}
865865
}
866+
867+
void
868+
VM_JFRChunkWriter::writeClassLoadingStatisticsEvent(void *anElement, void *userData)
869+
{
870+
ClassLoadingStatisticsEntry *entry = (ClassLoadingStatisticsEntry *)anElement;
871+
VM_BufferWriter *_bufferWriter = (VM_BufferWriter *)userData;
872+
873+
/* reserve size field */
874+
U_8 *dataStart = _bufferWriter->getAndIncCursor(sizeof(U_32));
875+
876+
/* write event type */
877+
_bufferWriter->writeLEB128(ClassLoadingStatisticsID);
878+
879+
/* write start time */
880+
_bufferWriter->writeLEB128(entry->ticks);
881+
882+
/* write user loaded class count */
883+
_bufferWriter->writeLEB128(entry->loadedClassCount);
884+
885+
/* write system unloaded class count */
886+
_bufferWriter->writeLEB128(entry->unloadedClassCount);
887+
888+
/* write size */
889+
_bufferWriter->writeLEB128PaddedU32(dataStart, _bufferWriter->getCursor() - dataStart);
890+
}
866891
#endif /* defined(J9VM_OPT_JFR) */

runtime/vm/JFRChunkWriter.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ enum MetadataTypeID {
7474
CPUInformationID = 92,
7575
CPULoadID = 94,
7676
ThreadCPULoadID = 95,
77+
ClassLoadingStatisticsID = 99,
7778
PhysicalMemoryID = 107,
7879
ExecutionSampleID = 108,
7980
ThreadID = 163,
@@ -164,6 +165,7 @@ class VM_JFRChunkWriter {
164165
static constexpr int CPU_LOAD_EVENT_SIZE = (3 * sizeof(float)) + (3 * sizeof(I_64));
165166
static constexpr int THREAD_CPU_LOAD_EVENT_SIZE = (2 * sizeof(float)) + (4 * sizeof(I_64));
166167
static constexpr int INITIAL_ENVIRONMENT_VARIABLE_EVENT_SIZE = 6000;
168+
static constexpr int CLASS_LOADING_STATISTICS_EVENT_SIZE = 5 * sizeof(I_64);
167169

168170
static constexpr int METADATA_ID = 1;
169171

@@ -339,6 +341,8 @@ class VM_JFRChunkWriter {
339341

340342
pool_do(_constantPoolTypes.getThreadCPULoadTable(), &writeThreadCPULoadEvent, _bufferWriter);
341343

344+
pool_do(_constantPoolTypes.getClassLoadingStatisticsTable(), &writeClassLoadingStatisticsEvent, _bufferWriter);
345+
342346
/* Only write constant events in first chunk */
343347
if (0 == _vm->jfrState.jfrChunkCount) {
344348
writeJVMInformationEvent();
@@ -668,6 +672,8 @@ class VM_JFRChunkWriter {
668672

669673
void writeInitialEnvironmentVariableEvents();
670674

675+
static void writeClassLoadingStatisticsEvent(void *anElement, void *userData);
676+
671677
UDATA
672678
calculateRequiredBufferSize()
673679
{
@@ -728,6 +734,8 @@ class VM_JFRChunkWriter {
728734

729735
requiredBufferSize += _constantPoolTypes.getThreadCPULoadCount() * THREAD_CPU_LOAD_EVENT_SIZE;
730736

737+
requiredBufferSize += _constantPoolTypes.getClassLoadingStatisticsCount() * CLASS_LOADING_STATISTICS_EVENT_SIZE;
738+
731739
return requiredBufferSize;
732740
}
733741

runtime/vm/JFRConstantPoolTypes.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,28 @@ VM_JFRConstantPoolTypes::addThreadCPULoadEntry(J9JFRThreadCPULoad *threadCPULoad
11451145
return index;
11461146
}
11471147

1148+
U_32
1149+
VM_JFRConstantPoolTypes::addClassLoadingStatisticsEntry(J9JFRClassLoadingStatistics *classLoadingStatisticsData)
1150+
{
1151+
ClassLoadingStatisticsEntry *entry = (ClassLoadingStatisticsEntry *)pool_newElement(_classLoadingStatisticsTable);
1152+
U_32 index = U_32_MAX;
1153+
1154+
if (NULL == entry) {
1155+
_buildResult = OutOfMemory;
1156+
goto done;
1157+
}
1158+
1159+
entry->ticks = classLoadingStatisticsData->startTicks;
1160+
entry->loadedClassCount = classLoadingStatisticsData->loadedClassCount;
1161+
entry->unloadedClassCount = classLoadingStatisticsData->unloadedClassCount;
1162+
1163+
index = _classLoadingStatisticsCount;
1164+
_classLoadingStatisticsCount += 1;
1165+
1166+
done:
1167+
return index;
1168+
}
1169+
11481170
void
11491171
VM_JFRConstantPoolTypes::printTables()
11501172
{

runtime/vm/JFRConstantPoolTypes.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,12 @@ struct ThreadCPULoadEntry {
228228
float system;
229229
};
230230

231+
struct ClassLoadingStatisticsEntry {
232+
I_64 ticks;
233+
I_64 loadedClassCount;
234+
I_64 unloadedClassCount;
235+
};
236+
231237
struct JVMInformationEntry {
232238
const char *jvmName;
233239
const char *jvmVersion;
@@ -309,6 +315,8 @@ class VM_JFRConstantPoolTypes {
309315
UDATA _cpuLoadCount;
310316
J9Pool *_threadCPULoadTable;
311317
UDATA _threadCPULoadCount;
318+
J9Pool *_classLoadingStatisticsTable;
319+
UDATA _classLoadingStatisticsCount;
312320

313321
/* Processing buffers */
314322
StackFrame *_currentStackFrameBuffer;
@@ -576,6 +584,8 @@ class VM_JFRConstantPoolTypes {
576584

577585
U_32 addThreadCPULoadEntry(J9JFRThreadCPULoad *threadCPULoadData);
578586

587+
U_32 addClassLoadingStatisticsEntry(J9JFRClassLoadingStatistics *classLoadingStatisticsData);
588+
579589
J9Pool *getExecutionSampleTable()
580590
{
581591
return _executionSampleTable;
@@ -611,6 +621,11 @@ class VM_JFRConstantPoolTypes {
611621
return _threadCPULoadTable;
612622
}
613623

624+
J9Pool *getClassLoadingStatisticsTable()
625+
{
626+
return _classLoadingStatisticsTable;
627+
}
628+
614629
UDATA getExecutionSampleCount()
615630
{
616631
return _executionSampleCount;
@@ -646,6 +661,11 @@ class VM_JFRConstantPoolTypes {
646661
return _threadCPULoadCount;
647662
}
648663

664+
UDATA getClassLoadingStatisticsCount()
665+
{
666+
return _classLoadingStatisticsCount;
667+
}
668+
649669
ClassloaderEntry *getClassloaderEntry()
650670
{
651671
return _firstClassloaderEntry;
@@ -795,6 +815,9 @@ class VM_JFRConstantPoolTypes {
795815
case J9JFR_EVENT_TYPE_THREAD_CPU_LOAD:
796816
addThreadCPULoadEntry((J9JFRThreadCPULoad *)event);
797817
break;
818+
case J9JFR_EVENT_TYPE_CLASS_LOADING_STATISTICS:
819+
addClassLoadingStatisticsEntry((J9JFRClassLoadingStatistics *)event);
820+
break;
798821
default:
799822
Assert_VM_unreachable();
800823
break;
@@ -1118,6 +1141,8 @@ class VM_JFRConstantPoolTypes {
11181141
, _cpuLoadCount(0)
11191142
, _threadCPULoadTable(NULL)
11201143
, _threadCPULoadCount(0)
1144+
, _classLoadingStatisticsTable(NULL)
1145+
, _classLoadingStatisticsCount(0)
11211146
, _previousStackTraceEntry(NULL)
11221147
, _firstStackTraceEntry(NULL)
11231148
, _previousThreadEntry(NULL)
@@ -1232,6 +1257,12 @@ class VM_JFRConstantPoolTypes {
12321257
goto done;
12331258
}
12341259

1260+
_classLoadingStatisticsTable = pool_new(sizeof(ClassLoadingStatisticsEntry), 0, sizeof(U_64), 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM, POOL_FOR_PORT(privatePortLibrary));
1261+
if (NULL == _classLoadingStatisticsTable ) {
1262+
_buildResult = OutOfMemory;
1263+
goto done;
1264+
}
1265+
12351266
/* Add reserved index for default entries. For strings zero is the empty or NUll string.
12361267
* For package zero is the deafult package, for Module zero is the unnamed module. ThreadGroup
12371268
* zero is NULL threadGroup.
@@ -1320,6 +1351,7 @@ class VM_JFRConstantPoolTypes {
13201351
pool_kill(_monitorWaitTable);
13211352
pool_kill(_cpuLoadTable);
13221353
pool_kill(_threadCPULoadTable);
1354+
pool_kill(_classLoadingStatisticsTable);
13231355
j9mem_free_memory(_globalStringTable);
13241356
}
13251357

runtime/vm/classallocation.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ allocateClassLoader(J9JavaVM *javaVM)
169169
classLoader->moduleHashTable = hashModuleNameTableNew(javaVM, INITIAL_MODULE_HASHTABLE_SIZE);
170170
classLoader->packageHashTable = hashPackageTableNew(javaVM, INITIAL_PACKAGE_HASHTABLE_SIZE);
171171
#endif /* JAVA_SPEC_VERSION > 8 */
172+
173+
#if defined(J9VM_OPT_JFR)
174+
classLoader->loadedClassCount = 0;
175+
#endif /* defined(J9VM_OPT_JFR) */
176+
172177
/* Allocate classLocationHashTable only for bootloader which is the first classloader to be allocated.
173178
* The classLoader being allocated must be the bootloader if javaVM->systemClassLoader is NULL.
174179
*/

runtime/vm/createramclass.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2161,6 +2161,10 @@ internalCreateRAMClassDone(J9VMThread *vmThread, J9ClassLoader *classLoader, J9C
21612161
javaVM->anonClassCount += 1;
21622162
}
21632163

2164+
#if defined(J9VM_OPT_JFR)
2165+
hostClassLoader->loadedClassCount += 1;
2166+
#endif /* defined(J9VM_OPT_JFR) */
2167+
21642168
/* Create all the method IDs if class load is hooked */
21652169
if (J9_EVENT_IS_HOOKED(javaVM->hookInterface, J9HOOK_VM_CLASS_LOAD)) {
21662170
U_32 count = romClass->romMethodCount;

runtime/vm/jfr.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "JFRConstantPoolTypes.hpp"
2323
#include "j9protos.h"
2424
#include "omrlinkedlist.h"
25+
#include "pool_api.h"
2526
#include "thread_api.h"
2627
#include "ut_j9vm.h"
2728
#include "vm_internal.h"
@@ -92,6 +93,9 @@ jfrEventSize(J9JFREvent *jfrEvent)
9293
case J9JFR_EVENT_TYPE_THREAD_CPU_LOAD:
9394
size = sizeof(J9JFRThreadCPULoad);
9495
break;
96+
case J9JFR_EVENT_TYPE_CLASS_LOADING_STATISTICS:
97+
size = sizeof(J9JFRClassLoadingStatistics);
98+
break;
9599
default:
96100
Assert_VM_unreachable();
97101
break;
@@ -939,6 +943,36 @@ jfrThreadCPULoadCallback(J9VMThread *currentThread, IDATA handlerKey, void *user
939943
jfrThreadCPULoad(currentThread, currentThread);
940944
}
941945

946+
void
947+
jfrClassLoadingStatistics(J9VMThread *currentThread)
948+
{
949+
J9JavaVM *vm = currentThread->javaVM;
950+
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
951+
J9JFRClassLoadingStatistics *jfrEvent = (J9JFRClassLoadingStatistics *)reserveBuffer(currentThread, sizeof(J9JFRClassLoadingStatistics));
952+
953+
if (NULL != jfrEvent) {
954+
initializeEventFields(currentThread, (J9JFREvent *)jfrEvent, J9JFR_EVENT_TYPE_CLASS_LOADING_STATISTICS);
955+
956+
UDATA unloadedClassCount = 0;
957+
vm->memoryManagerFunctions->j9gc_get_cumulative_class_unloading_stats(currentThread, NULL, &unloadedClassCount, NULL);
958+
jfrEvent->unloadedClassCount = (I_64)unloadedClassCount;
959+
960+
internalReleaseVMAccess(currentThread);
961+
962+
J9ClassLoaderWalkState walkState = {0};
963+
J9ClassLoader *classLoader = vmFuncs->allClassLoadersStartDo(&walkState, vm, 0);
964+
965+
while (NULL != classLoader) {
966+
jfrEvent->loadedClassCount += classLoader->loadedClassCount;
967+
968+
classLoader= vmFuncs->allClassLoadersNextDo(&walkState);
969+
}
970+
vmFuncs->allClassLoadersEndDo(&walkState);
971+
972+
internalAcquireVMAccess(currentThread);
973+
}
974+
}
975+
942976
static int J9THREAD_PROC
943977
jfrSamplingThreadProc(void *entryArg)
944978
{
@@ -956,6 +990,7 @@ jfrSamplingThreadProc(void *entryArg)
956990
omrthread_monitor_exit(vm->jfrSamplerMutex);
957991
internalAcquireVMAccess(currentThread);
958992
jfrCPULoad(currentThread);
993+
jfrClassLoadingStatistics(currentThread);
959994
internalReleaseVMAccess(currentThread);
960995
omrthread_monitor_enter(vm->jfrSamplerMutex);
961996
if (0 == (count % 1000)) { // 10 seconds

0 commit comments

Comments
 (0)