1717
1818#include " profiler.h"
1919#include " asyncSampleMutex.h"
20+ #include " common.h"
2021#include " context.h"
2122#include " counters.h"
2223#include " ctimer.h"
@@ -548,51 +549,6 @@ int Profiler::getJavaTraceAsync(void *ucontext, ASGCT_CallFrame *frames,
548549 return trace.frames - frames + 1 ;
549550}
550551
551- int Profiler::getJavaTraceJvmti (jvmtiFrameInfo *jvmti_frames,
552- ASGCT_CallFrame *frames, int start_depth,
553- int max_depth) {
554- int num_frames;
555- if (VM::jvmti ()->GetStackTrace (NULL , start_depth, _max_stack_depth,
556- jvmti_frames, &num_frames) == 0 &&
557- num_frames > 0 ) {
558- return convertFrames (jvmti_frames, frames, num_frames);
559- }
560- return 0 ;
561- }
562-
563- int Profiler::getJavaTraceInternal (jvmtiFrameInfo *jvmti_frames,
564- ASGCT_CallFrame *frames, int max_depth) {
565- // We cannot call pure JVM TI here, because it assumes _thread_in_native
566- // state, but allocation events happen in _thread_in_vm state, see
567- // https://github.com/jvm-profiling-tools/java-profiler/issues/64
568- JNIEnv *jni = VM::jni ();
569- if (jni == NULL ) {
570- return 0 ;
571- }
572-
573- JitWriteProtection jit (false );
574- VMThread *vm_thread = VMThread::fromEnv (jni);
575- int num_frames;
576- if (VMStructs::_get_stack_trace (NULL , vm_thread, 0 , max_depth, jvmti_frames,
577- &num_frames) == 0 &&
578- num_frames > 0 ) {
579- return convertFrames (jvmti_frames, frames, num_frames);
580- }
581- return 0 ;
582- }
583-
584- inline int Profiler::convertFrames (jvmtiFrameInfo *jvmti_frames,
585- ASGCT_CallFrame *frames, int num_frames) {
586- // Convert to AsyncGetCallTrace format.
587- // Note: jvmti_frames and frames may overlap.
588- for (int i = 0 ; i < num_frames; i++) {
589- jint bci = jvmti_frames[i].location ;
590- frames[i].method_id = jvmti_frames[i].method ;
591- frames[i].bci = bci;
592- }
593- return num_frames;
594- }
595-
596552void Profiler::fillFrameTypes (ASGCT_CallFrame *frames, int num_frames,
597553 NMethod *nmethod) {
598554 if (nmethod->isNMethod () && nmethod->isAlive ()) {
@@ -634,10 +590,7 @@ void Profiler::fillFrameTypes(ASGCT_CallFrame *frames, int num_frames,
634590 }
635591}
636592
637- void Profiler::recordExternalSample (u64 counter, int tid,
638- jvmtiFrameInfo *jvmti_frames,
639- jint num_jvmti_frames, bool truncated,
640- jint event_type, Event *event) {
593+ u32 Profiler::recordJVMTISample (u64 counter, int tid, jthread thread, jint event_type, Event *event, bool deferred) {
641594 atomicInc (_total_samples);
642595
643596 u32 lock_index = getLockIndex (tid);
@@ -647,29 +600,50 @@ void Profiler::recordExternalSample(u64 counter, int tid,
647600 // Too many concurrent signals already
648601 atomicInc (_failures[-ticks_skipped]);
649602
650- if (event_type == BCI_CPU && _cpu_engine == &perf_events) {
651- // Need to reset PerfEvents ring buffer, even though we discard the
652- // collected trace
653- PerfEvents::resetBuffer (tid);
654- }
655- return ;
603+ return 0 ;
656604 }
657605 u32 call_trace_id = 0 ;
658- if (!_omit_stacktraces && jvmti_frames != nullptr ) {
606+ if (!_omit_stacktraces) {
659607 ASGCT_CallFrame *frames = _calltrace_buffer[lock_index]->_asgct_frames ;
608+ jvmtiFrameInfo *jvmti_frames = _calltrace_buffer[lock_index]->_jvmti_frames ;
660609
661610 int num_frames = 0 ;
662- if (!_jfr.active () && BCI_ALLOC >= event_type && event_type >= BCI_PARK &&
663- event->_id ) {
664- num_frames = makeFrame (frames, event_type, event->_id );
611+
612+ if (VM::jvmti ()->GetStackTrace (thread, 0 , _max_stack_depth, jvmti_frames, &num_frames) == JVMTI_ERROR_NONE && num_frames > 0 ) {
613+ // Convert to AsyncGetCallTrace format.
614+ // Note: jvmti_frames and frames may overlap.
615+ for (int i = 0 ; i < num_frames; i++) {
616+ jint bci = jvmti_frames[i].location ;
617+ jmethodID mid = jvmti_frames[i].method ;
618+ frames[i].method_id = mid;
619+ frames[i].bci = bci;
620+ // see https://github.com/async-profiler/async-profiler/pull/1090
621+ LP64_ONLY (frames[i].padding = 0 ;)
622+ }
665623 }
666624
667- num_frames +=
668- convertFrames (jvmti_frames, frames + num_frames, num_jvmti_frames);
625+ call_trace_id = _call_trace_storage.put (num_frames, frames, false , counter);
626+ }
627+ if (!deferred) {
628+ _jfr.recordEvent (lock_index, tid, call_trace_id, event_type, event);
629+ }
630+
631+ _locks[lock_index].unlock ();
632+ return call_trace_id;
633+ }
669634
670- call_trace_id =
671- _call_trace_storage.put (num_frames, frames, truncated, counter);
635+ void Profiler::recordDeferredSample (int tid, u32 call_trace_id, jint event_type, Event *event) {
636+ atomicInc (_total_samples);
637+
638+ u32 lock_index = getLockIndex (tid);
639+ if (!_locks[lock_index].tryLock () &&
640+ !_locks[lock_index = (lock_index + 1 ) % CONCURRENCY_LEVEL].tryLock () &&
641+ !_locks[lock_index = (lock_index + 2 ) % CONCURRENCY_LEVEL].tryLock ()) {
642+ // Too many concurrent signals already
643+ atomicInc (_failures[-ticks_skipped]);
644+ return ;
672645 }
646+
673647 _jfr.recordEvent (lock_index, tid, call_trace_id, event_type, event);
674648
675649 _locks[lock_index].unlock ();
@@ -1153,13 +1127,11 @@ Error Profiler::start(Arguments &args, bool reset) {
11531127 // (Re-)allocate calltrace buffers
11541128 if (_max_stack_depth != args._jstackdepth ) {
11551129 _max_stack_depth = args._jstackdepth ;
1156- size_t buffer_size =
1157- (_max_stack_depth + MAX_NATIVE_FRAMES + RESERVED_FRAMES) *
1158- sizeof (CallTraceBuffer);
1130+ size_t nelem = _max_stack_depth + MAX_NATIVE_FRAMES + RESERVED_FRAMES;
11591131
11601132 for (int i = 0 ; i < CONCURRENCY_LEVEL; i++) {
11611133 free (_calltrace_buffer[i]);
1162- _calltrace_buffer[i] = (CallTraceBuffer *) malloc (buffer_size );
1134+ _calltrace_buffer[i] = (CallTraceBuffer*) calloc (nelem, sizeof (CallTraceBuffer) );
11631135 if (_calltrace_buffer[i] == NULL ) {
11641136 _max_stack_depth = 0 ;
11651137 return Error (" Not enough memory to allocate stack trace buffers (try "
0 commit comments