1 /* 2 * Copyright (c) 2017, 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 #include "precompiled.hpp" 26 #include "gc/shared/gcTimer.hpp" 27 #include "gc/shared/referenceProcessorPhaseTimes.hpp" 28 #include "gc/shared/referenceProcessor.inline.hpp" 29 #include "logging/log.hpp" 30 31 RefProcWorkerTimeTracker::RefProcWorkerTimeTracker(WorkerDataArray<double>* worker_time, uint worker_id) : 32 _worker_time(worker_time), _start_time(0.0), _worker_id(worker_id) { 33 if (_worker_time != NULL) { 34 _start_time = os::elapsedTime(); 35 } 36 } 37 38 RefProcWorkerTimeTracker::~RefProcWorkerTimeTracker() { 39 if (_worker_time != NULL) { 40 _worker_time->set(_worker_id, os::elapsedTime() - _start_time); 41 } 42 } 43 44 static size_t total_count_from_list(DiscoveredList lists[], uint max_num_q) { 45 size_t total = 0; 46 for (uint i = 0; i < max_num_q; ++i) { 47 total += lists[i].length(); 48 } 49 return total; 50 } 51 52 RefProcPhaseTimeBaseTracker::RefProcPhaseTimeBaseTracker(const char* title, 53 ReferenceProcessorPhaseTimes* phase_times, 54 GCTimer* gc_timer) : 55 _title(title), _phase_times(phase_times), _start_ticks(), _end_ticks(), _gc_timer(gc_timer) { 56 assert(_phase_times != NULL, "Invariant"); 57 58 _start_ticks.stamp(); 59 if (_gc_timer != NULL) { 60 _gc_timer->register_gc_phase_start(_title, _start_ticks); 61 } 62 } 63 64 static const char* phase_enum_2_string(ReferenceProcessorPhaseTimes::RefProcPhases phase) { 65 switch(phase) { 66 case ReferenceProcessorPhaseTimes::RefPhase1: 67 return "Phase1"; 68 case ReferenceProcessorPhaseTimes::RefPhase2: 69 return "Phase2"; 70 case ReferenceProcessorPhaseTimes::RefPhase3: 71 return "Phase3"; 72 case ReferenceProcessorPhaseTimes::RefEnqueue: 73 return "Enqueue reference lists"; 74 default: 75 ShouldNotReachHere(); 76 return NULL; 77 } 78 } 79 80 static const char* Indents[5] = {"", " ", " ", " ", " "}; 81 82 void RefProcPhaseTimeBaseTracker::print_phase(ReferenceProcessorPhaseTimes::RefProcPhases phase, uint indent) { 83 double phase_time = phase_times()->phase_time_ms(phase); 84 if (phase_time != ReferenceProcessorPhaseTimes::uninitialized()) { 85 Log(gc, ref) log; 86 87 log.debug_stream()->print_cr("%s%s%s %0.3fms", 88 Indents[indent], 89 phase_enum_2_string(phase), 90 indent == 0 ? "" : ":", /* 0 indent logs don't need colon. */ 91 phase_time); 92 if (phase_times()->processing_is_mt() && log.is_level(LogLevel::Trace)) { 93 outputStream* out = log.trace_stream(); 94 95 out->print("%s", Indents[2]); 96 // worker_time_sec is recorded in seconds but it will be printed in milliseconds. 97 phase_times()->worker_time_sec(phase)->print_summary_on(out, true); 98 } 99 } 100 } 101 102 Ticks RefProcPhaseTimeBaseTracker::end_ticks() { 103 // If ASSERT is defined, the default value of Ticks will be -2. 104 if (_end_ticks.value() <= 0) { 105 _end_ticks.stamp(); 106 } 107 108 return _end_ticks; 109 } 110 111 double RefProcPhaseTimeBaseTracker::elapsed_time() { 112 jlong end_value = end_ticks().value(); 113 114 return TimeHelper::counter_to_millis(end_value - _start_ticks.value()); 115 } 116 117 RefProcPhaseTimeBaseTracker::~RefProcPhaseTimeBaseTracker() { 118 if (_gc_timer != NULL) { 119 Ticks ticks = end_ticks(); 120 _gc_timer->register_gc_phase_end(ticks); 121 } 122 } 123 124 RefProcBalanceQueuesTimeTracker::RefProcBalanceQueuesTimeTracker(ReferenceProcessorPhaseTimes* phase_times, 125 GCTimer* gc_timer) : 126 RefProcPhaseTimeBaseTracker("Balance queues", phase_times, gc_timer) {} 127 128 RefProcBalanceQueuesTimeTracker::~RefProcBalanceQueuesTimeTracker() { 129 double elapsed = elapsed_time(); 130 phase_times()->set_balance_queues_time_ms(elapsed); 131 } 132 133 RefProcPhaseTimeTracker::RefProcPhaseTimeTracker(ReferenceProcessorPhaseTimes::RefProcPhases phase, 134 ReferenceProcessorPhaseTimes* phase_times, 135 GCTimer* gc_timer) : 136 _phase(phase), RefProcPhaseTimeBaseTracker(phase_enum_2_string(phase), phase_times, gc_timer) {} 137 138 RefProcPhaseTimeTracker::~RefProcPhaseTimeTracker() { 139 double elapsed = elapsed_time(); 140 phase_times()->set_phase_time_ms(_phase, elapsed); 141 } 142 143 RefProcPhaseTimesLogger::RefProcPhaseTimesLogger(const char* title, 144 ReferenceProcessorPhaseTimes* times, 145 DiscoveredList lists[], 146 GCTimer* gc_timer) : 147 _lists(lists), RefProcPhaseTimeBaseTracker(title, times, gc_timer) { 148 _ref_discovered = total_count_from_list(_lists, phase_times()->max_gc_threads()); 149 } 150 151 RefProcPhaseTimesLogger::~RefProcPhaseTimesLogger() { 152 double elapsed = elapsed_time(); 153 154 Log(gc, ref) log; 155 156 if (log.is_level(LogLevel::Debug)) { 157 outputStream* out = log.debug_stream(); 158 ResourceMark rm; 159 160 out->print_cr("%s %0.3fms", _title, elapsed); 161 162 double balance_time = phase_times()->balance_queues_time_ms(); 163 if (balance_time != ReferenceProcessorPhaseTimes::uninitialized()) { 164 out->print_cr(" %s %0.3fms", "Balance queues:", balance_time); 165 } 166 167 // Print stats 168 print_phase(ReferenceProcessorPhaseTimes::RefPhase1, 1); 169 print_phase(ReferenceProcessorPhaseTimes::RefPhase2, 1); 170 print_phase(ReferenceProcessorPhaseTimes::RefPhase3, 1); 171 172 size_t after_count = total_count_from_list(_lists, phase_times()->max_gc_threads()); 173 out->print_cr(" %s " SIZE_FORMAT, "Cleared:", _ref_discovered - after_count); 174 out->print_cr(" %s " SIZE_FORMAT, "Discovered:", _ref_discovered); 175 } 176 177 // Reset for next use. 178 phase_times()->reset(); 179 } 180 181 RefProcEnqueueTimeLogger::RefProcEnqueueTimeLogger(ReferenceProcessorPhaseTimes* phase_times, 182 ReferenceProcessorStats& stats, 183 GCTimer* gc_timer) : 184 _stats(stats), RefProcPhaseTimeBaseTracker("Enqueue reference lists", phase_times, gc_timer) {} 185 186 RefProcEnqueueTimeLogger::~RefProcEnqueueTimeLogger() { 187 double elapsed = elapsed_time(); 188 189 phase_times()->set_phase_time_ms(ReferenceProcessorPhaseTimes::RefEnqueue, elapsed); 190 191 print_phase(ReferenceProcessorPhaseTimes::RefEnqueue, 0); 192 phase_times()->reset(); 193 194 log_debug(gc, ref)(" Ref Counts: Soft: " SIZE_FORMAT " Weak: " SIZE_FORMAT 195 " Final: " SIZE_FORMAT " Phantom: " SIZE_FORMAT , 196 _stats.soft_count(), _stats.weak_count(), 197 _stats.final_count(), _stats.phantom_count()); 198 } 199 200 ReferenceProcessorPhaseTimes::ReferenceProcessorPhaseTimes(uint max_gc_threads, bool processing_is_mt) : 201 _balance_queues_time_ms(uninitialized()), _max_gc_threads(max_gc_threads), _processing_is_mt(processing_is_mt) { 202 203 _worker_time_sec[RefPhase1] = new WorkerDataArray<double>(_max_gc_threads, "Process lists (ms)"); 204 _worker_time_sec[RefPhase2] = new WorkerDataArray<double>(_max_gc_threads, "Process lists (ms)"); 205 _worker_time_sec[RefPhase3] = new WorkerDataArray<double>(_max_gc_threads, "Process lists (ms)"); 206 _worker_time_sec[RefEnqueue] = new WorkerDataArray<double>(_max_gc_threads, "Process lists (ms)"); 207 208 _phase_time_ms[RefPhase1] = uninitialized(); 209 _phase_time_ms[RefPhase2] = uninitialized(); 210 _phase_time_ms[RefPhase3] = uninitialized(); 211 _phase_time_ms[RefEnqueue] = uninitialized(); 212 } 213 214 WorkerDataArray<double>* ReferenceProcessorPhaseTimes::worker_time_sec(RefProcPhases phase) const { 215 assert(phase >= RefPhase1 && phase < RefPhaseMax, "Invariant"); 216 return _worker_time_sec[phase]; 217 } 218 219 double ReferenceProcessorPhaseTimes::phase_time_ms(RefProcPhases phase) const { 220 assert(phase >= RefPhase1 && phase < RefPhaseMax, "Invariant"); 221 return _phase_time_ms[phase]; 222 } 223 224 void ReferenceProcessorPhaseTimes::set_phase_time_ms(RefProcPhases phase, double phase_time_ms) { 225 assert(phase >= RefPhase1 && phase < RefPhaseMax, "Invariant"); 226 _phase_time_ms[phase] = phase_time_ms; 227 } 228 229 void ReferenceProcessorPhaseTimes::reset() { 230 for (int i = 0; i < RefPhaseMax; i++) { 231 _worker_time_sec[i]->reset(); 232 _phase_time_ms[i] = uninitialized(); 233 } 234 235 _balance_queues_time_ms = uninitialized(); 236 237 _processing_is_mt = false; 238 } 239