1 /*
2 * Copyright (c) 2012, 2018, 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 "utilities/growableArray.hpp"
28
29 // the "time" parameter for most functions
30 // has a default value set by Ticks::now()
31
register_gc_start(const Ticks & time)32 void GCTimer::register_gc_start(const Ticks& time) {
33 _time_partitions.clear();
34 _gc_start = time;
35 }
36
register_gc_end(const Ticks & time)37 void GCTimer::register_gc_end(const Ticks& time) {
38 assert(!_time_partitions.has_active_phases(),
39 "We should have ended all started phases, before ending the GC");
40
41 _gc_end = time;
42 }
43
register_gc_pause_start(const char * name,const Ticks & time)44 void GCTimer::register_gc_pause_start(const char* name, const Ticks& time) {
45 _time_partitions.report_gc_phase_start_top_level(name, time, GCPhase::PausePhaseType);
46 }
47
register_gc_pause_end(const Ticks & time)48 void GCTimer::register_gc_pause_end(const Ticks& time) {
49 _time_partitions.report_gc_phase_end(time);
50 }
51
register_gc_phase_start(const char * name,const Ticks & time)52 void GCTimer::register_gc_phase_start(const char* name, const Ticks& time) {
53 _time_partitions.report_gc_phase_start_sub_phase(name, time);
54 }
55
register_gc_phase_end(const Ticks & time)56 void GCTimer::register_gc_phase_end(const Ticks& time) {
57 _time_partitions.report_gc_phase_end(time);
58 }
59
register_gc_start(const Ticks & time)60 void STWGCTimer::register_gc_start(const Ticks& time) {
61 GCTimer::register_gc_start(time);
62 register_gc_pause_start("GC Pause", time);
63 }
64
register_gc_end(const Ticks & time)65 void STWGCTimer::register_gc_end(const Ticks& time) {
66 register_gc_pause_end(time);
67 GCTimer::register_gc_end(time);
68 }
69
register_gc_concurrent_start(const char * name,const Ticks & time)70 void ConcurrentGCTimer::register_gc_concurrent_start(const char* name, const Ticks& time) {
71 _time_partitions.report_gc_phase_start_top_level(name, time, GCPhase::ConcurrentPhaseType);
72 }
73
register_gc_concurrent_end(const Ticks & time)74 void ConcurrentGCTimer::register_gc_concurrent_end(const Ticks& time) {
75 _time_partitions.report_gc_phase_end(time);
76 }
77
clear()78 void PhasesStack::clear() {
79 _next_phase_level = 0;
80 }
81
push(int phase_index)82 void PhasesStack::push(int phase_index) {
83 assert(_next_phase_level < PHASE_LEVELS, "Overflow");
84
85 _phase_indices[_next_phase_level] = phase_index;
86 _next_phase_level++;
87 }
88
pop()89 int PhasesStack::pop() {
90 assert(_next_phase_level > 0, "Underflow");
91
92 _next_phase_level--;
93 return _phase_indices[_next_phase_level];
94 }
95
count() const96 int PhasesStack::count() const {
97 return _next_phase_level;
98 }
99
phase_index(int level) const100 int PhasesStack::phase_index(int level) const {
101 assert(level < count(), "Out-of-bounds");
102 return _phase_indices[level];
103 }
104
current_phase_type() const105 GCPhase::PhaseType TimePartitions::current_phase_type() const {
106 int level = _active_phases.count();
107 assert(level > 0, "No active phase");
108
109 int index = _active_phases.phase_index(level - 1);
110 GCPhase phase = _phases->at(index);
111 GCPhase::PhaseType type = phase.type();
112 return type;
113 }
114
TimePartitions()115 TimePartitions::TimePartitions() {
116 _phases = new (ResourceObj::C_HEAP, mtGC) GrowableArray<GCPhase>(INITIAL_CAPACITY, mtGC);
117 clear();
118 }
119
~TimePartitions()120 TimePartitions::~TimePartitions() {
121 delete _phases;
122 _phases = NULL;
123 }
124
clear()125 void TimePartitions::clear() {
126 _phases->clear();
127 _active_phases.clear();
128 _sum_of_pauses = Tickspan();
129 _longest_pause = Tickspan();
130 }
131
report_gc_phase_start(const char * name,const Ticks & time,GCPhase::PhaseType type)132 void TimePartitions::report_gc_phase_start(const char* name, const Ticks& time, GCPhase::PhaseType type) {
133 assert(_phases->length() <= 1000, "Too many recored phases?");
134
135 int level = _active_phases.count();
136
137 GCPhase phase;
138 phase.set_type(type);
139 phase.set_level(level);
140 phase.set_name(name);
141 phase.set_start(time);
142
143 int index = _phases->append(phase);
144
145 _active_phases.push(index);
146 }
147
report_gc_phase_start_top_level(const char * name,const Ticks & time,GCPhase::PhaseType type)148 void TimePartitions::report_gc_phase_start_top_level(const char* name, const Ticks& time, GCPhase::PhaseType type) {
149 int level = _active_phases.count();
150 assert(level == 0, "Must be a top-level phase");
151
152 report_gc_phase_start(name, time, type);
153 }
154
report_gc_phase_start_sub_phase(const char * name,const Ticks & time)155 void TimePartitions::report_gc_phase_start_sub_phase(const char* name, const Ticks& time) {
156 int level = _active_phases.count();
157 assert(level > 0, "Must be a sub-phase");
158
159 // Inherit phase type from parent phase.
160 GCPhase::PhaseType type = current_phase_type();
161
162 report_gc_phase_start(name, time, type);
163 }
164
update_statistics(GCPhase * phase)165 void TimePartitions::update_statistics(GCPhase* phase) {
166 if ((phase->type() == GCPhase::PausePhaseType) && (phase->level() == 0)) {
167 const Tickspan pause = phase->end() - phase->start();
168 _sum_of_pauses += pause;
169 _longest_pause = MAX2(pause, _longest_pause);
170 }
171 }
172
report_gc_phase_end(const Ticks & time)173 void TimePartitions::report_gc_phase_end(const Ticks& time) {
174 int phase_index = _active_phases.pop();
175 GCPhase* phase = _phases->adr_at(phase_index);
176 phase->set_end(time);
177 update_statistics(phase);
178 }
179
num_phases() const180 int TimePartitions::num_phases() const {
181 return _phases->length();
182 }
183
phase_at(int index) const184 GCPhase* TimePartitions::phase_at(int index) const {
185 assert(index >= 0, "Out of bounds");
186 assert(index < _phases->length(), "Out of bounds");
187
188 return _phases->adr_at(index);
189 }
190
has_active_phases()191 bool TimePartitions::has_active_phases() {
192 return _active_phases.count() > 0;
193 }
194
has_next()195 bool TimePartitionPhasesIterator::has_next() {
196 return _next < _time_partitions->num_phases();
197 }
198
next()199 GCPhase* TimePartitionPhasesIterator::next() {
200 assert(has_next(), "Must have phases left");
201 return _time_partitions->phase_at(_next++);
202 }
203