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