RFR: 8342818: Implement JEP 509: JFR CPU-Time Profiling [v50]

Patricio Chilano Mateo pchilanomate at openjdk.org
Wed Jun 4 14:15:53 UTC 2025


On Wed, 4 Jun 2025 12:56:22 GMT, Johannes Bechberger <jbechberger at openjdk.org> wrote:

>> This is the code for the [JEP 509: CPU Time based profiling for JFR](https://openjdk.org/jeps/509).
>> 
>> Currently tested using [this test suite](https://github.com/parttimenerd/basic-profiler-tests). This runs profiles the [Renaissance](https://renaissance.dev/) benchmark with
>> - ... different heap sizes
>> - ... different GCs
>> - ... different samplers (the standard JFR and the new CPU Time Sampler and both)
>> - ... different JFR recording durations
>> - ... different chunk-sizes
>
> Johannes Bechberger has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Fix build

I took a look at this. I only found one issue that needs fixing before integration and then a few comments. Thanks.

src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp line 59:

> 57:   Thread* raw_thread = Thread::current_or_null_safe();
> 58:   if (raw_thread == nullptr) {
> 59:     // probably while shutting down

Do you remember which test fail because of this? It would be interesting to know, since I don’t see how it could be null here.

src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp line 330:

> 328: void JfrCPUSamplerThread::stackwalk_threads_in_native() {
> 329:   ResourceMark rm;
> 330:   MutexLocker tlock(Threads_lock);

What exactly are we guarding against by holding the `Threads_lock`? Seems `ThreadsListHandle` should be enough.

src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp line 430:

> 428: void JfrCPUTimeThreadSampling::create_sampler(double rate, bool auto_adapt) {
> 429:   assert(_sampler == nullptr, "invariant");
> 430:   _sampler = new JfrCPUSamplerThread(rate, auto_adapt);

If we start a recording on an already running process we have a race here where a new thread can create and set its timer before we call init_timers() where the signal handler is installed. In that case the program will terminate with message “Profiling timer expired" (default action for SIGPROF). It can be easily reproduced by adding a delay here and starting a recording on a simple test that just creates new threads. We need to add some extra check in create_timer_for_thread() or install the signal handler earlier.

src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp line 584:

> 582:   sev.sigev_notify = SIGEV_THREAD_ID;
> 583:   sev.sigev_signo = SIG;
> 584:   sev.sigev_value.sival_ptr = &t;

Why setting the address of `t` which is a local variable here?

-------------

PR Review: https://git.openjdk.org/jdk/pull/25302#pullrequestreview-2896813404
PR Review Comment: https://git.openjdk.org/jdk/pull/25302#discussion_r2126661443
PR Review Comment: https://git.openjdk.org/jdk/pull/25302#discussion_r2126670024
PR Review Comment: https://git.openjdk.org/jdk/pull/25302#discussion_r2126651264
PR Review Comment: https://git.openjdk.org/jdk/pull/25302#discussion_r2126666505


More information about the serviceability-dev mailing list