RFR: 8242054: Shenandoah: New incremental-update mode

Aleksey Shipilev shade at redhat.com
Fri Apr 3 08:04:52 UTC 2020


On 4/2/20 9:23 PM, Roman Kennke wrote:
> Some of our users like some properties of the marking/traversal
> behaviour of the Traversal mode, but would also like the benefits and
> ergonomics of the normal mode. It turns out that it is relatively easy
> to transplant the barrier-model of Traversal mode into the regular mode.
> This is essentially a variant of the well-known incremental-update model
> of concurrent marking.
> 
> We already have all the barrier-foo that we need from the Traversal
> mode. The following modifications are required to make it work with
> regular mode:
> 
> - Arraycopy-barriers must mark through src instead of dst (we're
> interested in the new-values not in the previous-valuses). They must
> also trigger when dest is uninitialized (esp in the ASM prologue calls)
> - Related to this, clone-barriers now also need to mark through the
> src-object. (SATB doesn't need this because destination is by definition
> uninitialized).
> - Both clone and arraycopy-barriers can skip marking the src obj/array
> if the src is allocated-after-mark-start: in this case it's guaranteed
> by the barrier model than any reference in them must already have gone
> through a barrier.
> - C2 code sees some adjustments to allow marking-active checks when
> expanding ShenandoahStoreValEnqueueBarrierNode. It previously only
> checked HAS_FORWARDED to account for Traversal-active. It also adds
> MARKING to the state-check for the clone-barrier.
> - I removed the flags-checks from aggressive/compact/static heuristics.
> This is now checked in shenandoahNormalMode.cpp (and is consistent with
> adaptive)
> - I introduced a new mode called ShenandoahIUMode, mapped to
> ShenandoahGCMode=iu, which sets the flags for this new mode.
> - I added no testing yet. The plan is to change traversal tests to iu
> tests if/when Traversal gets eliminated.
> - I did, however, test everything in shenandoah/jdk by changing the
> default mode to iu.
> 
> Bug:
> https://bugs.openjdk.java.net/browse/JDK-8242054
> Webrev:
> http://cr.openjdk.java.net/~rkennke/JDK-8242054/webrev.00/

*) I would prefer for flag checks to be first. It makes it clearer to me that path is only taken in
some configurations. Example, this:
  if (dest_uninitialized && ShenandoahSATBBarrier) ...
 ...becomes this:
  if (ShenandoahSATBBarrier && dest_uninitialized) ...

*) These blocks should not be removed. At very least we want to make the check for SATB/StoreVal
barrier conditional on the mode. But other barrier checks should definitely stay.

  47   // Final configuration checks
  48   SHENANDOAH_CHECK_FLAG_SET(ShenandoahLoadRefBarrier);
  49   SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier);
  50   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier);
  51   SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier);

*) This is some local madness:

  84   int gc_state = _heap->gc_state();
  85   if ((gc_state & ShenandoahHeap::MARKING) != 0 &&
  86       ShenandoahStoreValEnqueueBarrier &&
  87       !_heap->marking_context()->allocated_after_mark_start(obj)) {
  88     ShenandoahUpdateRefsForOopClosure<false, false, true> cl;
  89     obj->oop_iterate(&cl);
  90   } else if ((gc_state & ShenandoahHeap::HAS_FORWARDED) != 0) {
  91     if (skip_bulk_update(cast_from_oop<HeapWord *>(obj))) return;

Do we really need to read the gc_state and then mask it, instead of just checking
heap->is_concurrent_mark_in_progress()? Why check for has_forwarded on the else branch? asserting
has_forwarded_objects is futile on that branch too.

It looks to me the whole thing is:

  if (ShenandoahStoreValEnqueueBarrier && _heap->is_concurrent_marking_in_progress() &&
       !_heap->marking_context()->allocated_after_mark_start(obj)) {
     ShenandoahUpdateRefsForOopClosure<false, false, true> cl;
     obj->oop_iterate(&cl);
     return;
   }

   assert(_heap->has_forwarded_objects(), "only when heap is unstable");
   if (skip_bulk_update(cast_from_oop<HeapWord *>(obj))) return;

   if (_heap->is_evacuation_in_progress()) {
     ...
   } else if (_heap->is_concurrent_traversal_in_progress()) {
     ...
   } else {
     ...
   }

*) I don't think the rewrite in ShFinalMarkTask is equivalent. See, on the path here:

 262 ShenandoahSATBAndRemarkCodeRootsThreadsClosure tc(&cl,
 263                                     ShenandoahStoreValEnqueueBarrier ? &mark_cl : NULL,
 264                                     &blobsCl);

 ...we used to pass NULL as blobsCL when do_nmethods is false.

*) Also, why ResourceMark here?

 199         if (_cl != NULL) {
 200           ResourceMark rm;
 201           thread->oops_do(_cl, _code_cl);

-- 
Thanks,
-Aleksey




More information about the hotspot-gc-dev mailing list