RFR: 8272138: ZGC: Adopt release ordering for self-healing

Xiaowei Lu github.com+39413832+weixlu at openjdk.java.net
Tue Aug 10 14:43:33 UTC 2021


On Tue, 10 Aug 2021 09:29:04 GMT, Erik Österlund <eosterlund at openjdk.org> wrote:

>>> @fisk Thanks a lot for your detailed explanation. But I’m quite confused about the release in the forwarding table, why is it able to act as a release for both accesses? In my view, since the release is “bonded” to forwarding table, it only ensures that copy happens before installing forwardee, why does it have something to do with self healing? From your explanation, I guess release is not “bonded” to forwarding table. Instead, it maybe serves as membar to block all the CASes afterwards. Thanks again for your patient explanation.
>> 
>> What I wrote kind of assumes that we have an explicit OrderAccess::release(); relaxed_cas(); in the forwarding table. Looks like we currently have a bounded releasing cas instead. The unbounded release is guaranteed to provide release semantics for *any* subsequent store operation. However, a bounded Store-Release, (i.e. stlr) instruction only needs to provide the release semantics to the bound store, as you say. So I suppose what I propose is to use release(); relaxed_cas(); in the forwarding table, and then also relaxed_cas(); in the self healing. Letting the release be done in only one place, and only when actual copying happens. The vast majority of self heals I have found are purely remapping the pointer lazily, which can then dodge any need for release when self healing. Hope this makes sense.
>
>> @fisk Hi, Eric. We are wondering if one thread loading a healed pointer can observe the corresponding copy has not finished yet. Assuming relaxed ordering for `cas_self_heal`, both Thread A and Thread B are loading the same reference.
>> 
>> **Thread A**: `load obj.fld; // will relocate the object referenced by obj.fld`
>> thread A will do the following:
>> 
>> ```
>> 1    copy();
>> 2    cas_forwarding_table(); // release
>> 3    cas_self_heal(); // relaxed
>> ```
>> 
>> **Thread B**: `load obj.fld; // load the same reference`
>> thread B may obverses the following reordering of **thread A**:
>> 
>> ```
>> 3    cas_self_heal(); // relaxed
>> 1    copy();
>> 2    cas_forwarding_table(); // release
>> ```
>> 
>> To our knowledge, release ordering in _line 2_ does not prevent _line 3_ to be reordering before _line 1_, which indicates the release in the forwarding table is not enough. Perhaps we need to add acquire ordering to _line 2_ or add release ordering to _line 3_.
>> 
>> In another way, as @weixlu said,
>> 
>> > Instead, it maybe serves as membar to block all the CASes afterwards.
>> 
>> relaxed ordering in _line 2_ along with release ordering in _line 3_ can indeed ensure thread B always observes the object copy.
>> 
>> Looking forward to your advice.
> 
> Yeah so I was kind of assuming the forwarding table installation would be an unbound release(); relaxed_cas();
> That way, the release serves a dual purpose: releasing for the table and releasing for the self heal. That way the vast majority of self heals (that only do remapping), won't need to release.

> > @fisk Thanks a lot for your detailed explanation. But I’m quite confused about the release in the forwarding table, why is it able to act as a release for both accesses? In my view, since the release is “bonded” to forwarding table, it only ensures that copy happens before installing forwardee, why does it have something to do with self healing? From your explanation, I guess release is not “bonded” to forwarding table. Instead, it maybe serves as membar to block all the CASes afterwards. Thanks again for your patient explanation.
> 
> What I wrote kind of assumes that we have an explicit OrderAccess::release(); relaxed_cas(); in the forwarding table. Looks like we currently have a bounded releasing cas instead. The unbounded release is guaranteed to provide release semantics for _any_ subsequent store operation. However, a bounded Store-Release, (i.e. stlr) instruction only needs to provide the release semantics to the bound store, as you say. So I suppose what I propose is to use release(); relaxed_cas(); in the forwarding table, and then also relaxed_cas(); in the self healing. Letting the release be done in only one place, and only when actual copying happens. The vast majority of self heals I have found are purely remapping the pointer lazily, which can then dodge any need for release when self healing. Hope this makes sense.

Yes, it's better to use OrderAccess::release() with two relaxed_cas in forwarding table and self heal. I have made some changes and will run benchmarks afterwards. I believe your advice helps improve performace.

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

PR: https://git.openjdk.java.net/jdk/pull/5046



More information about the hotspot-gc-dev mailing list