1 /* 2 * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 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 151 }; 152 153 private: 154 // Markers for grouping the phases in the GCPhases enum above 155 static const int GCMainPhasesLast = GCWorkerEnd; 156 static const int StringDedupPhasesFirst = StringDedupQueueFixup; 157 static const int StringDedupPhasesLast = StringDedupTableFixup; 158 159 WorkerDataArray<double>* _gc_phases[Sentinel]; 160 WorkerDataArray<size_t>* _update_rs_processed_buffers; 161 WorkerDataArray<size_t>* _termination_attempts; 162 WorkerDataArray<size_t>* _redirtied_cards; 163 164 double _cur_collection_par_time_ms; 165 double _cur_collection_code_root_fixup_time_ms; 166 double _cur_strong_code_root_purge_time_ms; 167 168 double _cur_evac_fail_recalc_used; 169 double _cur_evac_fail_restore_remsets; 170 double _cur_evac_fail_remove_self_forwards; 171 172 double _cur_string_dedup_fixup_time_ms; 173 174 double _cur_clear_ct_time_ms; 175 double _cur_ref_proc_time_ms; 176 double _cur_ref_enq_time_ms; 177 178 double _cur_collection_start_sec; 179 double _root_region_scan_wait_time_ms; 180 181 double _recorded_young_cset_choice_time_ms; 182 double _recorded_non_young_cset_choice_time_ms; 183 184 double _recorded_redirty_logged_cards_time_ms; 185 186 double _recorded_young_free_cset_time_ms; 187 double _recorded_non_young_free_cset_time_ms; 188 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 249 void record_evac_fail_restore_remsets(double ms) { 250 _cur_evac_fail_restore_remsets = ms; 251 } 252 253 void record_evac_fail_remove_self_forwards(double ms) { 254 _cur_evac_fail_remove_self_forwards = ms; 255 } 256 257 void record_string_dedup_fixup_time(double ms) { 258 _cur_string_dedup_fixup_time_ms = ms; 259 } 260 261 void record_ref_proc_time(double ms) { 262 _cur_ref_proc_time_ms = ms; 263 } 264 265 void record_ref_enq_time(double ms) { 266 _cur_ref_enq_time_ms = ms; 267 } 268 269 void record_root_region_scan_wait_time(double time_ms) { 270 _root_region_scan_wait_time_ms = time_ms; 271 } 272 273 void record_young_free_cset_time_ms(double time_ms) { 274 _recorded_young_free_cset_time_ms = time_ms; 275 } 276 277 void record_non_young_free_cset_time_ms(double time_ms) { 278 _recorded_non_young_free_cset_time_ms = time_ms; 279 } 280 281 void record_fast_reclaim_humongous_stats(double time_ms, size_t total, size_t candidates) { 282 _cur_fast_reclaim_humongous_register_time_ms = time_ms; 283 _cur_fast_reclaim_humongous_total = total; 284 _cur_fast_reclaim_humongous_candidates = candidates; 285 } 286 287 void record_fast_reclaim_humongous_time_ms(double value, size_t reclaimed) { 288 _cur_fast_reclaim_humongous_time_ms = value; 289 _cur_fast_reclaim_humongous_reclaimed = reclaimed; 290 } 291 292 void record_young_cset_choice_time_ms(double time_ms) { 293 _recorded_young_cset_choice_time_ms = time_ms; 294 } 295 296 void record_non_young_cset_choice_time_ms(double time_ms) { 297 _recorded_non_young_cset_choice_time_ms = time_ms; 298 } 299 300 void record_redirty_logged_cards_time_ms(double time_ms) { 301 _recorded_redirty_logged_cards_time_ms = time_ms; 302 } 303 304 void record_cur_collection_start_sec(double time_ms) { 305 _cur_collection_start_sec = time_ms; 306 } 307 308 void record_verify_before_time_ms(double time_ms) { 309 _cur_verify_before_time_ms = time_ms; 310 } 311 312 void record_verify_after_time_ms(double time_ms) { 313 _cur_verify_after_time_ms = time_ms; 314 } 315 316 double accounted_time_ms(); 317 318 double cur_collection_start_sec() { 319 return _cur_collection_start_sec; 320 } 321 322 double cur_collection_par_time_ms() { 323 return _cur_collection_par_time_ms; 324 } 325 326 double cur_clear_ct_time_ms() { 327 return _cur_clear_ct_time_ms; 328 } 329 330 double root_region_scan_wait_time_ms() { 331 return _root_region_scan_wait_time_ms; 332 } 333 334 double young_cset_choice_time_ms() { 335 return _recorded_young_cset_choice_time_ms; 336 } 337 338 double young_free_cset_time_ms() { 339 return _recorded_young_free_cset_time_ms; 340 } 341 342 double non_young_cset_choice_time_ms() { 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