RFR (M): JDK-8068394: Trace event for concurrent GC phases

Bengt Rutisson bengt.rutisson at oracle.com
Tue Nov 24 13:12:19 UTC 2015

Hi Sangheon,

Sorry for the very late reply to this review request.

On 2015-10-22 01:40, sangheon.kim wrote:
> Hi all,
> Can I get some reviews for this change of adding a trace event for 
> concurrent phases on CMS and G1?
> Currently we only measure pause times for major phases.
> But I want to add 'concurrent mark' and 'concurrent sweep' phases for 
> CMS and 'concurrent mark' phase for G1.
> To achieve this, I had to change ConcurrentGCTimer and related classes.
> This patch includes:
> 1) A concurrent phase can be measured only from ConcurrentGCTimer and 
> measuring an overlap between concurrent and pause is not allowed as 
> currently we don't have that use case. And TimePartitions class(or 
> related classes) will be simpler than an overlap allowed case.
> 2) I removed PausePhase and ConcurrentPhase which are derived from 
> GCPhase because I wanted to avoid heap allocation when adding to 
> GrowableArray. Instead introduced 'type' member variable at GCPhase.
> CR: https://bugs.openjdk.java.net/browse/JDK-8068394
> Webrev: http://cr.openjdk.java.net/~sangheki/8068394/webrev.00/

Nice work! It is great to get some timing information for the concurrent 

A few questions/comments:


You have added timing events for the concurrent phases mark and sweep, 
but not for other concurrent phases (preclean, abortable_preclean and 
reset_concurrent). I think that if you moved your calls to 
_gc_timer_cm->register_gc_concurrent_start() and 
_gc_timer_cm->register_gc_concurrent_end() into the constructor and 
destructor of CMSPhaseAccounting you would automatically get timing 
events for all concurrent phases.


I think the use of _concurrent_marking_from_roots is unfortunate. It 
would be much cleaner if 
ConcurrentMark::register_mark_from_roots_phase_end() called 
register_gc_concurrent_end() directly. I realize that this would change 
the timing for when a concurrent marking is aborted. The whole time for 
a full GC (or even several full GCs) would be included in the concurrent 
marking phase. But from a code perspective that is what happens, so 
maybe that is the correct time to report? Also, I think the logging is 
reported that way so if we want to make it easy to match the timing 
events with the logging we might want to use about the same scope for 

Why do we only measure the concurrent mark phase for G1? Wouldn't it be 
good to measure all concurrent phases?


  389   void visit(GCPhase* phase) {
  390     switch (phase->type()) {
  391       case GCPhase::PausePhaseType:
  392         assert(phase->level() < PhasesStack::PHASE_LEVELS, "Need 
more event types for PausePhase");
  394         switch (phase->level()) {
  395           case 0: send_phase<EventGCPhasePause>(phase); break;
  396           case 1: send_phase<EventGCPhasePauseLevel1>(phase); break;
  397           case 2: send_phase<EventGCPhasePauseLevel2>(phase); break;
  398           case 3: send_phase<EventGCPhasePauseLevel3>(phase); break;
  399           default: /* Ignore sending this phase */ break;
  400         }
  401         break;
  403       case GCPhase::ConcurrentPhaseType:
  404         assert(phase->level() < 1, "There's only one level for 
  406         switch (phase->level()) {
  407           case 0: send_phase<EventGCPhaseConcurrent>(phase); break;
  408           default: /* Ignore sending this phase */ break;
  409         }
  410         break;
  411     }
  412   }
  413 };

Since there are only two values for GCPhase::PhaseType it seems a bit 
odd to use a switch statement. I think I would prefer to factor out the 
code for the different types a bit too. So, maybe something like:

void visit(GCPhase* phase) {
   if (phase->type() == GCPhase::PausePhaseType) {
   } else {
     assert(phase->type() == GCPhase::ConcurrentPhaseType, "");


> Testing: JPRT
> Thanks,
> Sangheon

More information about the hotspot-gc-dev mailing list