src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp

Tue, 17 Oct 2017 12:58:25 +0800

author
aoqi
date
Tue, 17 Oct 2017 12:58:25 +0800
changeset 7994
04ff2f6cd0eb
parent 7893
a5b77ac78ad2
parent 7535
7ae4e26cb1e0
child 8604
04d83ba48607
permissions
-rw-r--r--

merge

aoqi@0 1 /*
tschatzl@7893 2 * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation.
aoqi@0 8 *
aoqi@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 12 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 13 * accompanied this code).
aoqi@0 14 *
aoqi@0 15 * You should have received a copy of the GNU General Public License version
aoqi@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 18 *
aoqi@0 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 20 * or visit www.oracle.com if you need additional information or have any
aoqi@0 21 * questions.
aoqi@0 22 *
aoqi@0 23 */
aoqi@0 24
aoqi@0 25 #include "precompiled.hpp"
aoqi@0 26 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
aoqi@0 27 #include "gc_implementation/g1/g1GCPhaseTimes.hpp"
aoqi@0 28 #include "gc_implementation/g1/g1Log.hpp"
aoqi@0 29 #include "gc_implementation/g1/g1StringDedup.hpp"
brutisso@7658 30 #include "memory/allocation.hpp"
brutisso@7658 31 #include "runtime/os.hpp"
aoqi@0 32
aoqi@0 33 // Helper class for avoiding interleaved logging
aoqi@0 34 class LineBuffer: public StackObj {
aoqi@0 35
aoqi@0 36 private:
aoqi@0 37 static const int BUFFER_LEN = 1024;
aoqi@0 38 static const int INDENT_CHARS = 3;
aoqi@0 39 char _buffer[BUFFER_LEN];
aoqi@0 40 int _indent_level;
aoqi@0 41 int _cur;
aoqi@0 42
aoqi@0 43 void vappend(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0) {
aoqi@0 44 int res = vsnprintf(&_buffer[_cur], BUFFER_LEN - _cur, format, ap);
aoqi@0 45 if (res != -1) {
aoqi@0 46 _cur += res;
aoqi@0 47 } else {
aoqi@0 48 DEBUG_ONLY(warning("buffer too small in LineBuffer");)
aoqi@0 49 _buffer[BUFFER_LEN -1] = 0;
aoqi@0 50 _cur = BUFFER_LEN; // vsnprintf above should not add to _buffer if we are called again
aoqi@0 51 }
aoqi@0 52 }
aoqi@0 53
aoqi@0 54 public:
aoqi@0 55 explicit LineBuffer(int indent_level): _indent_level(indent_level), _cur(0) {
aoqi@0 56 for (; (_cur < BUFFER_LEN && _cur < (_indent_level * INDENT_CHARS)); _cur++) {
aoqi@0 57 _buffer[_cur] = ' ';
aoqi@0 58 }
aoqi@0 59 }
aoqi@0 60
aoqi@0 61 #ifndef PRODUCT
aoqi@0 62 ~LineBuffer() {
aoqi@0 63 assert(_cur == _indent_level * INDENT_CHARS, "pending data in buffer - append_and_print_cr() not called?");
aoqi@0 64 }
aoqi@0 65 #endif
aoqi@0 66
aoqi@0 67 void append(const char* format, ...) ATTRIBUTE_PRINTF(2, 3) {
aoqi@0 68 va_list ap;
aoqi@0 69 va_start(ap, format);
aoqi@0 70 vappend(format, ap);
aoqi@0 71 va_end(ap);
aoqi@0 72 }
aoqi@0 73
brutisso@7658 74 void print_cr() {
brutisso@7658 75 gclog_or_tty->print_cr("%s", _buffer);
brutisso@7658 76 _cur = _indent_level * INDENT_CHARS;
brutisso@7658 77 }
brutisso@7658 78
aoqi@0 79 void append_and_print_cr(const char* format, ...) ATTRIBUTE_PRINTF(2, 3) {
aoqi@0 80 va_list ap;
aoqi@0 81 va_start(ap, format);
aoqi@0 82 vappend(format, ap);
aoqi@0 83 va_end(ap);
brutisso@7658 84 print_cr();
aoqi@0 85 }
aoqi@0 86 };
aoqi@0 87
aoqi@0 88 template <class T>
brutisso@7658 89 class WorkerDataArray : public CHeapObj<mtGC> {
brutisso@7658 90 friend class G1GCParPhasePrinter;
brutisso@7658 91 T* _data;
brutisso@7658 92 uint _length;
brutisso@7658 93 const char* _title;
brutisso@7658 94 bool _print_sum;
brutisso@7658 95 int _log_level;
brutisso@7658 96 uint _indent_level;
brutisso@7658 97 bool _enabled;
brutisso@7658 98
brutisso@7658 99 WorkerDataArray<size_t>* _thread_work_items;
brutisso@7658 100
brutisso@7658 101 NOT_PRODUCT(T uninitialized();)
brutisso@7658 102
brutisso@7658 103 // We are caching the sum and average to only have to calculate them once.
brutisso@7658 104 // This is not done in an MT-safe way. It is intended to allow single
brutisso@7658 105 // threaded code to call sum() and average() multiple times in any order
brutisso@7658 106 // without having to worry about the cost.
brutisso@7658 107 bool _has_new_data;
brutisso@7658 108 T _sum;
brutisso@7658 109 T _min;
brutisso@7658 110 T _max;
brutisso@7658 111 double _average;
brutisso@7658 112
brutisso@7658 113 public:
brutisso@7658 114 WorkerDataArray(uint length, const char* title, bool print_sum, int log_level, uint indent_level) :
brutisso@7658 115 _title(title), _length(0), _print_sum(print_sum), _log_level(log_level), _indent_level(indent_level),
brutisso@7658 116 _has_new_data(true), _thread_work_items(NULL), _enabled(true) {
brutisso@7658 117 assert(length > 0, "Must have some workers to store data for");
brutisso@7658 118 _length = length;
brutisso@7658 119 _data = NEW_C_HEAP_ARRAY(T, _length, mtGC);
aoqi@0 120 }
aoqi@0 121
brutisso@7658 122 ~WorkerDataArray() {
brutisso@7658 123 FREE_C_HEAP_ARRAY(T, _data, mtGC);
aoqi@0 124 }
aoqi@0 125
brutisso@7658 126 void link_thread_work_items(WorkerDataArray<size_t>* thread_work_items) {
brutisso@7658 127 _thread_work_items = thread_work_items;
aoqi@0 128 }
aoqi@0 129
brutisso@7658 130 WorkerDataArray<size_t>* thread_work_items() { return _thread_work_items; }
brutisso@7658 131
brutisso@7658 132 void set(uint worker_i, T value) {
brutisso@7658 133 assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length));
brutisso@7658 134 assert(_data[worker_i] == WorkerDataArray<T>::uninitialized(), err_msg("Overwriting data for worker %d in %s", worker_i, _title));
brutisso@7658 135 _data[worker_i] = value;
brutisso@7658 136 _has_new_data = true;
aoqi@0 137 }
brutisso@7658 138
brutisso@7658 139 void set_thread_work_item(uint worker_i, size_t value) {
brutisso@7658 140 assert(_thread_work_items != NULL, "No sub count");
brutisso@7658 141 _thread_work_items->set(worker_i, value);
brutisso@7658 142 }
brutisso@7658 143
brutisso@7658 144 T get(uint worker_i) {
brutisso@7658 145 assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length));
brutisso@7658 146 assert(_data[worker_i] != WorkerDataArray<T>::uninitialized(), err_msg("No data added for worker %d", worker_i));
brutisso@7658 147 return _data[worker_i];
brutisso@7658 148 }
brutisso@7658 149
brutisso@7658 150 void add(uint worker_i, T value) {
brutisso@7658 151 assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length));
brutisso@7658 152 assert(_data[worker_i] != WorkerDataArray<T>::uninitialized(), err_msg("No data to add to for worker %d", worker_i));
brutisso@7658 153 _data[worker_i] += value;
brutisso@7658 154 _has_new_data = true;
brutisso@7658 155 }
brutisso@7658 156
brutisso@7658 157 double average(){
brutisso@7658 158 calculate_totals();
brutisso@7658 159 return _average;
brutisso@7658 160 }
brutisso@7658 161
brutisso@7658 162 T sum() {
brutisso@7658 163 calculate_totals();
brutisso@7658 164 return _sum;
brutisso@7658 165 }
brutisso@7658 166
brutisso@7658 167 T minimum() {
brutisso@7658 168 calculate_totals();
brutisso@7658 169 return _min;
brutisso@7658 170 }
brutisso@7658 171
brutisso@7658 172 T maximum() {
brutisso@7658 173 calculate_totals();
brutisso@7658 174 return _max;
brutisso@7658 175 }
brutisso@7658 176
brutisso@7658 177 void reset() PRODUCT_RETURN;
brutisso@7658 178 void verify() PRODUCT_RETURN;
brutisso@7658 179
brutisso@7658 180 void set_enabled(bool enabled) { _enabled = enabled; }
brutisso@7658 181
brutisso@7658 182 int log_level() { return _log_level; }
brutisso@7658 183
brutisso@7658 184 private:
brutisso@7658 185
brutisso@7658 186 void calculate_totals(){
brutisso@7658 187 if (!_has_new_data) {
brutisso@7658 188 return;
brutisso@7658 189 }
brutisso@7658 190
brutisso@7658 191 _sum = (T)0;
brutisso@7658 192 _min = _data[0];
brutisso@7658 193 _max = _min;
brutisso@7658 194 for (uint i = 0; i < _length; ++i) {
brutisso@7658 195 T val = _data[i];
brutisso@7658 196 _sum += val;
brutisso@7658 197 _min = MIN2(_min, val);
brutisso@7658 198 _max = MAX2(_max, val);
brutisso@7658 199 }
brutisso@7658 200 _average = (double)_sum / (double)_length;
brutisso@7658 201 _has_new_data = false;
brutisso@7658 202 }
brutisso@7658 203 };
brutisso@7658 204
aoqi@0 205
aoqi@0 206 #ifndef PRODUCT
aoqi@0 207
brutisso@7658 208 template <>
brutisso@7658 209 size_t WorkerDataArray<size_t>::uninitialized() {
brutisso@7658 210 return (size_t)-1;
brutisso@7658 211 }
brutisso@7658 212
brutisso@7658 213 template <>
brutisso@7658 214 double WorkerDataArray<double>::uninitialized() {
brutisso@7658 215 return -1.0;
brutisso@7658 216 }
aoqi@0 217
aoqi@0 218 template <class T>
aoqi@0 219 void WorkerDataArray<T>::reset() {
aoqi@0 220 for (uint i = 0; i < _length; i++) {
brutisso@7658 221 _data[i] = WorkerDataArray<T>::uninitialized();
brutisso@7658 222 }
brutisso@7658 223 if (_thread_work_items != NULL) {
brutisso@7658 224 _thread_work_items->reset();
aoqi@0 225 }
aoqi@0 226 }
aoqi@0 227
aoqi@0 228 template <class T>
aoqi@0 229 void WorkerDataArray<T>::verify() {
brutisso@7658 230 if (!_enabled) {
brutisso@7658 231 return;
brutisso@7658 232 }
brutisso@7658 233
aoqi@0 234 for (uint i = 0; i < _length; i++) {
brutisso@7658 235 assert(_data[i] != WorkerDataArray<T>::uninitialized(),
brutisso@7658 236 err_msg("Invalid data for worker %u in '%s'", i, _title));
brutisso@7658 237 }
brutisso@7658 238 if (_thread_work_items != NULL) {
brutisso@7658 239 _thread_work_items->verify();
aoqi@0 240 }
aoqi@0 241 }
aoqi@0 242
aoqi@0 243 #endif
aoqi@0 244
aoqi@0 245 G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) :
brutisso@7658 246 _max_gc_threads(max_gc_threads)
aoqi@0 247 {
aoqi@0 248 assert(max_gc_threads > 0, "Must have some GC threads");
brutisso@7658 249
brutisso@7658 250 _gc_par_phases[GCWorkerStart] = new WorkerDataArray<double>(max_gc_threads, "GC Worker Start (ms)", false, G1Log::LevelFiner, 2);
brutisso@7658 251 _gc_par_phases[ExtRootScan] = new WorkerDataArray<double>(max_gc_threads, "Ext Root Scanning (ms)", true, G1Log::LevelFiner, 2);
brutisso@7660 252
brutisso@7660 253 // Root scanning phases
brutisso@7660 254 _gc_par_phases[ThreadRoots] = new WorkerDataArray<double>(max_gc_threads, "Thread Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 255 _gc_par_phases[StringTableRoots] = new WorkerDataArray<double>(max_gc_threads, "StringTable Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 256 _gc_par_phases[UniverseRoots] = new WorkerDataArray<double>(max_gc_threads, "Universe Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 257 _gc_par_phases[JNIRoots] = new WorkerDataArray<double>(max_gc_threads, "JNI Handles Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 258 _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray<double>(max_gc_threads, "ObjectSynchronizer Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 259 _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray<double>(max_gc_threads, "FlatProfiler Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 260 _gc_par_phases[ManagementRoots] = new WorkerDataArray<double>(max_gc_threads, "Management Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 261 _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray<double>(max_gc_threads, "SystemDictionary Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 262 _gc_par_phases[CLDGRoots] = new WorkerDataArray<double>(max_gc_threads, "CLDG Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 263 _gc_par_phases[JVMTIRoots] = new WorkerDataArray<double>(max_gc_threads, "JVMTI Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 264 _gc_par_phases[CodeCacheRoots] = new WorkerDataArray<double>(max_gc_threads, "CodeCache Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 265 _gc_par_phases[CMRefRoots] = new WorkerDataArray<double>(max_gc_threads, "CM RefProcessor Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 266 _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray<double>(max_gc_threads, "Wait For Strong CLD (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 267 _gc_par_phases[WeakCLDRoots] = new WorkerDataArray<double>(max_gc_threads, "Weak CLD Roots (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 268 _gc_par_phases[SATBFiltering] = new WorkerDataArray<double>(max_gc_threads, "SATB Filtering (ms)", true, G1Log::LevelFinest, 3);
brutisso@7660 269
brutisso@7658 270 _gc_par_phases[UpdateRS] = new WorkerDataArray<double>(max_gc_threads, "Update RS (ms)", true, G1Log::LevelFiner, 2);
brutisso@7658 271 _gc_par_phases[ScanRS] = new WorkerDataArray<double>(max_gc_threads, "Scan RS (ms)", true, G1Log::LevelFiner, 2);
brutisso@7658 272 _gc_par_phases[CodeRoots] = new WorkerDataArray<double>(max_gc_threads, "Code Root Scanning (ms)", true, G1Log::LevelFiner, 2);
brutisso@7658 273 _gc_par_phases[ObjCopy] = new WorkerDataArray<double>(max_gc_threads, "Object Copy (ms)", true, G1Log::LevelFiner, 2);
brutisso@7658 274 _gc_par_phases[Termination] = new WorkerDataArray<double>(max_gc_threads, "Termination (ms)", true, G1Log::LevelFiner, 2);
brutisso@7658 275 _gc_par_phases[GCWorkerTotal] = new WorkerDataArray<double>(max_gc_threads, "GC Worker Total (ms)", true, G1Log::LevelFiner, 2);
brutisso@7658 276 _gc_par_phases[GCWorkerEnd] = new WorkerDataArray<double>(max_gc_threads, "GC Worker End (ms)", false, G1Log::LevelFiner, 2);
brutisso@7658 277 _gc_par_phases[Other] = new WorkerDataArray<double>(max_gc_threads, "GC Worker Other (ms)", true, G1Log::LevelFiner, 2);
brutisso@7658 278
brutisso@7658 279 _update_rs_processed_buffers = new WorkerDataArray<size_t>(max_gc_threads, "Processed Buffers", true, G1Log::LevelFiner, 3);
brutisso@7658 280 _gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_processed_buffers);
brutisso@7658 281
brutisso@7658 282 _termination_attempts = new WorkerDataArray<size_t>(max_gc_threads, "Termination Attempts", true, G1Log::LevelFinest, 3);
brutisso@7658 283 _gc_par_phases[Termination]->link_thread_work_items(_termination_attempts);
brutisso@7658 284
brutisso@7658 285 _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray<double>(max_gc_threads, "Queue Fixup (ms)", true, G1Log::LevelFiner, 2);
brutisso@7658 286 _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray<double>(max_gc_threads, "Table Fixup (ms)", true, G1Log::LevelFiner, 2);
brutisso@7658 287
brutisso@7658 288 _gc_par_phases[RedirtyCards] = new WorkerDataArray<double>(max_gc_threads, "Parallel Redirty", true, G1Log::LevelFinest, 3);
brutisso@7658 289 _redirtied_cards = new WorkerDataArray<size_t>(max_gc_threads, "Redirtied Cards", true, G1Log::LevelFinest, 3);
brutisso@7658 290 _gc_par_phases[RedirtyCards]->link_thread_work_items(_redirtied_cards);
aoqi@0 291 }
aoqi@0 292
brutisso@7658 293 void G1GCPhaseTimes::note_gc_start(uint active_gc_threads, bool mark_in_progress) {
aoqi@0 294 assert(active_gc_threads > 0, "The number of threads must be > 0");
brutisso@7658 295 assert(active_gc_threads <= _max_gc_threads, "The number of active threads must be <= the max number of threads");
aoqi@0 296 _active_gc_threads = active_gc_threads;
aoqi@0 297
brutisso@7658 298 for (int i = 0; i < GCParPhasesSentinel; i++) {
brutisso@7658 299 _gc_par_phases[i]->reset();
brutisso@7658 300 }
tschatzl@6930 301
brutisso@7658 302 _gc_par_phases[StringDedupQueueFixup]->set_enabled(G1StringDedup::is_enabled());
brutisso@7658 303 _gc_par_phases[StringDedupTableFixup]->set_enabled(G1StringDedup::is_enabled());
aoqi@0 304 }
aoqi@0 305
aoqi@0 306 void G1GCPhaseTimes::note_gc_end() {
brutisso@7658 307 for (uint i = 0; i < _active_gc_threads; i++) {
brutisso@7658 308 double worker_time = _gc_par_phases[GCWorkerEnd]->get(i) - _gc_par_phases[GCWorkerStart]->get(i);
brutisso@7658 309 record_time_secs(GCWorkerTotal, i , worker_time);
aoqi@0 310
brutisso@7658 311 double worker_known_time =
brutisso@7658 312 _gc_par_phases[ExtRootScan]->get(i) +
brutisso@7658 313 _gc_par_phases[SATBFiltering]->get(i) +
brutisso@7658 314 _gc_par_phases[UpdateRS]->get(i) +
brutisso@7658 315 _gc_par_phases[ScanRS]->get(i) +
brutisso@7658 316 _gc_par_phases[CodeRoots]->get(i) +
brutisso@7658 317 _gc_par_phases[ObjCopy]->get(i) +
brutisso@7658 318 _gc_par_phases[Termination]->get(i);
aoqi@0 319
brutisso@7658 320 record_time_secs(Other, i, worker_time - worker_known_time);
aoqi@0 321 }
aoqi@0 322
brutisso@7658 323 for (int i = 0; i < GCParPhasesSentinel; i++) {
brutisso@7658 324 _gc_par_phases[i]->verify();
brutisso@7658 325 }
aoqi@0 326 }
aoqi@0 327
aoqi@0 328 void G1GCPhaseTimes::print_stats(int level, const char* str, double value) {
aoqi@0 329 LineBuffer(level).append_and_print_cr("[%s: %.1lf ms]", str, value);
aoqi@0 330 }
aoqi@0 331
tschatzl@7010 332 void G1GCPhaseTimes::print_stats(int level, const char* str, size_t value) {
tschatzl@7010 333 LineBuffer(level).append_and_print_cr("[%s: "SIZE_FORMAT"]", str, value);
tschatzl@7010 334 }
tschatzl@7010 335
aoqi@0 336 void G1GCPhaseTimes::print_stats(int level, const char* str, double value, uint workers) {
brutisso@7658 337 LineBuffer(level).append_and_print_cr("[%s: %.1lf ms, GC Workers: %u]", str, value, workers);
aoqi@0 338 }
aoqi@0 339
aoqi@0 340 double G1GCPhaseTimes::accounted_time_ms() {
aoqi@0 341 // Subtract the root region scanning wait time. It's initialized to
aoqi@0 342 // zero at the start of the pause.
aoqi@0 343 double misc_time_ms = _root_region_scan_wait_time_ms;
aoqi@0 344
aoqi@0 345 misc_time_ms += _cur_collection_par_time_ms;
aoqi@0 346
aoqi@0 347 // Now subtract the time taken to fix up roots in generated code
aoqi@0 348 misc_time_ms += _cur_collection_code_root_fixup_time_ms;
aoqi@0 349
aoqi@0 350 // Strong code root purge time
aoqi@0 351 misc_time_ms += _cur_strong_code_root_purge_time_ms;
aoqi@0 352
aoqi@0 353 if (G1StringDedup::is_enabled()) {
aoqi@0 354 // String dedup fixup time
aoqi@0 355 misc_time_ms += _cur_string_dedup_fixup_time_ms;
aoqi@0 356 }
aoqi@0 357
aoqi@0 358 // Subtract the time taken to clean the card table from the
aoqi@0 359 // current value of "other time"
aoqi@0 360 misc_time_ms += _cur_clear_ct_time_ms;
aoqi@0 361
aoqi@0 362 return misc_time_ms;
aoqi@0 363 }
aoqi@0 364
brutisso@7658 365 // record the time a phase took in seconds
brutisso@7658 366 void G1GCPhaseTimes::record_time_secs(GCParPhases phase, uint worker_i, double secs) {
brutisso@7658 367 _gc_par_phases[phase]->set(worker_i, secs);
brutisso@7658 368 }
brutisso@7658 369
brutisso@7658 370 // add a number of seconds to a phase
brutisso@7658 371 void G1GCPhaseTimes::add_time_secs(GCParPhases phase, uint worker_i, double secs) {
brutisso@7658 372 _gc_par_phases[phase]->add(worker_i, secs);
brutisso@7658 373 }
brutisso@7658 374
brutisso@7658 375 void G1GCPhaseTimes::record_thread_work_item(GCParPhases phase, uint worker_i, size_t count) {
brutisso@7658 376 _gc_par_phases[phase]->set_thread_work_item(worker_i, count);
brutisso@7658 377 }
brutisso@7658 378
brutisso@7658 379 // return the average time for a phase in milliseconds
brutisso@7658 380 double G1GCPhaseTimes::average_time_ms(GCParPhases phase) {
brutisso@7658 381 return _gc_par_phases[phase]->average() * 1000.0;
brutisso@7658 382 }
brutisso@7658 383
brutisso@7658 384 double G1GCPhaseTimes::get_time_ms(GCParPhases phase, uint worker_i) {
brutisso@7658 385 return _gc_par_phases[phase]->get(worker_i) * 1000.0;
brutisso@7658 386 }
brutisso@7658 387
brutisso@7658 388 double G1GCPhaseTimes::sum_time_ms(GCParPhases phase) {
brutisso@7658 389 return _gc_par_phases[phase]->sum() * 1000.0;
brutisso@7658 390 }
brutisso@7658 391
brutisso@7658 392 double G1GCPhaseTimes::min_time_ms(GCParPhases phase) {
brutisso@7658 393 return _gc_par_phases[phase]->minimum() * 1000.0;
brutisso@7658 394 }
brutisso@7658 395
brutisso@7658 396 double G1GCPhaseTimes::max_time_ms(GCParPhases phase) {
brutisso@7658 397 return _gc_par_phases[phase]->maximum() * 1000.0;
brutisso@7658 398 }
brutisso@7658 399
brutisso@7658 400 size_t G1GCPhaseTimes::get_thread_work_item(GCParPhases phase, uint worker_i) {
brutisso@7658 401 assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count");
brutisso@7658 402 return _gc_par_phases[phase]->thread_work_items()->get(worker_i);
brutisso@7658 403 }
brutisso@7658 404
brutisso@7658 405 size_t G1GCPhaseTimes::sum_thread_work_items(GCParPhases phase) {
brutisso@7658 406 assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count");
brutisso@7658 407 return _gc_par_phases[phase]->thread_work_items()->sum();
brutisso@7658 408 }
brutisso@7658 409
brutisso@7658 410 double G1GCPhaseTimes::average_thread_work_items(GCParPhases phase) {
brutisso@7658 411 assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count");
brutisso@7658 412 return _gc_par_phases[phase]->thread_work_items()->average();
brutisso@7658 413 }
brutisso@7658 414
brutisso@7658 415 size_t G1GCPhaseTimes::min_thread_work_items(GCParPhases phase) {
brutisso@7658 416 assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count");
brutisso@7658 417 return _gc_par_phases[phase]->thread_work_items()->minimum();
brutisso@7658 418 }
brutisso@7658 419
brutisso@7658 420 size_t G1GCPhaseTimes::max_thread_work_items(GCParPhases phase) {
brutisso@7658 421 assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count");
brutisso@7658 422 return _gc_par_phases[phase]->thread_work_items()->maximum();
brutisso@7658 423 }
brutisso@7658 424
brutisso@7658 425 class G1GCParPhasePrinter : public StackObj {
brutisso@7658 426 G1GCPhaseTimes* _phase_times;
brutisso@7658 427 public:
brutisso@7658 428 G1GCParPhasePrinter(G1GCPhaseTimes* phase_times) : _phase_times(phase_times) {}
brutisso@7658 429
brutisso@7658 430 void print(G1GCPhaseTimes::GCParPhases phase_id) {
brutisso@7658 431 WorkerDataArray<double>* phase = _phase_times->_gc_par_phases[phase_id];
brutisso@7658 432
brutisso@7658 433 if (phase->_log_level > G1Log::level() || !phase->_enabled) {
brutisso@7658 434 return;
brutisso@7658 435 }
brutisso@7658 436
brutisso@7658 437 if (phase->_length == 1) {
brutisso@7658 438 print_single_length(phase_id, phase);
brutisso@7658 439 } else {
brutisso@7658 440 print_multi_length(phase_id, phase);
brutisso@7658 441 }
brutisso@7658 442 }
brutisso@7658 443
brutisso@7658 444 private:
brutisso@7658 445
brutisso@7658 446 void print_single_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray<double>* phase) {
brutisso@7658 447 // No need for min, max, average and sum for only one worker
brutisso@7658 448 LineBuffer buf(phase->_indent_level);
brutisso@7658 449 buf.append_and_print_cr("[%s: %.1lf]", phase->_title, _phase_times->get_time_ms(phase_id, 0));
brutisso@7658 450
brutisso@7658 451 if (phase->_thread_work_items != NULL) {
brutisso@7658 452 LineBuffer buf2(phase->_thread_work_items->_indent_level);
brutisso@7658 453 buf2.append_and_print_cr("[%s: "SIZE_FORMAT"]", phase->_thread_work_items->_title, _phase_times->sum_thread_work_items(phase_id));
brutisso@7658 454 }
brutisso@7658 455 }
brutisso@7658 456
brutisso@7658 457 void print_time_values(LineBuffer& buf, G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray<double>* phase) {
brutisso@7658 458 for (uint i = 0; i < phase->_length; ++i) {
brutisso@7658 459 buf.append(" %.1lf", _phase_times->get_time_ms(phase_id, i));
brutisso@7658 460 }
brutisso@7658 461 buf.print_cr();
brutisso@7658 462 }
brutisso@7658 463
brutisso@7658 464 void print_count_values(LineBuffer& buf, G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray<size_t>* thread_work_items) {
brutisso@7658 465 for (uint i = 0; i < thread_work_items->_length; ++i) {
brutisso@7658 466 buf.append(" " SIZE_FORMAT, _phase_times->get_thread_work_item(phase_id, i));
brutisso@7658 467 }
brutisso@7658 468 buf.print_cr();
brutisso@7658 469 }
brutisso@7658 470
brutisso@7658 471 void print_thread_work_items(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray<size_t>* thread_work_items) {
brutisso@7658 472 LineBuffer buf(thread_work_items->_indent_level);
brutisso@7658 473 buf.append("[%s:", thread_work_items->_title);
brutisso@7658 474
brutisso@7658 475 if (G1Log::finest()) {
brutisso@7658 476 print_count_values(buf, phase_id, thread_work_items);
brutisso@7658 477 }
brutisso@7658 478
brutisso@7658 479 assert(thread_work_items->_print_sum, err_msg("%s does not have print sum true even though it is a count", thread_work_items->_title));
brutisso@7658 480
brutisso@7658 481 buf.append_and_print_cr(" Min: " SIZE_FORMAT ", Avg: %.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT ", Sum: " SIZE_FORMAT "]",
brutisso@7658 482 _phase_times->min_thread_work_items(phase_id), _phase_times->average_thread_work_items(phase_id), _phase_times->max_thread_work_items(phase_id),
brutisso@7658 483 _phase_times->max_thread_work_items(phase_id) - _phase_times->min_thread_work_items(phase_id), _phase_times->sum_thread_work_items(phase_id));
brutisso@7658 484 }
brutisso@7658 485
brutisso@7658 486 void print_multi_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray<double>* phase) {
brutisso@7658 487 LineBuffer buf(phase->_indent_level);
brutisso@7658 488 buf.append("[%s:", phase->_title);
brutisso@7658 489
brutisso@7658 490 if (G1Log::finest()) {
brutisso@7658 491 print_time_values(buf, phase_id, phase);
brutisso@7658 492 }
brutisso@7658 493
brutisso@7658 494 buf.append(" Min: %.1lf, Avg: %.1lf, Max: %.1lf, Diff: %.1lf",
brutisso@7658 495 _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id),
brutisso@7658 496 _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id));
brutisso@7658 497
brutisso@7658 498 if (phase->_print_sum) {
brutisso@7658 499 // for things like the start and end times the sum is not
brutisso@7658 500 // that relevant
brutisso@7658 501 buf.append(", Sum: %.1lf", _phase_times->sum_time_ms(phase_id));
brutisso@7658 502 }
brutisso@7658 503
brutisso@7658 504 buf.append_and_print_cr("]");
brutisso@7658 505
brutisso@7658 506 if (phase->_thread_work_items != NULL) {
brutisso@7658 507 print_thread_work_items(phase_id, phase->_thread_work_items);
brutisso@7658 508 }
brutisso@7658 509 }
brutisso@7658 510 };
brutisso@7658 511
aoqi@0 512 void G1GCPhaseTimes::print(double pause_time_sec) {
brutisso@7658 513 G1GCParPhasePrinter par_phase_printer(this);
brutisso@7658 514
aoqi@0 515 if (_root_region_scan_wait_time_ms > 0.0) {
aoqi@0 516 print_stats(1, "Root Region Scan Waiting", _root_region_scan_wait_time_ms);
aoqi@0 517 }
brutisso@7658 518
brutisso@7658 519 print_stats(1, "Parallel Time", _cur_collection_par_time_ms, _active_gc_threads);
brutisso@7658 520 for (int i = 0; i <= GCMainParPhasesLast; i++) {
brutisso@7658 521 par_phase_printer.print((GCParPhases) i);
aoqi@0 522 }
brutisso@7658 523
aoqi@0 524 print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms);
aoqi@0 525 print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms);
aoqi@0 526 if (G1StringDedup::is_enabled()) {
aoqi@0 527 print_stats(1, "String Dedup Fixup", _cur_string_dedup_fixup_time_ms, _active_gc_threads);
brutisso@7658 528 for (int i = StringDedupPhasesFirst; i <= StringDedupPhasesLast; i++) {
brutisso@7658 529 par_phase_printer.print((GCParPhases) i);
brutisso@7658 530 }
aoqi@0 531 }
aoqi@0 532 print_stats(1, "Clear CT", _cur_clear_ct_time_ms);
aoqi@0 533 double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms();
aoqi@0 534 print_stats(1, "Other", misc_time_ms);
aoqi@0 535 if (_cur_verify_before_time_ms > 0.0) {
aoqi@0 536 print_stats(2, "Verify Before", _cur_verify_before_time_ms);
aoqi@0 537 }
aoqi@0 538 if (G1CollectedHeap::heap()->evacuation_failed()) {
aoqi@0 539 double evac_fail_handling = _cur_evac_fail_recalc_used + _cur_evac_fail_remove_self_forwards +
aoqi@0 540 _cur_evac_fail_restore_remsets;
aoqi@0 541 print_stats(2, "Evacuation Failure", evac_fail_handling);
aoqi@0 542 if (G1Log::finest()) {
aoqi@0 543 print_stats(3, "Recalculate Used", _cur_evac_fail_recalc_used);
aoqi@0 544 print_stats(3, "Remove Self Forwards", _cur_evac_fail_remove_self_forwards);
aoqi@0 545 print_stats(3, "Restore RemSet", _cur_evac_fail_restore_remsets);
aoqi@0 546 }
aoqi@0 547 }
aoqi@0 548 print_stats(2, "Choose CSet",
aoqi@0 549 (_recorded_young_cset_choice_time_ms +
aoqi@0 550 _recorded_non_young_cset_choice_time_ms));
aoqi@0 551 print_stats(2, "Ref Proc", _cur_ref_proc_time_ms);
aoqi@0 552 print_stats(2, "Ref Enq", _cur_ref_enq_time_ms);
tschatzl@7218 553 print_stats(2, "Redirty Cards", _recorded_redirty_logged_cards_time_ms);
brutisso@7658 554 par_phase_printer.print(RedirtyCards);
tschatzl@7828 555
tschatzl@7828 556 if (G1EagerReclaimHumongousObjects) {
tschatzl@7828 557 print_stats(2, "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms);
tschatzl@7010 558 if (G1Log::finest()) {
tschatzl@7010 559 print_stats(3, "Humongous Total", _cur_fast_reclaim_humongous_total);
tschatzl@7010 560 print_stats(3, "Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
tschatzl@7828 561 }
tschatzl@7828 562 print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
tschatzl@7828 563 if (G1Log::finest()) {
tschatzl@7010 564 print_stats(3, "Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed);
tschatzl@7010 565 }
aoqi@0 566 }
aoqi@0 567 print_stats(2, "Free CSet",
aoqi@0 568 (_recorded_young_free_cset_time_ms +
aoqi@0 569 _recorded_non_young_free_cset_time_ms));
aoqi@0 570 if (G1Log::finest()) {
aoqi@0 571 print_stats(3, "Young Free CSet", _recorded_young_free_cset_time_ms);
aoqi@0 572 print_stats(3, "Non-Young Free CSet", _recorded_non_young_free_cset_time_ms);
aoqi@0 573 }
aoqi@0 574 if (_cur_verify_after_time_ms > 0.0) {
aoqi@0 575 print_stats(2, "Verify After", _cur_verify_after_time_ms);
aoqi@0 576 }
aoqi@0 577 }
brutisso@7658 578
brutisso@7658 579 G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times, G1GCPhaseTimes::GCParPhases phase, uint worker_id) :
brutisso@7658 580 _phase_times(phase_times), _phase(phase), _worker_id(worker_id) {
brutisso@7658 581 if (_phase_times != NULL) {
brutisso@7658 582 _start_time = os::elapsedTime();
brutisso@7658 583 }
brutisso@7658 584 }
brutisso@7658 585
brutisso@7658 586 G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() {
brutisso@7658 587 if (_phase_times != NULL) {
brutisso@7658 588 _phase_times->record_time_secs(_phase, _worker_id, os::elapsedTime() - _start_time);
brutisso@7658 589 }
brutisso@7658 590 }
brutisso@7658 591

mercurial