RFR: 8153745: Avoid spawning G1ParPreserveCMReferentsTask when there is no work to be done

Jon Masamitsu jon.masamitsu at oracle.com
Mon Apr 11 17:58:53 UTC 2016

On 04/11/2016 08:36 AM, Stefan Johansson wrote:
> Thanks for looking at this Thomas,
> On 2016-04-08 13:45, Thomas Schatzl wrote:
>> Hi,
>> On Fri, 2016-04-08 at 13:10 +0200, Stefan Johansson wrote:
>>> Hi,
>>> Please review this enhancement to avoid spawning tasks when there is
>>> no
>>> work to do:
>>> https://bugs.openjdk.java.net/browse/JDK-8153745
>>> Webrev:
>>> http://cr.openjdk.java.net/~sjohanss/8153745/hotspot.00/
>>> Summary:
>>> During post_evacuate_collection_set the call to preserve_cm_referents
>>> ensures that no referents discovered by the concurrent reference
>>> processor are lost. This is done unconditionally and sometimes a lot
>>> of
>>> tasks are spawned just to find that there is no work to be done. This
>>> enhancement avoids the unnecessary work by first checking that the
>>> cm-ref-processor has at least some discovered reference to take care
>>> of.
>>    - I would prefer if the referenceprocessor would track whether there
>> are any references in it by itself by setting a flag while adding a
>> reference. I would think that this would be noise in gathering
>> references anyway.
>> While I do not think it is very problematic, consider machines having
>> thousands of threads (which is reality right now).
>> Otherwise at least, if there is no way that any references could have
>> been enqueued because concurrent marking is not running, add an early
>> exit.
> I'm leaning towards the second alternative. I've tried both and doing 
> the book-keeping isn't to bad but it will affect all GCs since the 
> reference processor is shared and it is only G1 that cares about this. 
> I've instead updated the patch with an extra check that makes sure 
> that we only look through the lists when a concurrent cycle is under way.
>>    - the code should not add timing information in case there has been
>> no work. It will automatically show "skipped" in that case. I.e. please
>> move the timing stuff inside the if-block.
>> There is a difference between taking "0.0" time and not having executed
>> that is sometimes interesting to know.
> I did discuss this with Bengt before sending out the patch and for the 
> debug level we currently don't have any logic for "skipped" phases. If 
> turning on logging on trace-level the output will now look like this:
> [1,241s][info ][gc,phases     ] GC(9)   Other: 1,0ms
> [1,241s][debug][gc,phases     ] GC(9)     Choose CSet: 0,0ms
> [1,241s][debug][gc,phases     ] GC(9)     Preserve CM Refs: 0,0ms
> [1,241s][trace][gc,phases     ] GC(9)       Parallel Preserve CM Refs 
> (ms): skipped
> [1,241s][debug][gc,phases     ] GC(9)     Reference Processing: 0,4ms
> [1,241s][debug][gc,phases     ] GC(9)     Reference Enqueuing: 0,0ms
> I think this is ok, but we might want to look at adding logic for 
> "skipping" debug phases as well.
> New webrevs:
> Full: http://cr.openjdk.java.net/~sjohanss/8153745/hotspot.01/
> Inc: http://cr.openjdk.java.net/~sjohanss/8153745/hotspot.00-01/


This is a ignorable comment because it's about an enhancement.

I think the next thing that we will want is to set the number of GC 
threads based
on the number of references that need to be processed.

4468 if (concurrent_mark()->cmThread()->during_cycle() &&
4469 ref_processor_cm()->has_discovered_references()) {
4470     double preserve_cm_referents_start = os::elapsedTime();
4471     uint no_of_gc_workers = workers()->active_workers();
4472     G1ParPreserveCMReferentsTask keep_cm_referents(this,
4473                                                    per_thread_states,
4474                                                    no_of_gc_workers,
4475                                                    _task_queues);
4476     workers()->run_task(&keep_cm_referents);
4477     preserve_cm_referents_time = os::elapsedTime() - preserve_cm_referents_start;
4478   }

For that enhancement I think we will want from the reference processor the
maximum references of any kind that needs to be processed.  When I say
of any kind, I mean that the reference processing is done by type so we want
to choose that number of GC workers based on the largest number that
they will have to process.  Instead of has_discovered_references() I
would choose to implement max_discovered_references().  Then the
testat 4469  would be

if (ref_processor_cm()->max_discovered_references() > 0 ) {

and  later we could do something like

GC_workers_by_max_of_work = max_discovered_references() /

Again totally ignorable.


> Thanks,
> Stefan
>> Thanks,
>>    Thomas

More information about the hotspot-gc-dev mailing list