RFR: 8056240: Investigate increased GC remark time after class unloading changes in CRM Fuse
Stefan Karlsson
stefan.karlsson at oracle.com
Wed Oct 15 12:08:33 UTC 2014
Hi Coleen,
On 2014-10-14 23:00, Coleen Phillimore wrote:
>
> Stefan, I've reviewed the new version of the code (02) and have some
> comments. Thank you for all the work resolving my concerns.
>
> The comments are inline.
>
> On 10/13/14, 5:15 AM, Stefan Karlsson wrote:
>> Hi Coleen,
>>
>> On 2014-10-10 22:54, Coleen Phillimore wrote:
>>>
>>> Hi Stefan,
>>>
>>> Thank you for your patience. Some review comments:
>>>
>>> http://cr.openjdk.java.net/~stefank/8056240/webrev.00/src/share/vm/classfile/metadataOnStackMark.hpp.udiff.html
>>>
>>>
> ...
>> I guess you are opposing code in metadataOnStackMark, rather than
>> saying that this is complicated code?
>
> Well, both, but yes. I want to think about MetadataOnStackMark in
> this file. Thank you for adding chunkedList. It seems like it could
> be generally useful.
>
>>
>>> Is it trying to add as chunked list?
>>
>> Yes.
>>
>>> Can we add a utility for this instead of tying it to the
>>> MetadataOnStackMark functionality?
>>
>> We could. That would make it possible to reuse the code, but the code
>> would be a tiny bit more non-obvious. I can try to implement this as
>> a generic template data structure.
>>
>>>
>>> In this file, what is _doit and why? This looks really strange.
>>> Can you add a comment why sometimes doit is false and sometimes doit
>>> is true? Is there a way to encapsulate this in a function as it's
>>> supposed to be a scoped object.
>>
>>
> ...
>> Sounds good to me. Should has_metadata_to_deallocate always be true
>> in the current code? I don't want to add code to check if Metadata
>> has been allocated. I think that should be handled as a separate RFE.
>
> Thank you for adding this code this way. I think conditional on
> clean_alive is fine.
>>
>>>
>>> http://cr.openjdk.java.net/~stefank/8056240/webrev.00/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp.udiff.html
>>>
>>>
>>> + if (JvmtiExport::has_redefined_a_class()) {
>>> + InstanceKlass::purge_previous_versions(ik);
>>> + }
>>>
>>>
>>> purge previous versions requires the on_stack bits to be set. Is
>>> this true here?
>>
>> Yes, that's what the MetadataOnStackMark in
>> ConcurrentMark::weakRefsWorkParallelPart (concurrentMark.cpp) is used
>> for.
>>
>>> It seems very far away from the other code to me to be able to tell.
>>
>> Yes, I agree. It's non-obvious, but I couldn't figure out a good way
>> to solve it. In similar situations, I've passed down the instance of
>> the class, in this case MetadataOnStackMark, to the code that uses
>> it. Just to ensure that we have an instance setup when calling the
>> code. We've discussed that approach a couple of years ago, but you
>> didn't like it then. We have similar problems with ResourceMarks and
>> HandleMarks, but code using Handles or Resource allocated memory
>> asserts that those are in place. Maybe we should do the same for
>> on_stack?
>
> Yes, I remember some other code from the past. I don't think it's
> worth having a metadata-on-stack-mark assert. It's just far away.
> We'll have to see how hard this is to maintain going forward.
>>
>>> Why can't this go in the same place as the free_deallocate_lists?
>>
>> Because purge_previous_versions can be called in parallel, whereas
>> free_deallocate_lists needs to be called when we are sure that all
>> calls to purge_previous_versions have been called. So,
>> free_deallocate_lists was added as a separate phase after the
>> parallel unloading code. I can add comments about this.
>
> If you did purge_previous_versions and free_deallocate lists together
> in clean_metaspaces() would it really hurt performance?
I can redo that investigation after this change has been pushed.
>
>>
>>>
>>> http://cr.openjdk.java.net/~stefank/8056240/webrev.00/src/share/vm/code/nmethod.cpp.udiff.html
>>>
>>>
>>> I really don't like that the on-stack bit marks are done at the same
>>> time as clean_ic_if_metadata_is_dead. They are for different
>>> purposes.
>>
>> Yes, I agree. It's an abstraction violation, but I've done so that we
>> don't have to execute the expensive reloc iter lookup code more than
>> once. Maybe I should use a callback instead, so that we don't
>> hard-wire the MetadataOnStackMark code into the
>> clean_ic_if_metadata_is_dead function?
>>
>>> Also, this seems to mark metadata for methods that are unloaded as
>>> well as ones that survive unloading. I guess this wouldn't prevent
>>> methods from being unloaded but seems unnecessary callbacks to
>>> mark_on_stack. Maybe I'm not reading this right though.
>>
>> I think you are right. On the other hand, previously we visited all
>> Metadata in the entire code cache, and we didn't do this separation.
>> I'd like this to be changes as a follow-up fix, so that I don't
>> introduce a regression here.
>
> I think since the abstraction has been broken that metadata_do()
> should be rewritten so that it shares the code that duplicates the
> walks in
> nmethod::mark_metadata_on_stack_at
> nmethod::mark_metadata_on_stack_non_relocs()
You mean something like this?:
http://cr.openjdk.java.net/~stefank/8056240/webrev.02.do_metadata.delta
http://cr.openjdk.java.net/~stefank/8056240/webrev.02.do_metadata
>
>
> Rather than sharing code with CheckClass, which we didn't like because
> it had to have a static _is_alive.
We used the static is_alive because nmethod::method_do takes a function
pointer. We wouldn't need to do that if nmethod::method_do took a
MetadataClosure, that could hold the _is_alive instance.
>
> Then it would be easier to check that only old methods are marked here.
>
> I can file this bug and fix it, since I have multiple bugs in this
> right now to fix.
OK.
>>
>>> I thought you couldn't do the unloading walk with the
>>> mark-on-stack walk?
>>
>> There are two separate phases of the unloading walk and a barrier in
>> between those phases. The mark-on-stack walk happens in the first
>> phase, and the purge_previous_version happens in the second phase.
>> The free_deallocate_lists is called in a serial phase after that.
>>
>>> Also, we actually only have to mark OLD methods in the code cache
>>> which would greatly reduce the callbacks. I could make this in a
>>> separate change as I have this change in a private repository.
>>
>> Sounds good. You mean OLD as in a previous version plus the Methods
>> that were put on the deallocate_free_list?
>
> No, OLD is only methods that are redefined. You can get other methods
> on the deallocate_list from relocating jsr/ret from ancient
> classfiles. Also there are constant pools on the deallocate_list from
> lambdas. Perhaps it would be good to separate these things.
OK.
>>
>>>
>>> I think you should have a compiler reviewer comment on the nmethod
>>> code though.
>>>
>>> http://cr.openjdk.java.net/~stefank/8056240/webrev.00/src/share/vm/utilities/accessFlags.cpp.udiff.html
>>>
>>>
>>> I don't know why this needs to be different than the atomic_set_bits
>>> function.
>>
>> Previously, we didn't care if the Metadata had already been marked.
>> They were just blindly recorded by MetadataOnStackMark. That caused
>> the number of stored elements to be orders of magnitude larger than
>> they had to be. To fix this, I only record Metadata if they have not
>> already been added. I need this new function to tell if the current
>> call, by the current thread, was setting the mark bit. The thread
>> that succeeds with this marking, will be the one that records the
>> Metadata in the array (or now, chunked list).
>>
>> Bertrand had comments about the usage of atomic_try_set_bits, so I
>> have a version that uses a slightly altered copy of
>> AccessFlags::atomic_set_bits.
>>
>>> I should have made on_stack be a flag in Method* rather than in
>>> access flags.
>>
>> Sounds like a good follow-up fix.
>
> Yes, I'll file a bug for that also so I can clean this up.
>
> The only comment I had was to do purge_previous_versions with
> free_deallocate_list. But if it's shown to have bad performance, I'm
> fine with the way it is.
OK. I'll leave it as it is, and then I can investigate this more in a
separate cleanup CR.
>
> I think purge_previous_versions does work that could be done earlier
> in class redefinition, which could be a third RFE from this. If we
> could make purge_previous_versions do little or nothing, these could
> go together, right?
Sounds reasonable.
>
> Thanks for the code changes and comments.
Thanks for reviewing.
StefanK
>
> Coleen
>
>
>>
>>>
>>> There's a lot here. I'm glad it helps performance and making the
>>> code cache walk parallel is a really good change.
>>
>> Thanks Coleen.
>>
>> StefanK
>>
>>>
>>> Thanks,
>>> Coleen
>>>
>>>
>>> On 10/2/14, 6:53 AM, Stefan Karlsson wrote:
>>>> Hi all,
>>>>
>>>> (The following patch changes HotSpot code in areas concerning GC,
>>>> RT, and Compiler. So, it would be good to get reviews from all
>>>> three teams.)
>>>>
>>>> Please, review this patch to optimize and parallelize the CodeCache
>>>> part of MetadaOnStackMark.
>>>>
>>>> G1 performance measurements showed longer than expected remark
>>>> times on an application using a lot of nmethods and Metadata. The
>>>> cause for this performance regression was the call to
>>>> CodeCache::alive_nmethods_do(nmethod::mark_on_stack); in
>>>> MetadataOnStackMark. This code path is only taken when class
>>>> redefinition is used. Class redefinition is typically used in
>>>> monitoring and diagnostic frameworks.
>>>>
>>>> With this patch we now:
>>>> 1) Filter out duplicate Metadata* entries instead of storing a
>>>> Metadata* per visited metadata reference.
>>>> 2) Collect the set of Metadata* entries in parallel. The code
>>>> piggy-backs on the parallel CodeCache cleaning task.
>>>>
>>>> http://cr.openjdk.java.net/~stefank/8056240/webrev.00/
>>>> https://bugs.openjdk.java.net/browse/JDK-8056240
>>>>
>>>> Functional testing:
>>>> JPRT, Kitchensink, parallel_class_unloading, unit tests
>>>>
>>>> Performance testing:
>>>> CRM Fuse - where the regression was found
>>>>
>>>> The patch changes HotSpot code in areas concerning GC, RT,
>>>> Compiler, and Serviceability. It would be good to get some reviews
>>>> from the other teams, and not only from the GC team.
>>>>
>>>> thanks,
>>>> StefanK
>>>
>>
>
More information about the hotspot-dev
mailing list