Skip to content

Commit

Permalink
Add JFR ClassLoadingStatistics support
Browse files Browse the repository at this point in the history
Signed-off-by: Gengchen Tuo <gengchen.tuo@ibm.com>
  • Loading branch information
thallium committed Nov 29, 2024
1 parent b5ee59c commit 5db0741
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 0 deletions.
1 change: 1 addition & 0 deletions runtime/oti/j9consts.h
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,7 @@ extern "C" {
#define J9JFR_EVENT_TYPE_OBJECT_WAIT 4
#define J9JFR_EVENT_TYPE_CPU_LOAD 5
#define J9JFR_EVENT_TYPE_THREAD_CPU_LOAD 6
#define J9JFR_EVENT_TYPE_CLASS_LOADING_STATISTICS 7

/* JFR thread states */

Expand Down
9 changes: 9 additions & 0 deletions runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,12 @@ typedef struct J9JFRThreadCPULoad {
float system;
} J9JFRThreadCPULoad;

typedef struct J9JFRClassLoadingStatistics {
J9JFR_EVENT_COMMON_FIELDS
I_64 loadedClassCount;
I_64 unloadedClassCount;
} J9JFRClassLoadingStatistics;

#endif /* defined(J9VM_OPT_JFR) */

/* @ddr_namespace: map_to_type=J9CfrError */
Expand Down Expand Up @@ -3601,6 +3607,9 @@ typedef struct J9ClassLoader {
omrthread_rwmutex_t cpEntriesMutex;
UDATA initClassPathEntryCount;
UDATA asyncGetCallTraceUsed;
#if defined(J9VM_OPT_JFR)
UDATA loadedClassCount;
#endif /* defined(J9VM_OPT_JFR) */
} J9ClassLoader;

#define J9CLASSLOADER_SHARED_CLASSES_ENABLED 8
Expand Down
31 changes: 31 additions & 0 deletions runtime/vm/JFRChunkWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ enum MetadataTypeID {
CPUInformationID = 92,
CPULoadID = 94,
ThreadCPULoadID = 95,
ClassLoadingStatisticsID = 99,
PhysicalMemoryID = 107,
ExecutionSampleID = 108,
ThreadID = 163,
Expand Down Expand Up @@ -164,6 +165,7 @@ class VM_JFRChunkWriter {
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 INITIAL_ENVIRONMENT_VARIABLE_EVENT_SIZE = 6000;
static constexpr int CLASS_LOADING_STATISTICS_EVENT_SIZE = 5 * sizeof(I_64);

static constexpr int METADATA_ID = 1;

Expand Down Expand Up @@ -339,6 +341,8 @@ class VM_JFRChunkWriter {

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

pool_do(_constantPoolTypes.getClassLoadingStatisticsTable(), &writeClassLoadingStatisticsEvent, _bufferWriter);

/* Only write constant events in first chunk */
if (0 == _vm->jfrState.jfrChunkCount) {
writeJVMInformationEvent();
Expand Down Expand Up @@ -600,6 +604,31 @@ class VM_JFRChunkWriter {
_bufferWriter->writeLEB128PaddedU32(dataStart, _bufferWriter->getCursor() - dataStart);
}

static void
writeClassLoadingStatisticsEvent(void *anElement, void *userData)
{
ClassLoadingStatisticsEntry *entry = (ClassLoadingStatisticsEntry *)anElement;
VM_BufferWriter *_bufferWriter = (VM_BufferWriter *)userData;

/* reserve size field */
U_8 *dataStart = _bufferWriter->getAndIncCursor(sizeof(U_32));

/* write event type */
_bufferWriter->writeLEB128(ClassLoadingStatisticsID);

/* write start time */
_bufferWriter->writeLEB128(entry->ticks);

/* write user loaded class count */
_bufferWriter->writeFloat(entry->loadedClassCount);

/* write system unloaded class count */
_bufferWriter->writeFloat(entry->unloadedClassCount);

/* write size */
_bufferWriter->writeLEB128PaddedU32(dataStart, _bufferWriter->getCursor() - dataStart);
}

void
writeJFRChunkToFile()
{
Expand Down Expand Up @@ -728,6 +757,8 @@ class VM_JFRChunkWriter {

requiredBufferSize += _constantPoolTypes.getThreadCPULoadCount() * THREAD_CPU_LOAD_EVENT_SIZE;

requiredBufferSize += _constantPoolTypes.getClassLoadingStatisticsCount() * CLASS_LOADING_STATISTICS_EVENT_SIZE;

return requiredBufferSize;
}

Expand Down
22 changes: 22 additions & 0 deletions runtime/vm/JFRConstantPoolTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,28 @@ VM_JFRConstantPoolTypes::addThreadCPULoadEntry(J9JFRThreadCPULoad *threadCPULoad
return index;
}

U_32
VM_JFRConstantPoolTypes::addClassLoadingStatisticsEntry(J9JFRClassLoadingStatistics *classLoadingStatisticsData)
{
ClassLoadingStatisticsEntry *entry = (ClassLoadingStatisticsEntry *)pool_newElement(_classLoadingStatisticsTable);
U_32 index = U_32_MAX;

if (NULL == entry) {
_buildResult = OutOfMemory;
goto done;
}

entry->ticks = classLoadingStatisticsData->startTicks;
entry->loadedClassCount = classLoadingStatisticsData->loadedClassCount;
entry->unloadedClassCount = classLoadingStatisticsData->unloadedClassCount;

index = _classLoadingStatisticsCount;
_classLoadingStatisticsCount += 1;

done:
return index;
}

void
VM_JFRConstantPoolTypes::printTables()
{
Expand Down
32 changes: 32 additions & 0 deletions runtime/vm/JFRConstantPoolTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,12 @@ struct ThreadCPULoadEntry {
float system;
};

struct ClassLoadingStatisticsEntry {
I_64 ticks;
I_64 loadedClassCount;
I_64 unloadedClassCount;
};

struct JVMInformationEntry {
const char *jvmName;
const char *jvmVersion;
Expand Down Expand Up @@ -308,6 +314,8 @@ class VM_JFRConstantPoolTypes {
UDATA _cpuLoadCount;
J9Pool *_threadCPULoadTable;
UDATA _threadCPULoadCount;
J9Pool *_classLoadingStatisticsTable;
UDATA _classLoadingStatisticsCount;

/* Processing buffers */
StackFrame *_currentStackFrameBuffer;
Expand Down Expand Up @@ -560,6 +568,8 @@ class VM_JFRConstantPoolTypes {

U_32 addThreadCPULoadEntry(J9JFRThreadCPULoad *threadCPULoadData);

U_32 addClassLoadingStatisticsEntry(J9JFRClassLoadingStatistics *classLoadingStatisticsData);

J9Pool *getExecutionSampleTable()
{
return _executionSampleTable;
Expand Down Expand Up @@ -595,6 +605,11 @@ class VM_JFRConstantPoolTypes {
return _threadCPULoadTable;
}

J9Pool *getClassLoadingStatisticsTable()
{
return _classLoadingStatisticsTable;
}

UDATA getExecutionSampleCount()
{
return _executionSampleCount;
Expand Down Expand Up @@ -630,6 +645,11 @@ class VM_JFRConstantPoolTypes {
return _threadCPULoadCount;
}

UDATA getClassLoadingStatisticsCount()
{
return _classLoadingStatisticsCount;
}

ClassloaderEntry *getClassloaderEntry()
{
return _firstClassloaderEntry;
Expand Down Expand Up @@ -779,6 +799,9 @@ class VM_JFRConstantPoolTypes {
case J9JFR_EVENT_TYPE_THREAD_CPU_LOAD:
addThreadCPULoadEntry((J9JFRThreadCPULoad *)event);
break;
case J9JFR_EVENT_TYPE_CLASS_LOADING_STATISTICS:
addClassLoadingStatisticsEntry((J9JFRClassLoadingStatistics *)event);
break;
default:
Assert_VM_unreachable();
break;
Expand Down Expand Up @@ -1102,6 +1125,8 @@ class VM_JFRConstantPoolTypes {
, _cpuLoadCount(0)
, _threadCPULoadTable(NULL)
, _threadCPULoadCount(0)
, _classLoadingStatisticsTable(NULL)
, _classLoadingStatisticsCount(0)
, _previousStackTraceEntry(NULL)
, _firstStackTraceEntry(NULL)
, _previousThreadEntry(NULL)
Expand Down Expand Up @@ -1216,6 +1241,12 @@ class VM_JFRConstantPoolTypes {
goto done;
}

_classLoadingStatisticsTable = pool_new(sizeof(ClassLoadingStatisticsEntry), 0, sizeof(U_64), 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM, POOL_FOR_PORT(privatePortLibrary));
if (NULL == _classLoadingStatisticsTable ) {
_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.
Expand Down Expand Up @@ -1303,6 +1334,7 @@ class VM_JFRConstantPoolTypes {
pool_kill(_monitorWaitTable);
pool_kill(_cpuLoadTable);
pool_kill(_threadCPULoadTable);
pool_kill(_classLoadingStatisticsTable);
j9mem_free_memory(_globalStringTable);
}

Expand Down
5 changes: 5 additions & 0 deletions runtime/vm/classallocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,11 @@ allocateClassLoader(J9JavaVM *javaVM)
classLoader->moduleHashTable = hashModuleNameTableNew(javaVM, INITIAL_MODULE_HASHTABLE_SIZE);
classLoader->packageHashTable = hashPackageTableNew(javaVM, INITIAL_PACKAGE_HASHTABLE_SIZE);
#endif /* JAVA_SPEC_VERSION > 8 */

#if defined(J9VM_OPT_JFR)
classLoader->loadedClassCount = 0;
#endif /* defined(J9VM_OPT_JFR) */

/* Allocate classLocationHashTable only for bootloader which is the first classloader to be allocated.
* The classLoader being allocated must be the bootloader if javaVM->systemClassLoader is NULL.
*/
Expand Down
4 changes: 4 additions & 0 deletions runtime/vm/createramclass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2163,6 +2163,10 @@ internalCreateRAMClassDone(J9VMThread *vmThread, J9ClassLoader *classLoader, J9C
javaVM->anonClassCount += 1;
}

#if defined(J9VM_OPT_JFR)
hostClassLoader->loadedClassCount += 1;
#endif /* defined(J9VM_OPT_JFR) */

/* Create all the method IDs if class load is hooked */
if (J9_EVENT_IS_HOOKED(javaVM->hookInterface, J9HOOK_VM_CLASS_LOAD)) {
U_32 count = romClass->romMethodCount;
Expand Down
35 changes: 35 additions & 0 deletions runtime/vm/jfr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "JFRConstantPoolTypes.hpp"
#include "j9protos.h"
#include "omrlinkedlist.h"
#include "pool_api.h"
#include "thread_api.h"
#include "ut_j9vm.h"
#include "vm_internal.h"
Expand Down Expand Up @@ -92,6 +93,9 @@ jfrEventSize(J9JFREvent *jfrEvent)
case J9JFR_EVENT_TYPE_THREAD_CPU_LOAD:
size = sizeof(J9JFRThreadCPULoad);
break;
case J9JFR_EVENT_TYPE_CLASS_LOADING_STATISTICS:
size = sizeof(J9JFRClassLoadingStatistics);
break;
default:
Assert_VM_unreachable();
break;
Expand Down Expand Up @@ -939,6 +943,36 @@ jfrThreadCPULoadCallback(J9VMThread *currentThread, IDATA handlerKey, void *user
jfrThreadCPULoad(currentThread, currentThread);
}

void
jfrClassLoadingStatistics(J9VMThread *currentThread)
{
J9JavaVM *vm = currentThread->javaVM;
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
J9JFRClassLoadingStatistics *jfrEvent = (J9JFRClassLoadingStatistics *)reserveBuffer(currentThread, sizeof(J9JFRClassLoadingStatistics));

if (NULL != jfrEvent) {
initializeEventFields(currentThread, (J9JFREvent *)jfrEvent, J9JFR_EVENT_TYPE_CLASS_LOADING_STATISTICS);

UDATA unloadedClassCount = 0;
vm->memoryManagerFunctions->j9gc_get_cumulative_class_unloading_stats(currentThread, NULL, &unloadedClassCount, NULL);
jfrEvent->unloadedClassCount = (I_64)unloadedClassCount;

internalReleaseVMAccess(currentThread);

J9ClassLoaderWalkState walkState = {0};
J9ClassLoader *classLoader = vmFuncs->allClassLoadersStartDo(&walkState, vm, 0);

while (NULL != classLoader) {
jfrEvent->loadedClassCount += classLoader->loadedClassCount;

classLoader= vmFuncs->allClassLoadersNextDo(&walkState);
}
vmFuncs->allClassLoadersEndDo(&walkState);

internalAcquireVMAccess(currentThread);
}
}

static int J9THREAD_PROC
jfrSamplingThreadProc(void *entryArg)
{
Expand All @@ -956,6 +990,7 @@ jfrSamplingThreadProc(void *entryArg)
omrthread_monitor_exit(vm->jfrSamplerMutex);
internalAcquireVMAccess(currentThread);
jfrCPULoad(currentThread);
jfrClassLoadingStatistics(currentThread);
internalReleaseVMAccess(currentThread);
omrthread_monitor_enter(vm->jfrSamplerMutex);
if (0 == (count % 1000)) { // 10 seconds
Expand Down

0 comments on commit 5db0741

Please sign in to comment.