14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1GCPHASETIMESLOG_HPP 26 #define SHARE_VM_GC_IMPLEMENTATION_G1_G1GCPHASETIMESLOG_HPP 27 28 #include "gc_interface/gcCause.hpp" 29 30 class LineBuffer; 31 32 template <class T> 33 class WorkerDataArray : public CHeapObj<mtGC> { 34 T* _data; 35 uint _length; 36 const char* _title; 37 bool _print_sum; 38 int _log_level; 39 uint _indent_level; 40 bool _enabled; 41 42 WorkerDataArray<size_t>* _sub_count; 43 44 NOT_PRODUCT(T uninitialized();) 45 46 // We are caching the sum and average to only have to calculate them once. 47 // This is not done in an MT-safe way. It is intended to allow single 48 // threaded code to call sum() and average() multiple times in any order 49 // without having to worry about the cost. 50 bool _has_new_data; 51 T _sum; 52 double _average; 53 54 void log_value(LineBuffer& buf, T value); 55 56 public: 57 WorkerDataArray(uint length, const char* title, bool print_sum, int log_level, uint indent_level); 58 59 ~WorkerDataArray(); 60 61 void link_sub_count_array(WorkerDataArray<size_t>* sub_count) { 62 _sub_count = sub_count; 63 } 64 65 void set(uint worker_i, T value) { 66 assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); 67 assert(_data[worker_i] == WorkerDataArray<T>::uninitialized(), err_msg("Overwriting data for worker %d in %s", worker_i, _title)); 68 _data[worker_i] = value; 69 _has_new_data = true; 70 } 71 72 void set_sub_count(uint worker_i, size_t value) { 73 assert(_sub_count != NULL, "No sub count"); 74 _sub_count->set(worker_i, value); 75 } 76 77 size_t sub_count_sum() { 78 assert(_sub_count != NULL, "No sub count"); 79 return _sub_count->sum(); 80 } 81 82 T get(uint worker_i) { 83 assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); 84 assert(_data[worker_i] != WorkerDataArray<T>::uninitialized(), err_msg("No data to add to for worker %d", worker_i)); 85 return _data[worker_i]; 86 } 87 88 void add(uint worker_i, T value) { 89 assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); 90 assert(_data[worker_i] != WorkerDataArray<T>::uninitialized(), err_msg("No data to add to for worker %d", worker_i)); 91 _data[worker_i] += value; 92 _has_new_data = true; 93 } 94 95 double average(){ 96 if (_has_new_data) { 97 calculate_totals(); 98 } 99 return _average; 100 } 101 102 T sum() { 103 if (_has_new_data) { 104 calculate_totals(); 105 } 106 return _sum; 107 } 108 109 void print(); 110 111 void reset() PRODUCT_RETURN; 112 void verify() PRODUCT_RETURN; 113 114 void set_enabled(bool enabled) { _enabled = enabled; } 115 116 int log_level() { return _log_level; } 117 118 private: 119 120 void calculate_totals(){ 121 _sum = (T)0; 122 for (uint i = 0; i < _length; ++i) { 123 _sum += _data[i]; 124 } 125 _average = (double)_sum / (double)_length; 126 _has_new_data = false; 127 } 128 }; 129 130 class G1GCPhaseTimes : public CHeapObj<mtGC> { 131 uint _active_gc_threads; 132 uint _max_gc_threads; 133 134 public: 135 enum GCPhases { 136 GCWorkerStart, 137 ExtRootScan, 138 SATBFiltering, 139 UpdateRS, 140 ScanRS, 141 CodeRoots, 142 ObjCopy, 143 Termination, 144 Other, 145 GCWorkerTotal, 146 GCWorkerEnd, 147 StringDedupQueueFixup, 148 StringDedupTableFixup, 149 RedirtyCards, 150 Sentinel 189 double _cur_fast_reclaim_humongous_time_ms; 190 double _cur_fast_reclaim_humongous_register_time_ms; 191 size_t _cur_fast_reclaim_humongous_total; 192 size_t _cur_fast_reclaim_humongous_candidates; 193 size_t _cur_fast_reclaim_humongous_reclaimed; 194 195 double _cur_verify_before_time_ms; 196 double _cur_verify_after_time_ms; 197 198 // Helper methods for detailed logging 199 void print_stats(int level, const char* str, double value); 200 void print_stats(int level, const char* str, size_t value); 201 void print_stats(int level, const char* str, double value, uint workers); 202 203 public: 204 G1GCPhaseTimes(uint max_gc_threads); 205 void note_gc_start(uint active_gc_threads, bool mark_in_progress); 206 void note_gc_end(); 207 void print(double pause_time_sec); 208 209 void record_time(GCPhases phase, uint worker_i, double time) { 210 _gc_phases[phase]->set(worker_i, time); 211 } 212 213 void add_time(GCPhases phase, uint worker_i, double time) { 214 _gc_phases[phase]->add(worker_i, time); 215 } 216 217 void record_sub_count(GCPhases phase, uint worker_i, size_t count) { 218 _gc_phases[phase]->set_sub_count(worker_i, count); 219 } 220 221 double average_time(GCPhases phase) { 222 return _gc_phases[phase]->average(); 223 } 224 225 size_t sub_count_sum(GCPhases phase) { 226 return _gc_phases[phase]->sub_count_sum(); 227 } 228 229 void record_clear_ct_time(double ms) { 230 _cur_clear_ct_time_ms = ms; 231 } 232 233 void record_par_time(double ms) { 234 _cur_collection_par_time_ms = ms; 235 } 236 237 void record_code_root_fixup_time(double ms) { 238 _cur_collection_code_root_fixup_time_ms = ms; 239 } 240 241 void record_strong_code_root_purge_time(double ms) { 242 _cur_strong_code_root_purge_time_ms = ms; 243 } 244 245 void record_evac_fail_recalc_used_time(double ms) { 246 _cur_evac_fail_recalc_used = ms; 247 } 248 343 return _recorded_non_young_cset_choice_time_ms; 344 } 345 346 double non_young_free_cset_time_ms() { 347 return _recorded_non_young_free_cset_time_ms; 348 } 349 350 double fast_reclaim_humongous_time_ms() { 351 return _cur_fast_reclaim_humongous_time_ms; 352 } 353 }; 354 355 class G1GCPhaseTimesTracker : public StackObj { 356 double _start_time; 357 G1GCPhaseTimes::GCPhases _phase; 358 G1GCPhaseTimes* _phase_times; 359 uint _worker_id; 360 public: 361 G1GCPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCPhases phase, uint worker_id); 362 ~G1GCPhaseTimesTracker(); 363 }; 364 365 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1GCPHASETIMESLOG_HPP | 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1GCPHASETIMESLOG_HPP 26 #define SHARE_VM_GC_IMPLEMENTATION_G1_G1GCPHASETIMESLOG_HPP 27 28 #include "gc_interface/gcCause.hpp" 29 30 class LineBuffer; 31 32 template <class T> 33 class WorkerDataArray : public CHeapObj<mtGC> { 34 friend class G1GCPhasePrinter; 35 T* _data; 36 uint _length; 37 const char* _title; 38 bool _print_sum; 39 int _log_level; 40 uint _indent_level; 41 bool _enabled; 42 43 WorkerDataArray<size_t>* _sub_count; 44 45 NOT_PRODUCT(T uninitialized();) 46 47 // We are caching the sum and average to only have to calculate them once. 48 // This is not done in an MT-safe way. It is intended to allow single 49 // threaded code to call sum() and average() multiple times in any order 50 // without having to worry about the cost. 51 bool _has_new_data; 52 T _sum; 53 T _min; 54 T _max; 55 double _average; 56 57 public: 58 WorkerDataArray(uint length, const char* title, bool print_sum, int log_level, uint indent_level); 59 60 ~WorkerDataArray(); 61 62 void link_sub_count_array(WorkerDataArray<size_t>* sub_count) { 63 _sub_count = sub_count; 64 } 65 66 WorkerDataArray<size_t>* sub_count() { return _sub_count; } 67 68 void set(uint worker_i, T value) { 69 assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); 70 assert(_data[worker_i] == WorkerDataArray<T>::uninitialized(), err_msg("Overwriting data for worker %d in %s", worker_i, _title)); 71 _data[worker_i] = value; 72 _has_new_data = true; 73 } 74 75 void set_sub_count(uint worker_i, size_t value) { 76 assert(_sub_count != NULL, "No sub count"); 77 _sub_count->set(worker_i, value); 78 } 79 80 T get(uint worker_i) { 81 assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); 82 assert(_data[worker_i] != WorkerDataArray<T>::uninitialized(), err_msg("No data to add to for worker %d", worker_i)); 83 return _data[worker_i]; 84 } 85 86 void add(uint worker_i, T value) { 87 assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); 88 assert(_data[worker_i] != WorkerDataArray<T>::uninitialized(), err_msg("No data to add to for worker %d", worker_i)); 89 _data[worker_i] += value; 90 _has_new_data = true; 91 } 92 93 double average(){ 94 calculate_totals(); 95 return _average; 96 } 97 98 T sum() { 99 calculate_totals(); 100 return _sum; 101 } 102 103 T minimum() { 104 calculate_totals(); 105 return _min; 106 } 107 108 T maximum() { 109 calculate_totals(); 110 return _max; 111 } 112 113 void reset() PRODUCT_RETURN; 114 void verify() PRODUCT_RETURN; 115 116 void set_enabled(bool enabled) { _enabled = enabled; } 117 118 int log_level() { return _log_level; } 119 120 private: 121 122 void calculate_totals(){ 123 if (!_has_new_data) { 124 return; 125 } 126 127 _sum = (T)0; 128 _min = _data[0]; 129 _max = _min; 130 for (uint i = 0; i < _length; ++i) { 131 T val = _data[i]; 132 _sum += val; 133 _min = MIN2(_min, val); 134 _max = MAX2(_max, val); 135 } 136 _average = (double)_sum / (double)_length; 137 _has_new_data = false; 138 } 139 }; 140 141 class G1GCPhaseTimes : public CHeapObj<mtGC> { 142 friend class G1GCPhasePrinter; 143 144 uint _active_gc_threads; 145 uint _max_gc_threads; 146 147 public: 148 enum GCPhases { 149 GCWorkerStart, 150 ExtRootScan, 151 SATBFiltering, 152 UpdateRS, 153 ScanRS, 154 CodeRoots, 155 ObjCopy, 156 Termination, 157 Other, 158 GCWorkerTotal, 159 GCWorkerEnd, 160 StringDedupQueueFixup, 161 StringDedupTableFixup, 162 RedirtyCards, 163 Sentinel 202 double _cur_fast_reclaim_humongous_time_ms; 203 double _cur_fast_reclaim_humongous_register_time_ms; 204 size_t _cur_fast_reclaim_humongous_total; 205 size_t _cur_fast_reclaim_humongous_candidates; 206 size_t _cur_fast_reclaim_humongous_reclaimed; 207 208 double _cur_verify_before_time_ms; 209 double _cur_verify_after_time_ms; 210 211 // Helper methods for detailed logging 212 void print_stats(int level, const char* str, double value); 213 void print_stats(int level, const char* str, size_t value); 214 void print_stats(int level, const char* str, double value, uint workers); 215 216 public: 217 G1GCPhaseTimes(uint max_gc_threads); 218 void note_gc_start(uint active_gc_threads, bool mark_in_progress); 219 void note_gc_end(); 220 void print(double pause_time_sec); 221 222 // record the time a phase took in seconds 223 void record_time_secs(GCPhases phase, uint worker_i, double secs) { 224 _gc_phases[phase]->set(worker_i, secs); 225 } 226 227 // add a number of seconds to a phase 228 void add_time_secs(GCPhases phase, uint worker_i, double secs) { 229 _gc_phases[phase]->add(worker_i, secs); 230 } 231 232 void record_sub_count(GCPhases phase, uint worker_i, size_t count) { 233 _gc_phases[phase]->set_sub_count(worker_i, count); 234 } 235 236 // return the average time for a phase in milliseconds 237 double average_time_ms(GCPhases phase) { 238 return _gc_phases[phase]->average() * 1000.0; 239 } 240 241 size_t sub_count_sum(GCPhases phase) { 242 assert(_gc_phases[phase]->sub_count() != NULL, "No sub count"); 243 return _gc_phases[phase]->sub_count()->sum(); 244 } 245 246 private: 247 248 double get_time_ms(GCPhases phase, uint worker_i) { 249 return _gc_phases[phase]->get(worker_i) * 1000.0; 250 } 251 252 double sum_time_ms(GCPhases phase) { 253 return _gc_phases[phase]->sum() * 1000.0; 254 } 255 256 double min_time_ms(GCPhases phase) { 257 return _gc_phases[phase]->minimum() * 1000.0; 258 } 259 260 double max_time_ms(GCPhases phase) { 261 return _gc_phases[phase]->maximum() * 1000.0; 262 } 263 264 size_t get_sub_count(GCPhases phase, uint worker_i) { 265 assert(_gc_phases[phase]->sub_count() != NULL, "No sub count"); 266 return _gc_phases[phase]->sub_count()->get(worker_i); 267 } 268 269 size_t sum_sub_count(GCPhases phase) { 270 assert(_gc_phases[phase]->sub_count() != NULL, "No sub count"); 271 return _gc_phases[phase]->sub_count()->sum(); 272 } 273 274 double average_sub_count(GCPhases phase) { 275 assert(_gc_phases[phase]->sub_count() != NULL, "No sub count"); 276 return _gc_phases[phase]->sub_count()->average(); 277 } 278 279 size_t min_sub_count(GCPhases phase) { 280 assert(_gc_phases[phase]->sub_count() != NULL, "No sub count"); 281 return _gc_phases[phase]->sub_count()->minimum(); 282 } 283 284 size_t max_sub_count(GCPhases phase) { 285 assert(_gc_phases[phase]->sub_count() != NULL, "No sub count"); 286 return _gc_phases[phase]->sub_count()->maximum(); 287 } 288 289 public: 290 291 void record_clear_ct_time(double ms) { 292 _cur_clear_ct_time_ms = ms; 293 } 294 295 void record_par_time(double ms) { 296 _cur_collection_par_time_ms = ms; 297 } 298 299 void record_code_root_fixup_time(double ms) { 300 _cur_collection_code_root_fixup_time_ms = ms; 301 } 302 303 void record_strong_code_root_purge_time(double ms) { 304 _cur_strong_code_root_purge_time_ms = ms; 305 } 306 307 void record_evac_fail_recalc_used_time(double ms) { 308 _cur_evac_fail_recalc_used = ms; 309 } 310 405 return _recorded_non_young_cset_choice_time_ms; 406 } 407 408 double non_young_free_cset_time_ms() { 409 return _recorded_non_young_free_cset_time_ms; 410 } 411 412 double fast_reclaim_humongous_time_ms() { 413 return _cur_fast_reclaim_humongous_time_ms; 414 } 415 }; 416 417 class G1GCPhaseTimesTracker : public StackObj { 418 double _start_time; 419 G1GCPhaseTimes::GCPhases _phase; 420 G1GCPhaseTimes* _phase_times; 421 uint _worker_id; 422 public: 423 G1GCPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCPhases phase, uint worker_id); 424 ~G1GCPhaseTimesTracker(); 425 }; 426 427 class G1GCPhasePrinter : public StackObj { 428 G1GCPhaseTimes* _phase_times; 429 void print_single_length(G1GCPhaseTimes::GCPhases phase_id, WorkerDataArray<double>* phase); 430 void print_multi_length(G1GCPhaseTimes::GCPhases phase_id, WorkerDataArray<double>* phase); 431 void print_sub_count(G1GCPhaseTimes::GCPhases phase_id, WorkerDataArray<size_t>* sub_count); 432 void print_time_values(LineBuffer& buf, G1GCPhaseTimes::GCPhases phase_id, WorkerDataArray<double>* phase); 433 void print_count_values(LineBuffer& buf, G1GCPhaseTimes::GCPhases phase_id, WorkerDataArray<size_t>* phase); 434 public: 435 G1GCPhasePrinter(G1GCPhaseTimes* phase_times) : _phase_times(phase_times) {} 436 void print(G1GCPhaseTimes::GCPhases phase_id); 437 }; 438 439 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1GCPHASETIMESLOG_HPP |