Skip to content

Commit 1cac505

Browse files
authored
Merge pull request #19951 from gacholio/jfr
Basic sampling thread for JFR
2 parents d57675e + f84fbc7 commit 1cac505

File tree

2 files changed

+117
-6
lines changed

2 files changed

+117
-6
lines changed

runtime/oti/j9nonbuilder.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6147,6 +6147,9 @@ typedef struct J9JavaVM {
61476147
JFRState jfrState;
61486148
J9JFRBuffer jfrBuffer;
61496149
omrthread_monitor_t jfrBufferMutex;
6150+
omrthread_monitor_t jfrSamplerMutex;
6151+
omrthread_t jfrSamplerThread;
6152+
UDATA jfrSamplerState;
61506153
#endif /* defined(J9VM_OPT_JFR) */
61516154
#if JAVA_SPEC_VERSION >= 22
61526155
omrthread_monitor_t closeScopeMutex;
@@ -6155,6 +6158,11 @@ typedef struct J9JavaVM {
61556158
UDATA unsafeIndexableHeaderSize;
61566159
} J9JavaVM;
61576160

6161+
#define J9JFR_SAMPLER_STATE_UNINITIALIZED 0
6162+
#define J9JFR_SAMPLER_STATE_RUNNING 1
6163+
#define J9JFR_SAMPLER_STATE_STOP 2
6164+
#define J9JFR_SAMPLER_STATE_DEAD 3
6165+
61586166
#define J9VM_PHASE_STARTUP 1
61596167
#define J9VM_PHASE_NOT_STARTUP 2
61606168
#define J9VM_PHASE_LATE_SCC_DISCLAIM 3

runtime/vm/jfr.cpp

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ extern "C" {
3232

3333
#undef DEBUG
3434

35-
// TODO: allow different buffer sizes on different threads and configureable sizes
35+
// TODO: allow configureable values
3636
#define J9JFR_THREAD_BUFFER_SIZE (1024*1024)
3737
#define J9JFR_GLOBAL_BUFFER_SIZE (10 * J9JFR_THREAD_BUFFER_SIZE)
38+
#define J9JFR_SAMPLING_RATE 1000
3839

3940
static UDATA jfrEventSize(J9JFREvent *jfrEvent);
4041
static void tearDownJFR(J9JavaVM *vm);
@@ -48,7 +49,9 @@ static void jfrClassesUnload(J9HookInterface **hook, UDATA eventNum, void *event
4849
static void jfrVMShutdown(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);
4950
static void jfrThreadStarting(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);
5051
static void jfrThreadEnd(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);
52+
static void jfrVMInitialized(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);
5153
static void initializeEventFields(J9VMThread *currentThread, J9JFREvent *jfrEvent, UDATA eventType);
54+
static int J9THREAD_PROC jfrSamplingThreadProc(void *entryArg);
5255

5356
/**
5457
* Calculate the size in bytes of a JFR event.
@@ -496,6 +499,41 @@ jfrVMSleep(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userDa
496499
}
497500
}
498501

502+
/**
503+
* Hook for VM intialized. Called without VM access.
504+
*
505+
* @param hook[in] the VM hook interface
506+
* @param eventNum[in] the event number
507+
* @param eventData[in] the event data
508+
* @param userData[in] the registered user data
509+
*/
510+
static void
511+
jfrVMInitialized(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)
512+
{
513+
J9VMInitEvent *event = (J9VMInitEvent *)eventData;
514+
J9VMThread *currentThread = event->vmThread;
515+
J9JavaVM *vm = currentThread->javaVM;
516+
517+
#if defined(DEBUG)
518+
PORT_ACCESS_FROM_VMC(currentThread);
519+
j9tty_printf(PORTLIB, "\n!!! VM init %p\n", currentThread);
520+
#endif /* defined(DEBUG) */
521+
522+
/* Start the sampler thread */
523+
if (0 == omrthread_create(&(vm->jfrSamplerThread), vm->defaultOSStackSize, J9THREAD_PRIORITY_NORMAL, FALSE, jfrSamplingThreadProc, (void*)vm)) {
524+
omrthread_monitor_enter(vm->jfrSamplerMutex);
525+
while (J9JFR_SAMPLER_STATE_UNINITIALIZED == vm->jfrSamplerState) {
526+
omrthread_monitor_wait(vm->jfrSamplerMutex);
527+
}
528+
omrthread_monitor_exit(vm->jfrSamplerMutex);
529+
if (J9JFR_SAMPLER_STATE_DEAD == vm->jfrSamplerState) {
530+
// TODO: tracepoint?
531+
}
532+
} else {
533+
// TODO: tracepoint?
534+
}
535+
}
536+
499537
jint
500538
initializeJFR(J9JavaVM *vm)
501539
{
@@ -525,8 +563,11 @@ initializeJFR(J9JavaVM *vm)
525563
if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_SLEEP, jfrVMSleep, OMR_GET_CALLSITE(), NULL)) {
526564
goto fail;
527565
}
566+
if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_INITIALIZED, jfrVMInitialized, OMR_GET_CALLSITE(), NULL)) {
567+
goto fail;
568+
}
528569

529-
/* Allocate the global buffer and mutex */
570+
/* Allocate global data */
530571
buffer = (U_8*)j9mem_allocate_memory(J9JFR_GLOBAL_BUFFER_SIZE, OMRMEM_CATEGORY_VM);
531572
if (NULL == buffer) {
532573
goto fail;
@@ -537,7 +578,10 @@ initializeJFR(J9JavaVM *vm)
537578
vm->jfrBuffer.bufferRemaining = J9JFR_GLOBAL_BUFFER_SIZE;
538579
vm->jfrState.jfrChunkCount = 0;
539580
if (omrthread_monitor_init_with_name(&vm->jfrBufferMutex, 0, "JFR global buffer mutex")) {
540-
goto done;
581+
goto fail;
582+
}
583+
if (omrthread_monitor_init_with_name(&vm->jfrSamplerMutex, 0, "JFR sampler mutex")) {
584+
goto fail;
541585
}
542586

543587
if (!VM_JFRWriter::initializaJFRWriter(vm)) {
@@ -563,6 +607,21 @@ tearDownJFR(J9JavaVM *vm)
563607
PORT_ACCESS_FROM_JAVAVM(vm);
564608
J9HookInterface **vmHooks = getVMHookInterface(vm);
565609

610+
/* Stop the sampler thread */
611+
if (NULL != vm->jfrSamplerMutex) {
612+
omrthread_monitor_enter(vm->jfrSamplerMutex);
613+
if (J9JFR_SAMPLER_STATE_RUNNING == vm->jfrSamplerState) {
614+
vm->jfrSamplerState = J9JFR_SAMPLER_STATE_STOP;
615+
omrthread_monitor_notify_all(vm->jfrSamplerMutex);
616+
while (J9JFR_SAMPLER_STATE_DEAD != vm->jfrSamplerState) {
617+
omrthread_monitor_wait(vm->jfrSamplerMutex);
618+
}
619+
}
620+
omrthread_monitor_exit(vm->jfrSamplerMutex);
621+
omrthread_monitor_destroy(vm->jfrSamplerMutex);
622+
vm->jfrSamplerMutex = NULL;
623+
}
624+
566625
VM_JFRWriter::teardownJFRWriter(vm);
567626

568627
/* Unhook all the events */
@@ -573,17 +632,18 @@ tearDownJFR(J9JavaVM *vm)
573632
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_THREAD_STARTING, jfrThreadStarting, NULL);
574633
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_THREAD_END, jfrThreadEnd, NULL);
575634
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_SLEEP, jfrVMSleep, NULL);
635+
(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_INITIALIZED, jfrVMInitialized, NULL);
576636

577-
/* Free global buffer and mutex */
578-
637+
/* Free global data */
579638
j9mem_free_memory((void*)vm->jfrBuffer.bufferStart);
580639
memset(&vm->jfrBuffer, 0, sizeof(vm->jfrBuffer));
581640
if (NULL != vm->jfrBufferMutex) {
582641
omrthread_monitor_destroy(vm->jfrBufferMutex);
583642
vm->jfrBufferMutex = NULL;
584643
}
585-
vm->jfrState.metaDataBlobFileSize = 0;
586644
j9mem_free_memory(vm->jfrState.metaDataBlobFile);
645+
vm->jfrState.metaDataBlobFile = NULL;
646+
vm->jfrState.metaDataBlobFileSize = 0;
587647
}
588648

589649
/**
@@ -602,15 +662,58 @@ initializeEventFields(J9VMThread *currentThread, J9JFREvent *event, UDATA eventT
602662
event->vmThread = currentThread;
603663
}
604664

665+
// TODO: add thread state parameter
605666
void
606667
jfrExecutionSample(J9VMThread *currentThread, J9VMThread *sampleThread)
607668
{
669+
#if defined(DEBUG)
670+
PORT_ACCESS_FROM_VMC(currentThread);
671+
j9tty_printf(PORTLIB, "\n!!! execution sample %p %p\n", currentThread, sampleThread);
672+
#endif /* defined(DEBUG) */
673+
608674
J9JFRExecutionSample *jfrEvent = (J9JFRExecutionSample*)reserveBufferWithStackTrace(currentThread, sampleThread, J9JFR_EVENT_TYPE_EXECUTION_SAMPLE, sizeof(*jfrEvent));
609675
if (NULL != jfrEvent) {
610676
jfrEvent->threadState = J9JFR_THREAD_STATE_RUNNING;
611677
}
612678
}
613679

680+
static int J9THREAD_PROC
681+
jfrSamplingThreadProc(void *entryArg)
682+
{
683+
J9JavaVM *vm = (J9JavaVM*)entryArg;
684+
J9VMThread *currentThread = NULL;
685+
686+
if (JNI_OK == attachSystemDaemonThread(vm, &currentThread, "JFR sampler")) {
687+
omrthread_monitor_enter(vm->jfrSamplerMutex);
688+
vm->jfrSamplerState = J9JFR_SAMPLER_STATE_RUNNING;
689+
omrthread_monitor_notify_all(vm->jfrSamplerMutex);
690+
while (J9JFR_SAMPLER_STATE_STOP != vm->jfrSamplerState) {
691+
omrthread_monitor_exit(vm->jfrSamplerMutex);
692+
internalEnterVMFromJNI(currentThread);
693+
acquireExclusiveVMAccess(currentThread);
694+
J9VMThread *walkThread = J9_LINKED_LIST_START_DO(vm->mainThread);
695+
while (NULL != walkThread) {
696+
if (VM_VMHelpers::threadCanRunJavaCode(walkThread)) {
697+
jfrExecutionSample(currentThread, walkThread);
698+
}
699+
walkThread = J9_LINKED_LIST_NEXT_DO(vm->mainThread, walkThread);
700+
}
701+
releaseExclusiveVMAccess(currentThread);
702+
internalExitVMToJNI(currentThread);
703+
omrthread_monitor_enter(vm->jfrSamplerMutex);
704+
omrthread_monitor_wait_timed(vm->jfrSamplerMutex, J9JFR_SAMPLING_RATE, 0);
705+
}
706+
omrthread_monitor_exit(vm->jfrSamplerMutex);
707+
DetachCurrentThread((JavaVM*)vm);
708+
}
709+
710+
omrthread_monitor_enter(vm->jfrSamplerMutex);
711+
vm->jfrSamplerState = J9JFR_SAMPLER_STATE_DEAD;
712+
omrthread_monitor_notify_all(vm->jfrSamplerMutex);
713+
omrthread_exit(vm->jfrSamplerMutex);
714+
return 0;
715+
}
716+
614717
} /* extern "C" */
615718

616719
#endif /* defined(J9VM_OPT_JFR) */

0 commit comments

Comments
 (0)