3030#include " gc/shenandoah/shenandoahHeap.hpp"
3131#include " gc/shenandoah/shenandoahHeuristics.hpp"
3232#include " gc/shenandoah/shenandoahUtils.hpp"
33+ #include " runtime/orderAccess.hpp"
3334#include " utilities/ostream.hpp"
3435
36+ #define SHENANDOAH_PHASE_NAME_FORMAT " %-28s"
37+ #define SHENANDOAH_S_TIME_FORMAT " %8.3lf"
38+ #define SHENANDOAH_US_TIME_FORMAT " %8.0lf"
39+ #define SHENANDOAH_US_WORKER_TIME_FORMAT " %3.0lf"
40+
3541#define GC_PHASE_DECLARE_NAME (type, title ) \
3642 title,
3743
@@ -42,62 +48,155 @@ const char* ShenandoahPhaseTimings::_phase_names[] = {
4248#undef GC_PHASE_DECLARE_NAME
4349
4450ShenandoahPhaseTimings::ShenandoahPhaseTimings () {
45- uint max_workers = MAX2 (ConcGCThreads, ParallelGCThreads);
46- assert (max_workers > 0 , " Must have some GC threads" );
51+ _max_workers = MAX2 (ConcGCThreads, ParallelGCThreads);
52+ assert (_max_workers > 0 , " Must have some GC threads" );
4753
48- #define GC_PAR_PHASE_DECLARE_WORKER_DATA (type, title ) \
49- _gc_par_phases[ShenandoahPhaseTimings::type] = new WorkerDataArray<double >(title, max_workers);
50- // Root scanning phases
51- SHENANDOAH_GC_PAR_PHASE_DO (,, GC_PAR_PHASE_DECLARE_WORKER_DATA)
52- #undef GC_PAR_PHASE_DECLARE_WORKER_DATA
54+ // Initialize everything to sane defaults
55+ for (uint i = 0 ; i < _num_phases; i++) {
56+ #define SHENANDOAH_WORKER_DATA_NULL (type, title ) \
57+ _worker_data[i] = NULL ;
58+ SHENANDOAH_GC_PAR_PHASE_DO (,, SHENANDOAH_WORKER_DATA_NULL)
59+ #undef SHENANDOAH_WORKER_DATA_NULL
60+ _cycle_data[i] = 0 ;
61+ }
62+
63+ // Then punch in the worker-related data.
64+ // Every worker phase get a bunch of internal objects, except
65+ // the very first slot, which is "<total>" and is not populated.
66+ for (uint i = 0 ; i < _num_phases; i++) {
67+ if (is_worker_phase (Phase (i))) {
68+ int c = 0 ;
69+ #define SHENANDOAH_WORKER_DATA_INIT (type, title ) \
70+ if (c++ != 0 ) _worker_data[i + c] = new ShenandoahWorkerData (title, _max_workers);
71+ SHENANDOAH_GC_PAR_PHASE_DO (,, SHENANDOAH_WORKER_DATA_INIT)
72+ #undef SHENANDOAH_WORKER_DATA_INIT
73+ }
74+ }
5375
5476 _policy = ShenandoahHeap::heap ()->shenandoah_policy ();
5577 assert (_policy != NULL , " Can not be NULL" );
78+
79+ _current_worker_phase = _invalid_phase;
80+ }
81+
82+ ShenandoahPhaseTimings::Phase ShenandoahPhaseTimings::worker_par_phase (Phase phase, GCParPhases par_phase) {
83+ assert (is_worker_phase (phase), " Phase should accept worker phase times: %s" , phase_name (phase));
84+ Phase p = Phase (phase + 1 + par_phase);
85+ assert (p >= 0 && p < _num_phases, " Out of bound for: %s" , phase_name (phase));
86+ return p;
87+ }
88+
89+ ShenandoahWorkerData* ShenandoahPhaseTimings::worker_data (Phase phase, GCParPhases par_phase) {
90+ Phase p = worker_par_phase (phase, par_phase);
91+ ShenandoahWorkerData* wd = _worker_data[p];
92+ assert (wd != NULL , " Counter initialized: %s" , phase_name (p));
93+ return wd;
94+ }
95+
96+ bool ShenandoahPhaseTimings::is_worker_phase (Phase phase) {
97+ assert (phase >= 0 && phase < _num_phases, " Out of bounds" );
98+ switch (phase) {
99+ case init_evac:
100+ case scan_roots:
101+ case update_roots:
102+ case final_update_refs_roots:
103+ case full_gc_scan_roots:
104+ case full_gc_update_roots:
105+ case full_gc_adjust_roots:
106+ case degen_gc_update_roots:
107+ case full_gc_purge_class_unload:
108+ case full_gc_purge_weak_par:
109+ case purge_class_unload:
110+ case purge_weak_par:
111+ case heap_iteration_roots:
112+ return true ;
113+ default :
114+ return false ;
115+ }
116+ }
117+
118+ void ShenandoahPhaseTimings::set_cycle_data (Phase phase, double time) {
119+ #ifdef ASSERT
120+ double d = _cycle_data[phase];
121+ assert (d == 0 , " Should not be set yet: %s, current value: %lf" , phase_name (phase), d);
122+ #endif
123+ _cycle_data[phase] = time;
56124}
57125
58126void ShenandoahPhaseTimings::record_phase_time (Phase phase, double time) {
59127 if (!_policy->is_at_shutdown ()) {
60- _timing_data[phase]. add ( time);
128+ set_cycle_data (phase, time);
61129 }
62130}
63131
64132void ShenandoahPhaseTimings::record_workers_start (Phase phase) {
65- for (uint i = 0 ; i < GCParPhasesSentinel; i++) {
66- _gc_par_phases[i]->reset ();
133+ assert (is_worker_phase (phase), " Phase should accept worker phase times: %s" , phase_name (phase));
134+
135+ assert (_current_worker_phase == _invalid_phase, " Should not be set yet: requested %s, existing %s" ,
136+ phase_name (phase), phase_name (_current_worker_phase));
137+ _current_worker_phase = phase;
138+
139+ for (uint i = 1 ; i < GCParPhasesSentinel; i++) {
140+ worker_data (phase, GCParPhases (i))->reset ();
67141 }
68142}
69143
70144void ShenandoahPhaseTimings::record_workers_end (Phase phase) {
71- if (_policy->is_at_shutdown ()) {
72- // Do not record the past-shutdown events
73- return ;
145+ assert (is_worker_phase (phase), " Phase should accept worker phase times: %s" , phase_name (phase));
146+ _current_worker_phase = _invalid_phase;
147+ }
148+
149+ void ShenandoahPhaseTimings::flush_par_workers_to_cycle () {
150+ for (uint pi = 0 ; pi < _num_phases; pi++) {
151+ Phase phase = Phase (pi);
152+ if (is_worker_phase (phase)) {
153+ double s = 0 ;
154+ for (uint i = 1 ; i < GCParPhasesSentinel; i++) {
155+ double t = worker_data (phase, GCParPhases (i))->sum ();
156+ // add to each line in phase
157+ set_cycle_data (Phase (phase + i + 1 ), t);
158+ s += t;
159+ }
160+ // add to total for phase
161+ set_cycle_data (Phase (phase + 1 ), s);
162+ }
74163 }
164+ }
75165
76- assert (phase == init_evac ||
77- phase == scan_roots ||
78- phase == update_roots ||
79- phase == final_update_refs_roots ||
80- phase == full_gc_scan_roots ||
81- phase == full_gc_update_roots ||
82- phase == full_gc_adjust_roots ||
83- phase == degen_gc_update_roots ||
84- phase == full_gc_purge_class_unload ||
85- phase == full_gc_purge_weak_par ||
86- phase == purge_class_unload ||
87- phase == purge_weak_par ||
88- phase == heap_iteration_roots,
89- " Phase should accept accept per-thread phase times: %s" , phase_name (phase));
90-
91- double s = 0 ;
92- for (uint i = 1 ; i < GCParPhasesSentinel; i++) {
93- double t = _gc_par_phases[i]->sum ();
94- _timing_data[phase + i + 1 ].add (t); // add to each line in phase
95- s += t;
166+ void ShenandoahPhaseTimings::flush_cycle_to_global () {
167+ for (uint i = 0 ; i < _num_phases; i++) {
168+ _global_data[i].add (_cycle_data[i]);
169+ _cycle_data[i] = 0 ;
96170 }
97- _timing_data[phase + 1 ]. add (s); // add to total for phase
171+ OrderAccess::fence ();
98172}
99173
100- void ShenandoahPhaseTimings::print_on (outputStream* out) const {
174+ void ShenandoahPhaseTimings::print_cycle_on (outputStream* out) const {
175+ out->cr ();
176+ out->print_cr (" All times are wall-clock times, except per-root-class counters, that are sum over" );
177+ out->print_cr (" all workers. Dividing the <total> over the root stage time estimates parallelism." );
178+ out->cr ();
179+ for (uint i = 0 ; i < _num_phases; i++) {
180+ double v = _cycle_data[i] * 1000000.0 ;
181+ if (v > 0 ) {
182+ out->print (SHENANDOAH_PHASE_NAME_FORMAT " " SHENANDOAH_US_TIME_FORMAT " us" , _phase_names[i], v);
183+ if (_worker_data[i] != NULL ) {
184+ out->print (" , workers (us): " );
185+ for (size_t c = 0 ; c < _max_workers; c++) {
186+ double tv = _worker_data[i]->get (c);
187+ if (tv != ShenandoahWorkerData::uninitialized ()) {
188+ out->print (SHENANDOAH_US_WORKER_TIME_FORMAT " , " , tv * 1000000.0 );
189+ } else {
190+ out->print (" %3s, " , " ---" );
191+ }
192+ }
193+ }
194+ out->cr ();
195+ }
196+ }
197+ }
198+
199+ void ShenandoahPhaseTimings::print_global_on (outputStream* out) const {
101200 out->cr ();
102201 out->print_cr (" GC STATISTICS:" );
103202 out->print_cr (" \" (G)\" (gross) pauses include VM time: time to notify and block threads, do the pre-" );
@@ -111,37 +210,43 @@ void ShenandoahPhaseTimings::print_on(outputStream* out) const {
111210 out->cr ();
112211
113212 for (uint i = 0 ; i < _num_phases; i++) {
114- if (_timing_data[i].maximum () != 0 ) {
115- out->print_cr (" %-27s = %8.2lf s (a = %8.0lf us) (n = " INT32_FORMAT_W (5 ) " ) (lvls, us = %8.0lf, %8.0lf, %8.0lf, %8.0lf, %8.0lf)" ,
213+ if (_global_data[i].maximum () != 0 ) {
214+ out->print_cr (SHENANDOAH_PHASE_NAME_FORMAT " = " SHENANDOAH_S_TIME_FORMAT " s "
215+ " (a = " SHENANDOAH_US_TIME_FORMAT " us) "
216+ " (n = " INT32_FORMAT_W (5 ) " ) (lvls, us = "
217+ SHENANDOAH_US_TIME_FORMAT " , "
218+ SHENANDOAH_US_TIME_FORMAT " , "
219+ SHENANDOAH_US_TIME_FORMAT " , "
220+ SHENANDOAH_US_TIME_FORMAT " , "
221+ SHENANDOAH_US_TIME_FORMAT " )" ,
116222 _phase_names[i],
117- _timing_data [i].sum (),
118- _timing_data [i].avg () * 1000000.0 ,
119- _timing_data [i].num (),
120- _timing_data [i].percentile (0 ) * 1000000.0 ,
121- _timing_data [i].percentile (25 ) * 1000000.0 ,
122- _timing_data [i].percentile (50 ) * 1000000.0 ,
123- _timing_data [i].percentile (75 ) * 1000000.0 ,
124- _timing_data [i].maximum () * 1000000.0
223+ _global_data [i].sum (),
224+ _global_data [i].avg () * 1000000.0 ,
225+ _global_data [i].num (),
226+ _global_data [i].percentile (0 ) * 1000000.0 ,
227+ _global_data [i].percentile (25 ) * 1000000.0 ,
228+ _global_data [i].percentile (50 ) * 1000000.0 ,
229+ _global_data [i].percentile (75 ) * 1000000.0 ,
230+ _global_data [i].maximum () * 1000000.0
125231 );
126232 }
127233 }
128234}
129235
130- void ShenandoahPhaseTimings::record_worker_time (ShenandoahPhaseTimings::GCParPhases phase, uint worker_id, double secs) {
131- _gc_par_phases[phase]->set (worker_id, secs);
132- }
133-
134- ShenandoahWorkerTimingsTracker::ShenandoahWorkerTimingsTracker (ShenandoahPhaseTimings::GCParPhases phase, uint worker_id) :
135- _phase(phase), _timings(ShenandoahHeap::heap()->phase_timings()), _worker_id(worker_id) {
236+ ShenandoahWorkerTimingsTracker::ShenandoahWorkerTimingsTracker (ShenandoahPhaseTimings::GCParPhases par_phase, uint worker_id) :
237+ _timings(ShenandoahHeap::heap()->phase_timings()), _phase(_timings->current_worker_phase ()),
238+ _par_phase(par_phase), _worker_id(worker_id) {
239+ assert (_timings->worker_data (_phase, _par_phase)->get (_worker_id) == ShenandoahWorkerData::uninitialized (),
240+ " Should not be set yet: %s" , ShenandoahPhaseTimings::phase_name (_timings->worker_par_phase (_phase, _par_phase)));
136241 _start_time = os::elapsedTime ();
137242}
138243
139244ShenandoahWorkerTimingsTracker::~ShenandoahWorkerTimingsTracker () {
140- _timings->record_worker_time (_phase, _worker_id, os::elapsedTime () - _start_time);
245+ _timings->worker_data (_phase, _par_phase)-> set ( _worker_id, os::elapsedTime () - _start_time);
141246
142247 if (ShenandoahGCPhase::is_root_work_phase ()) {
143248 ShenandoahPhaseTimings::Phase root_phase = ShenandoahGCPhase::current_phase ();
144- ShenandoahPhaseTimings::Phase cur_phase = (ShenandoahPhaseTimings::Phase)(( int ) root_phase + ( int )_phase + 1 );
249+ ShenandoahPhaseTimings::Phase cur_phase = _timings-> worker_par_phase ( root_phase, _par_phase );
145250 _event.commit (GCId::current (), _worker_id, ShenandoahPhaseTimings::phase_name (cur_phase));
146251 }
147252}
0 commit comments