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 | |
32 | void GCTimer::register_gc_start(const Ticks& time) { |
33 | _time_partitions.clear(); |
34 | _gc_start = time; |
35 | } |
36 | |
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 | |
44 | void GCTimer::register_gc_pause_start(const char* name, const Ticks& time) { |
45 | _time_partitions.report_gc_phase_start(name, time); |
46 | } |
47 | |
48 | void GCTimer::register_gc_pause_end(const Ticks& time) { |
49 | _time_partitions.report_gc_phase_end(time); |
50 | } |
51 | |
52 | void GCTimer::register_gc_phase_start(const char* name, const Ticks& time) { |
53 | _time_partitions.report_gc_phase_start(name, time); |
54 | } |
55 | |
56 | void GCTimer::register_gc_phase_end(const Ticks& time) { |
57 | _time_partitions.report_gc_phase_end(time); |
58 | } |
59 | |
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 | |
65 | void STWGCTimer::register_gc_end(const Ticks& time) { |
66 | register_gc_pause_end(time); |
67 | GCTimer::register_gc_end(time); |
68 | } |
69 | |
70 | void ConcurrentGCTimer::register_gc_pause_start(const char* name, const Ticks& time) { |
71 | assert(!_is_concurrent_phase_active, "A pause phase can't be started while a concurrent phase is active." ); |
72 | GCTimer::register_gc_pause_start(name, time); |
73 | } |
74 | |
75 | void ConcurrentGCTimer::register_gc_pause_end(const Ticks& time) { |
76 | assert(!_is_concurrent_phase_active, "A pause phase can't be ended while a concurrent phase is active." ); |
77 | GCTimer::register_gc_pause_end(time); |
78 | } |
79 | |
80 | void ConcurrentGCTimer::register_gc_concurrent_start(const char* name, const Ticks& time) { |
81 | assert(!_is_concurrent_phase_active, "A concurrent phase is already active." ); |
82 | _time_partitions.report_gc_phase_start(name, time, GCPhase::ConcurrentPhaseType); |
83 | _is_concurrent_phase_active = true; |
84 | } |
85 | |
86 | void ConcurrentGCTimer::register_gc_concurrent_end(const Ticks& time) { |
87 | assert(_is_concurrent_phase_active, "A concurrent phase is not active." ); |
88 | _time_partitions.report_gc_phase_end(time, GCPhase::ConcurrentPhaseType); |
89 | _is_concurrent_phase_active = false; |
90 | } |
91 | |
92 | void PhasesStack::clear() { |
93 | _next_phase_level = 0; |
94 | } |
95 | |
96 | void PhasesStack::push(int phase_index) { |
97 | assert(_next_phase_level < PHASE_LEVELS, "Overflow" ); |
98 | |
99 | _phase_indices[_next_phase_level] = phase_index; |
100 | _next_phase_level++; |
101 | } |
102 | |
103 | int PhasesStack::pop() { |
104 | assert(_next_phase_level > 0, "Underflow" ); |
105 | |
106 | _next_phase_level--; |
107 | return _phase_indices[_next_phase_level]; |
108 | } |
109 | |
110 | int PhasesStack::count() const { |
111 | return _next_phase_level; |
112 | } |
113 | |
114 | TimePartitions::TimePartitions() { |
115 | _phases = new (ResourceObj::C_HEAP, mtGC) GrowableArray<GCPhase>(INITIAL_CAPACITY, true, mtGC); |
116 | clear(); |
117 | } |
118 | |
119 | TimePartitions::~TimePartitions() { |
120 | delete _phases; |
121 | _phases = NULL; |
122 | } |
123 | |
124 | void TimePartitions::clear() { |
125 | _phases->clear(); |
126 | _active_phases.clear(); |
127 | _sum_of_pauses = Tickspan(); |
128 | _longest_pause = Tickspan(); |
129 | } |
130 | |
131 | void TimePartitions::report_gc_phase_start(const char* name, const Ticks& time, GCPhase::PhaseType type) { |
132 | assert(_phases->length() <= 1000, "Too many recored phases?" ); |
133 | |
134 | int level = _active_phases.count(); |
135 | |
136 | GCPhase phase; |
137 | phase.set_type(type); |
138 | phase.set_level(level); |
139 | phase.set_name(name); |
140 | phase.set_start(time); |
141 | |
142 | int index = _phases->append(phase); |
143 | |
144 | _active_phases.push(index); |
145 | } |
146 | |
147 | void TimePartitions::update_statistics(GCPhase* phase) { |
148 | if ((phase->type() == GCPhase::PausePhaseType) && (phase->level() == 0)) { |
149 | const Tickspan pause = phase->end() - phase->start(); |
150 | _sum_of_pauses += pause; |
151 | _longest_pause = MAX2(pause, _longest_pause); |
152 | } |
153 | } |
154 | |
155 | void TimePartitions::report_gc_phase_end(const Ticks& time, GCPhase::PhaseType type) { |
156 | int phase_index = _active_phases.pop(); |
157 | GCPhase* phase = _phases->adr_at(phase_index); |
158 | phase->set_end(time); |
159 | update_statistics(phase); |
160 | } |
161 | |
162 | int TimePartitions::num_phases() const { |
163 | return _phases->length(); |
164 | } |
165 | |
166 | GCPhase* TimePartitions::phase_at(int index) const { |
167 | assert(index >= 0, "Out of bounds" ); |
168 | assert(index < _phases->length(), "Out of bounds" ); |
169 | |
170 | return _phases->adr_at(index); |
171 | } |
172 | |
173 | bool TimePartitions::has_active_phases() { |
174 | return _active_phases.count() > 0; |
175 | } |
176 | |
177 | bool TimePartitionPhasesIterator::has_next() { |
178 | return _next < _time_partitions->num_phases(); |
179 | } |
180 | |
181 | GCPhase* TimePartitionPhasesIterator::next() { |
182 | assert(has_next(), "Must have phases left" ); |
183 | return _time_partitions->phase_at(_next++); |
184 | } |
185 | |