KEMBAR78
Latency Profiling enhancements by fandreuz · Pull Request #1499 · async-profiler/async-profiler · GitHub
Skip to content

Conversation

fandreuz
Copy link
Contributor

@fandreuz fandreuz commented Sep 19, 2025

Description

  • Removed --latency in favor of --trace
  • Format examples:
    • --trace A.B: latency=0, wildcard signature
    • --trace A.B(JJ)V: latency=0
    • --trace A.B(JJ)V+10ms: latency=10ms
    • --trace A.B+10ms: latency=10ms, wildcard signature
  • --trace can appear multiple times in the arguments
  • --trace can target multiple methods in the same or different classes
  • --trace takes one independent latency threshold for each target
  • event=A.B will always perform "old" instrumentation
  • Latency profiling can run in parallel with other profiling modes
  • args._include/exclude now use std::vector

Related issues

#1421

Motivation and context

This feature is nice to have for users, latency profiling should not exclude other profiling modes.

How has this been tested?

New tests.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@fandreuz fandreuz changed the title Enable CPU sampling and latency profiling to run together Enable CPU sampling and method tracing to run together Sep 19, 2025
@fandreuz fandreuz marked this pull request as draft September 26, 2025 13:18
@fandreuz
Copy link
Contributor Author

Hi team, thanks for the feedback. This PR currently does a bit more than what I was expecting:

  • enable method tracing in parallel with other engines
  • enable multiple methods to be traced

I'll need some more changes to get the following:

  1. enable multiple methods to be traced in the same class (won't work at the moment)
  2. per-method latency
  3. per-method interval

I see two ways to move forward:

  • keep this PR open a bit more and add all the required features (I think 1# is needed, 2# is nice, 3# is lower-priority);
  • we add checks to report an appropriate failure when user tries to do 1#, merge this PR, and follow-up later.

Any thoughts @apangin ?

@fandreuz fandreuz marked this pull request as ready for review September 29, 2025 14:34
@fandreuz fandreuz marked this pull request as draft September 29, 2025 15:26
@fandreuz
Copy link
Contributor Author

I propose the following action table:

trace=A.B(50ms) event=NULL event=cpu event=C.D latency=100ms Result
yes yes no no yes Error: unexpected argument latency
yes no yes no yes Error: unexpected argument latency
yes no no yes yes Trace A.B with latency=50ms, trace C.D with latency=100ms
yes yes no no no Trace A.B with latency=50ms
yes no yes no no Trace A.B with latency=50ms, and cpu sampling
yes no no yes no Trace A.B with latency=50ms, old instrumentation on C.D
no yes no no yes Error: unexpected argument latency
no no yes no yes Error: unexpected argument latency
no no no yes yes Trace C.D with latency=100ms
no yes no no no Cpu sampling
no no yes no no Cpu sampling
no no no yes no Old instrumentation on C.D

Q:

  • Is it ok to let --latency refer only to event=C.D, not to --trace?
    • Consequence: --trace=A.B will fail, --trace=A.B(50ms) is expected
    • Alternative: --trace=A.B will do old instrumentation rather than method tracing
      - If we do this, then we should probably reconsider the name --trace as it won't only do method tracing
  • Do we want to support row 3# ?

@fandreuz
Copy link
Contributor Author

Discussed offline, we'll remove --latency. New table:

trace=A.B(50ms) event=NULL event=cpu event=C.D Result
yes yes no no Trace A.B with latency=50ms
yes no yes no Trace A.B with latency=50ms, and cpu sampling
yes no no yes Trace A.B with latency=50ms, old instrumentation on C.D
no yes no no Cpu sampling
no no yes no Cpu sampling
no no no yes Old instrumentation on C.D

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Clang-Tidy found issue(s) with the introduced code (1/1)

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Clang-Tidy found issue(s) with the introduced code (1/1)

@fandreuz fandreuz marked this pull request as ready for review October 2, 2025 08:46
@fandreuz fandreuz changed the title Enable CPU sampling and method tracing to run together Latency profiling enhancements Oct 2, 2025
@fandreuz
Copy link
Contributor Author

This PR is already very large and not easy to review as is. I think we should take every chance to refactor bits out that can be merged in smaller PRs.

@fandreuz I think the commit should be pushed into a separate PR

Are there other candidates to refactor out into new smaller PRs, in addition to this?

Not really, all these changes should go together as they don't really make sense without each other now. I proposed to split them here, but my comment did not receive any reaction.

I reverted 12b4ce7 in d49d41a.

Comment on lines 1251 to 1252
// Make sure the class is rewritten, constant pool reconstitution
// doesn't always work (JDK-8216547)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is JDK-8216547 related here?

Copy link
Contributor Author

@fandreuz fandreuz Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I have if (name == NULL) return in the ClassFileLoadHook i get a segfault with this stacktrace:

V  [libjvm.so+0xa9a409]  Symbol::as_C_string() const+0x9
V  [libjvm.so+0x4e6cd1]  ConstantPool::copy_cpool_bytes(int, SymbolHashMap*, unsigned char*)+0x191
V  [libjvm.so+0x75d83c]  JvmtiClassFileReconstituter::write_class_file_format()+0x2cc
V  [libjvm.so+0x7b4f5f]  JvmtiEnv::RetransformClasses(int, _jclass* const*)+0x78f
V  [libjvm.so+0x7600a6]  jvmti_RetransformClasses+0x136
C  [libasyncProfiler.so+0xea53]  VM::RetransformClassesHook(_jvmtiEnv*, int, _jclass* const*)+0x23
C  [libasyncProfiler.so+0x1ea6d]  Instrument::retransformMatchedClasses(_jvmtiEnv*) [clone .constprop.0]+0xcd
C  [libasyncProfiler.so+0x1ecbf]  Instrument::stop()+0x2f
C  [libasyncProfiler.so+0x4b61d]  Profiler::stop(bool)+0xbd
C  [libasyncProfiler.so+0x5468f]  Profiler::runInternal(Arguments&, Writer&)+0x14f
C  [libasyncProfiler.so+0x55326]  Profiler::run(Arguments&)+0xc6
C  [libasyncProfiler.so+0x5605e]  VM::VMDeath(_jvmtiEnv*, JNIEnv_*)+0x4e
V  [libjvm.so+0x7c1b69]  JvmtiExport::post_vm_death()+0x1f9
V  [libjvm.so+0x69dfbf]  before_exit(JavaThread*)+0x12f
V  [libjvm.so+0xae450b]  Threads::destroy_vm()+0x34b
V  [libjvm.so+0x7110cf]  jni_DestroyJavaVM+0x7f
C  [libjli.so+0x8618]  JavaMain+0x5c8
C  [libc.so.6+0x891f5]

My impression is that the class data is corrupted somehow and needs to be copied from the original version, which is more or less what is happening in the ticket. I could investigate more if you want to understand the root cause, but it only affects jdk8 and I figured it's not a priority.

Copy link
Contributor Author

@fandreuz fandreuz Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works fine:

if (name == NULL) {
    VM::jvmti()->Allocate(class_data_len, new_class_data);
    memcpy(*new_class_data, class_data, class_data_len);
    *new_class_data_len = class_data_len;
    return;
}

but does not support the request you had the other day, that we should support the feature even when name == NULL by getting the name from class_data.

u16 name_idx = _cpool[i]->info();
const auto& it = _targets->find(_cpool[name_idx]->as_string());
if (it == _targets->end()) {
_target_methods = &EMPTY_METHOD_TARGETS;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EMPTY_METHOD_TARGETS does not make sense to me.
If there is nothing to rewrite, return immediately.
If returning NULL from ClassFileLoadHook does not work for some reason (I still don't understand why), you can just copy _src to _dst, and that's it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If returning NULL from ClassFileLoadHook does not work for some reason (I still don't understand why),

See here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just copy _src to _dst, and that's it.

Check Result::ABORTED: 5696577

@apangin apangin merged commit fc2a9b9 into async-profiler:master Oct 15, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants