@@ -32,9 +32,10 @@ extern "C" {
32
32
33
33
#undef DEBUG
34
34
35
- // TODO: allow different buffer sizes on different threads and configureable sizes
35
+ // TODO: allow configureable values
36
36
#define J9JFR_THREAD_BUFFER_SIZE (1024 *1024 )
37
37
#define J9JFR_GLOBAL_BUFFER_SIZE (10 * J9JFR_THREAD_BUFFER_SIZE)
38
+ #define J9JFR_SAMPLING_RATE 1000
38
39
39
40
static UDATA jfrEventSize (J9JFREvent *jfrEvent);
40
41
static void tearDownJFR (J9JavaVM *vm);
@@ -48,7 +49,9 @@ static void jfrClassesUnload(J9HookInterface **hook, UDATA eventNum, void *event
48
49
static void jfrVMShutdown (J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);
49
50
static void jfrThreadStarting (J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);
50
51
static void jfrThreadEnd (J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);
52
+ static void jfrVMInitialized (J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);
51
53
static void initializeEventFields (J9VMThread *currentThread, J9JFREvent *jfrEvent, UDATA eventType);
54
+ static int J9THREAD_PROC jfrSamplingThreadProc (void *entryArg);
52
55
53
56
/* *
54
57
* Calculate the size in bytes of a JFR event.
@@ -496,6 +499,41 @@ jfrVMSleep(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userDa
496
499
}
497
500
}
498
501
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
+
499
537
jint
500
538
initializeJFR (J9JavaVM *vm)
501
539
{
@@ -525,8 +563,11 @@ initializeJFR(J9JavaVM *vm)
525
563
if ((*vmHooks)->J9HookRegisterWithCallSite (vmHooks, J9HOOK_VM_SLEEP, jfrVMSleep, OMR_GET_CALLSITE (), NULL )) {
526
564
goto fail;
527
565
}
566
+ if ((*vmHooks)->J9HookRegisterWithCallSite (vmHooks, J9HOOK_VM_INITIALIZED, jfrVMInitialized, OMR_GET_CALLSITE (), NULL )) {
567
+ goto fail;
568
+ }
528
569
529
- /* Allocate the global buffer and mutex */
570
+ /* Allocate global data */
530
571
buffer = (U_8*)j9mem_allocate_memory (J9JFR_GLOBAL_BUFFER_SIZE, OMRMEM_CATEGORY_VM);
531
572
if (NULL == buffer) {
532
573
goto fail;
@@ -537,7 +578,10 @@ initializeJFR(J9JavaVM *vm)
537
578
vm->jfrBuffer .bufferRemaining = J9JFR_GLOBAL_BUFFER_SIZE;
538
579
vm->jfrState .jfrChunkCount = 0 ;
539
580
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;
541
585
}
542
586
543
587
if (!VM_JFRWriter::initializaJFRWriter (vm)) {
@@ -563,6 +607,21 @@ tearDownJFR(J9JavaVM *vm)
563
607
PORT_ACCESS_FROM_JAVAVM (vm);
564
608
J9HookInterface **vmHooks = getVMHookInterface (vm);
565
609
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
+
566
625
VM_JFRWriter::teardownJFRWriter (vm);
567
626
568
627
/* Unhook all the events */
@@ -573,17 +632,18 @@ tearDownJFR(J9JavaVM *vm)
573
632
(*vmHooks)->J9HookUnregister (vmHooks, J9HOOK_VM_THREAD_STARTING, jfrThreadStarting, NULL );
574
633
(*vmHooks)->J9HookUnregister (vmHooks, J9HOOK_VM_THREAD_END, jfrThreadEnd, NULL );
575
634
(*vmHooks)->J9HookUnregister (vmHooks, J9HOOK_VM_SLEEP, jfrVMSleep, NULL );
635
+ (*vmHooks)->J9HookUnregister (vmHooks, J9HOOK_VM_INITIALIZED, jfrVMInitialized, NULL );
576
636
577
- /* Free global buffer and mutex */
578
-
637
+ /* Free global data */
579
638
j9mem_free_memory ((void *)vm->jfrBuffer .bufferStart );
580
639
memset (&vm->jfrBuffer , 0 , sizeof (vm->jfrBuffer ));
581
640
if (NULL != vm->jfrBufferMutex ) {
582
641
omrthread_monitor_destroy (vm->jfrBufferMutex );
583
642
vm->jfrBufferMutex = NULL ;
584
643
}
585
- vm->jfrState .metaDataBlobFileSize = 0 ;
586
644
j9mem_free_memory (vm->jfrState .metaDataBlobFile );
645
+ vm->jfrState .metaDataBlobFile = NULL ;
646
+ vm->jfrState .metaDataBlobFileSize = 0 ;
587
647
}
588
648
589
649
/* *
@@ -602,15 +662,58 @@ initializeEventFields(J9VMThread *currentThread, J9JFREvent *event, UDATA eventT
602
662
event->vmThread = currentThread;
603
663
}
604
664
665
+ // TODO: add thread state parameter
605
666
void
606
667
jfrExecutionSample (J9VMThread *currentThread, J9VMThread *sampleThread)
607
668
{
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
+
608
674
J9JFRExecutionSample *jfrEvent = (J9JFRExecutionSample*)reserveBufferWithStackTrace (currentThread, sampleThread, J9JFR_EVENT_TYPE_EXECUTION_SAMPLE, sizeof (*jfrEvent));
609
675
if (NULL != jfrEvent) {
610
676
jfrEvent->threadState = J9JFR_THREAD_STATE_RUNNING;
611
677
}
612
678
}
613
679
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, ¤tThread, " 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
+
614
717
} /* extern "C" */
615
718
616
719
#endif /* defined(J9VM_OPT_JFR) */
0 commit comments