RFR: 8368015: Shenandoah: fix error in computation of average allocation rate [v2]
William Kemper
wkemper at openjdk.org
Wed Sep 24 21:56:47 UTC 2025
On Tue, 23 Sep 2025 15:36:42 GMT, Kelvin Nilsen <kdnilsen at openjdk.org> wrote:
>> src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp line 364:
>>
>>> 362:
>>> 363: double ShenandoahAllocationRate::force_sample(size_t allocated, size_t &unaccounted_bytes_allocated) {
>>> 364: const double MinSampleTime = 0.002; // Do not sample if time since last update is less than 2 ms
>>
>> Would it make sense to "carry over" the `unaccounted_bytes_allocated` if, at the time of reset, the last sample was taken less than `ShenandoahAllocationRate::_interval_sec` (instead of `MinSampleTime`)? I believe this would result in more samples being carried over.
>
> I've done experiments with a variety of different values for MinSampleTime (e.g. 50 ms, 25ms, 2 ms). I find that any value
> greater than 1 ms works pretty well in the sense that the measured rate is pretty consistent with the average rate as computed
> by the preexisting mechanisms.
>
> The biggest problem I observed was when we tried to measure rate over an interval of a few microseconds, and these intervals
> sometimes had zero allocations.
>
> We could make the change you suggest, but that would actually result in fewer samples rather than more. It would also make
> the value of bytes_allocated_since_gc_start() less precise in that this quantity would carry up to 100 ms of allocations that
> actually occurred before the start of the current GC.
>
> Here's an ASCII art attempt to illustrate how it works in the current implementation.
>
> Here is a timeline with a tick mark to illustrate the desired sample time, every 100 ms:
>
>
> .1s .2s .3s .4s. .5s .6s .7s .8s. .9s 1s 1.1s 1.2s
> |---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|---
> ^ ^
> Existing | |
> Samples: A B C D E
> | |
> Proposed | |
> Samples: A | B C D
> | |
> | |
> Trigger GC at 0.14s Finish GC at 1.03s
>
> In either approach, we sample at 0.1s and this sample contributes to the average allocation rate that causes us to trigger at
> time 0.14s. In the current implementation, at time 0.14s, we take a new sample representing the most current allocation rate
> as computed over the span between 0.1s and 0.14s. As implemented, if this time delta (0.14s minus 0.10s =0...
With the change in the PR, I was thinking of "skipped" samples as being "carried over" to the next cycle (per `unaccounted_bytes_allocated = allocated - _last_sample_value;`).
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/27398#discussion_r2377167640
More information about the hotspot-gc-dev
mailing list