Skip to content

Implement the JFR ObjectAllocationSample event - step2 - #24659

Open
LinHu2016 wants to merge 2 commits into
eclipse-openj9:masterfrom
LinHu2016:jfrAllocationSampling_recalibrateU
Open

Implement the JFR ObjectAllocationSample event - step2#24659
LinHu2016 wants to merge 2 commits into
eclipse-openj9:masterfrom
LinHu2016:jfrAllocationSampling_recalibrateU

Conversation

@LinHu2016

Copy link
Copy Markdown
Contributor

Update the recalibration of the JFR ObjectAllocationSample interval.

The original allocation sample byte interval recalibration was performed
in jfrSamplingThreadProc(), which runs every second. It collects
totalBytes allocated since the end of the previous GC cycle and divides
it by the elapsed time since that GC to calculate the allocation rate.

Collecting totalBytes since the previous GC cycle requires acquiring
exclusive VM access, which may introduce performance concerns.

The recalibration is now performed in
jfrRecalibrateObjectAllocationSampleInterval(), which is called at the
start of a GC cycle. At this point, flushCachesForGC() has already
merged all per-thread allocation statistics into
extensions->allocationStats.

The allocation rate is calculated using the allocation statistics
collected during the interval since the previous GC cycle ended. Based
on this rate, the per-thread sampling interval is adjusted to keep the
observed event rate close to the configured throttle rate.

To avoid frequent small adjustments, a new sampling interval is applied
only when it differs from the current interval by more than 5%.
#depends on #24609
Signed-off-by: lhu linhu@ca.ibm.com

@LinHu2016 LinHu2016 changed the title Jfr allocation sampling recalibrate u Implement the JFR ObjectAllocationSample event - step2 Aug 28, 2026
@LinHu2016
LinHu2016 force-pushed the jfrAllocationSampling_recalibrateU branch from d170227 to 906d77c Compare August 28, 2026 15:44
Base on JFR event specification (from [SAP JFR Events
17](https://sap.github.io/jfrevents/17.html#objectallocationsample)):

- Introduce a new GC hook J9HOOK_MM_OBJECT_ALLOCATION_SAMPLING_INTERNAL
that is functionally identical to J9HOOK_MM_OBJECT_ALLOCATION_SAMPLING
but is designated internal-only (JVM use only, no Java code runs in
callbacks). This prevents the hook's registration from disabling JIT OSR
safe-point optimization in vmhook.c.

- Define the event structure J9JFRObjectAllocationSample in
j9nonbuilder.h and J9JFR_EVENT_TYPE_OBJECT_ALLOCATION_SAMPLE id in
j9consts.h

- Register a JFR-internal callback jfrObjectAllocationSample() on
J9HOOK_MM_OBJECT_ALLOCATION_SAMPLING_INTERNAL in
startJFRRecording(), implement the callback to write a
J9JFRObjectAllocationSample event with
a stack trace into the per-thread buffer, and unregister it in
stopJFRRecording().

- new jfrObjectSamplingBytesGranularity in GCExtensionBase
  new _jfrTraceAllocationBytes in EnvironmentBase for tracking and
triggering J9JFRObjectAllocationSample event.

- JFR specifies `ObjectAllocationSample` throttling in events-per-second
(default: 150/s, profiling: 300/s). The GC layer works in bytes. A
conversion is needed: from the JVM's current heap allocation rate
(bytes/sec), derive a byte-granularity interval such that approximately
`N` events/second are emitted. JVM startup uses a reasonable default
byte interval 512KB. new objectAllocationSampleThrottleRate (throttle
value (events/s)) in vm->jfrState.

- New function j9gc_set_jfr_allocation_sampling_interval() to let JFR
enable/disable/reconfigure the threshold.

- Add a periodic recalibration step in jfrSamplingThreadProc()'s
1-second tick block, Read total bytes allocated since last GC, Compute
new byte interval: newInterval = allocatedBytes / (throttleRate *
elapsedSinceLastGC).

- handle the case JVMTI sampling is also active, arm the TLH top at the
nearer of the two next-trigger points so that neither sampler fires
late.

Signed-off-by: lhu <linhu@ca.ibm.com>
@LinHu2016
LinHu2016 force-pushed the jfrAllocationSampling_recalibrateU branch from 906d77c to a783dde Compare August 28, 2026 15:48
The original allocation sample byte interval recalibration was performed
in jfrSamplingThreadProc(), which runs every second. It collects
totalBytes allocated since the end of the previous GC cycle and divides
it by the elapsed time since that GC to calculate the allocation rate.

Collecting totalBytes since the previous GC cycle requires acquiring
exclusive VM access, which may introduce performance concerns.

The recalibration is now performed in
jfrRecalibrateObjectAllocationSampleInterval(), which is called at the
start of a GC cycle. At this point, flushCachesForGC() has already
merged all per-thread allocation statistics into
extensions->allocationStats.

The allocation rate is calculated using the allocation statistics
collected during the interval since the previous GC cycle ended. Based
on this rate, the per-thread sampling interval is adjusted to keep the
observed event rate close to the configured throttle rate.

To avoid frequent small adjustments, a new sampling interval is applied
only when it differs from the current interval by more than 5%.

Signed-off-by: lhu <linhu@ca.ibm.com>
@LinHu2016
LinHu2016 force-pushed the jfrAllocationSampling_recalibrateU branch from a783dde to 431a7c3 Compare August 28, 2026 17:43
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.

1 participant