RFR: 8306334: Handle preemption of old cycle between filling and bootstrap phases [v2]

William Kemper wkemper at openjdk.org
Thu Apr 20 22:54:31 UTC 2023


On Thu, 20 Apr 2023 20:15:05 GMT, Y. Srinivas Ramakrishna <ysr at openjdk.org> wrote:

>> William Kemper has updated the pull request incrementally with one additional commit since the last revision:
>> 
>>   Re-enable TestArrayCopyStress
>
> src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp line 536:
> 
>> 534:     }
>> 535:     case ShenandoahOldGeneration::BOOTSTRAPPING: {
>> 536:       // It is possible for a young generation request to preempt this nascent old
> 
> This comment is helpful. 
> 
> There is an ASCII art of an intended state transition diagram for the old generation states in `shenandoahOldGeneration.cpp`. It would be a good idea to update that diagram with possible premptible states and also the state transitions that might occur as a result of cancellations that might occur outside of the pre-emptible states. (I assume that cancellations can only interrupt and reset us out of pre-emptible states, not from any other, i.e. non-pre-emptible state.)
> 
> Similarly, at lines 444-458 above is another, presumably for Controller thread states. Does that figure get new transitions as a result of this change?
> 
> I see this documentation comment further below at lines 607-610:
> 
> 
>   // We can only tolerate being cancelled during concurrent marking or during preparation for mixed
>   // evacuation. This flag here (passed by reference) is used to control precisely where the regulator
>   // is allowed to cancel a GC.
>   ShenandoahOldGC gc(generation, _allow_old_preemption);
> 
> 
> The comment says "cancel", but uses a flag `_allow_old_preemption`.  When I first saw this I was a bit confused, until I realized that cancellations will be see only in the pre-emptible states, and ignored in all other states until we have completed the work for that state and transition out of it, or if we are otherwise in a pre-emptible state.
> 
> Your description below hints at these interactions, I think, but it would be great if this is documented clearly somewhere (may be it is, somewhere in either old generation or in the control thread). It would also be nice to explain, in case this makes sense, if there any possible correspondences between states of the control thread and those of the old generation state.

Yes, [the diagram ](https://github.com/openjdk/shenandoah/blob/master/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp#L363) depicts preemption as the "YOUNG GC" boxes associated with "FILLING" and "MARKING". The comment on the diagram explains that an allocation failure may interrupt _any_ state and that they all lead to degenerated/full GCs. These were omitted from the diagram to reduce clutter.

The new state in the control thread isn't strictly necessary for this fix, but it prevents the regulator from trying to start a concurrent young cycle during the bootstrap cycle (which is a concurrent young cycle).

The implementation of all this could certainly stand some readability improvement. Essentially, there are _two_ reasons an old cycle may be cancelled:
1. Allocation failure. This can happen at any phase of the old cycle and always results in at least a degenerated cycle.
2. Preemption. If the regulator thread detects a need to run a young generation it may "preempt" the old cycle and run a young cycle. This does _not_ result in a degenerated cycle, but it pauses the old cycle. This requires some coordination with the old collection and so is only supported during the filling and marking phases.

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

PR Review Comment: https://git.openjdk.org/shenandoah/pull/262#discussion_r1173156914


More information about the shenandoah-dev mailing list