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