RFR: 8209189: Make CompiledMethod::do_unloading more concurrent

coleen.phillimore at oracle.com coleen.phillimore at oracle.com
Fri Oct 26 17:31:17 UTC 2018



On 10/26/18 12:25 PM, Erik Österlund wrote:
> Hi Coleen,
>
> Thank you for reviewing this.
>
> On 2018-10-26 17:58, coleen.phillimore at oracle.com wrote:
>>
>> I think this looks really good. I appreciate the cleanup in this 
>> complexity.  It's nice that nmethod/CompiledMethod as non-gc 
>> structure with oops, there's simply an oops_do() vs. all these 
>> do_unloading_scopes() functions.   It reduces the special handling. I 
>> spent a lot of time trying to figure out how this "postponed" 
>> cleaning works.  This make a lot of sense.
>
> I'm glad you like it! I also think the new model is more intuitive.
>
>> http://cr.openjdk.java.net/~eosterlund/8209189/webrev.00/src/hotspot/share/code/compiledMethod.cpp.udiff.html 
>>
>>
>> 508 bool result = IsUnloadingBehaviour::current()->is_unloading(this);
>>
>>
>> This line is essentially the special sauce to this change.  What is 
>> hard to see immediately is that this doesn't just test the flag but 
>> will do an oops_do in order to set the flag.  Can you add a comment 
>> to this effect here?
>
> Done.
>
> New incremental (including Vladimir's suggestion to remove now dead 
> code):
> http://cr.openjdk.java.net/~eosterlund/8209189/webrev.00_01/
>
> Full:
> http://cr.openjdk.java.net/~eosterlund/8209189/webrev.01/
>
>
>> Also, two GC threads could be visiting the same nmethods at the same 
>> time with this cleaning.  This is ok though as long as they set the 
>> is_unloading state correctly.
>
> Exactly. The value will monotonically change, possibly by multiple 
> threads (but in practice mostly by one thread) to the same value. If 
> two threads race, they will race for writing the same value, which is 
> harmless.
>
>> 500 state._value = RawAccess<MO_RELAXED>::load(&_is_unloading_state);
>>
>>
>> Are these required or are you being pedantic?  Shouldn't it be 
>> ordered for multiple GC threads?
>
> No, ordering is irrelevant here. What is relevant is that the access 
> is atomic; that's why I use MO_RELAXED, which gives me those guarantees.
>
> As mentioned previously, two threads may race, and that is harmless; 
> they will race for writing the same cached value. There are no 
> ordering constraints.

So is RawAccess<MO_RELAXED> the same as:

state._value = _is_unloading_state; ?
>
>> http://cr.openjdk.java.net/~eosterlund/8209189/webrev.00/src/hotspot/share/gc/shared/gcBehaviours.new.hpp.html 
>>
>>
>> Despite the fact that you spelled "behavoirs" wrong, I think I'm 
>> warming up to this use of the concept here.  I'm having trouble 
>> thinking of a more specific word for it.
>
> Sorry Coleen, but "behaviours" is the correct English spelling. 
> American English is not English. Shots fired...

:)
>
>> I have to confess to not reviewing the epoch handling very well.
>>
>> Since there's a big alignment gap in CompiledMethod, why not just 
>> have two fields and skip this odd union?  One bool for is_unloading 
>> and one short for unloading_cycle?  Reading the word _inflated is 
>> strange here.
>
> I use the union to make sure that both values are accessed as a pair 
> atomically. The union allows me to represent the same data either as a 
> single value that can be accessed atomically, and then interpret it as 
> an "inflated" view where it comprises a tuple representing both an 
> epoch and result value. The single value is used to ensure atomicity, 
> and the inflated view is used for interpreting what the state represents.

Can you put some sort of comment above the IsUnloading{Union,Struct} to 
that effect?  I don't need to see it.  I'm sure your English will be good :)

Coleen

>
> Thanks,
> /Erik
>
>> Thanks,
>> Coleen
>>
>> On 10/19/18 10:22 AM, Erik Österlund wrote:
>>> Hi,
>>>
>>> Today the nmethods are unloaded either serially or in parallel due 
>>> to GC (and e.g. class unloading). With ZGC concurrent class 
>>> unloading, a concurrent fashion is required. Rather than inventing 
>>> yet a third way of unloading nmethods due to class unloading, it 
>>> would be ideal if there could be one unified way of doing it that 
>>> makes everyone happy.
>>>
>>> To solve this problem in a more general way, a new member function 
>>> on CompiledMethod is added: is_unloading(). It returns whether a 
>>> CompiledMethod has broken oops. In order to not have to iterate over 
>>> all the oops every time this question is asked, it caches the 
>>> result, so it needs to be computed only once per "epoch". Every time 
>>> a CodeCache unloading is triggered by the GC, a new epoch is 
>>> started, which forces re-computation of whether the CompiledMethod 
>>> is_unloading() the first time it is called.
>>>
>>> So by having is_unloading() be lazily evaluated, it is now possible 
>>> to build a do_unloading() method on nmethod that simply makes the 
>>> nmethod unloaded if it is_unloading(), and otherwise cleans the 
>>> various caches. Cleaning e.g. the inline caches of said nmethod, 
>>> uses the same is_unloading() method on its targets to figure out if 
>>> the IC cache should be cleaned or not. Again, the epoched caching 
>>> mechanism makes sure we don't recompute this value.
>>>
>>> The new do_unloading() method may be called in both serial, parallel 
>>> and concurrent contexts. So I removed the parallel variation of this 
>>> that we had before, that unnecessarily postponed the unloading due 
>>> to not having computed whether the nmethod should be unloaded or 
>>> not. Since that is now computed on-demand lazily, there is no longer 
>>> a need for postponing this, nor to have two phases for parallel 
>>> nmethod unloading.
>>>
>>> While there is more work involved in making concurrent nmethod 
>>> unloading work, this is a good cleanup towards that goal.
>>>
>>> Bug ID:
>>> https://bugs.openjdk.java.net/browse/JDK-8209189
>>>
>>> Webrev:
>>> cr.openjdk.java.net/~eosterlund/8209189/webrev.00/
>>>
>>> Thanks,
>>> /Erik
>>



More information about the hotspot-dev mailing list