src/share/vm/gc_implementation/shared/gcTimer.cpp

changeset 0
f90c822e73f8
child 6876
710a3c8b516e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/gc_implementation/shared/gcTimer.cpp	Wed Apr 27 01:25:04 2016 +0800
     1.3 @@ -0,0 +1,369 @@
     1.4 +/*
     1.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +#include "precompiled.hpp"
    1.29 +#include "gc_implementation/shared/gcTimer.hpp"
    1.30 +#include "utilities/growableArray.hpp"
    1.31 +#include "utilities/ticks.inline.hpp"
    1.32 +
    1.33 +// the "time" parameter for most functions
    1.34 +// has a default value set by Ticks::now()
    1.35 +
    1.36 +void GCTimer::register_gc_start(const Ticks& time) {
    1.37 +  _time_partitions.clear();
    1.38 +  _gc_start = time;
    1.39 +}
    1.40 +
    1.41 +void GCTimer::register_gc_end(const Ticks& time) {
    1.42 +  assert(!_time_partitions.has_active_phases(),
    1.43 +      "We should have ended all started phases, before ending the GC");
    1.44 +
    1.45 +  _gc_end = time;
    1.46 +}
    1.47 +
    1.48 +void GCTimer::register_gc_pause_start(const char* name, const Ticks& time) {
    1.49 +  _time_partitions.report_gc_phase_start(name, time);
    1.50 +}
    1.51 +
    1.52 +void GCTimer::register_gc_pause_end(const Ticks& time) {
    1.53 +  _time_partitions.report_gc_phase_end(time);
    1.54 +}
    1.55 +
    1.56 +void GCTimer::register_gc_phase_start(const char* name, const Ticks& time) {
    1.57 +  _time_partitions.report_gc_phase_start(name, time);
    1.58 +}
    1.59 +
    1.60 +void GCTimer::register_gc_phase_end(const Ticks& time) {
    1.61 +  _time_partitions.report_gc_phase_end(time);
    1.62 +}
    1.63 +
    1.64 +void STWGCTimer::register_gc_start(const Ticks& time) {
    1.65 +  GCTimer::register_gc_start(time);
    1.66 +  register_gc_pause_start("GC Pause", time);
    1.67 +}
    1.68 +
    1.69 +void STWGCTimer::register_gc_end(const Ticks& time) {
    1.70 +  register_gc_pause_end(time);
    1.71 +  GCTimer::register_gc_end(time);
    1.72 +}
    1.73 +
    1.74 +void ConcurrentGCTimer::register_gc_pause_start(const char* name) {
    1.75 +  GCTimer::register_gc_pause_start(name);
    1.76 +}
    1.77 +
    1.78 +void ConcurrentGCTimer::register_gc_pause_end() {
    1.79 +  GCTimer::register_gc_pause_end();
    1.80 +}
    1.81 +
    1.82 +void PhasesStack::clear() {
    1.83 +  _next_phase_level = 0;
    1.84 +}
    1.85 +
    1.86 +void PhasesStack::push(int phase_index) {
    1.87 +  assert(_next_phase_level < PHASE_LEVELS, "Overflow");
    1.88 +
    1.89 +  _phase_indices[_next_phase_level] = phase_index;
    1.90 +
    1.91 +  _next_phase_level++;
    1.92 +}
    1.93 +
    1.94 +int PhasesStack::pop() {
    1.95 +  assert(_next_phase_level > 0, "Underflow");
    1.96 +
    1.97 +  _next_phase_level--;
    1.98 +
    1.99 +  return _phase_indices[_next_phase_level];
   1.100 +}
   1.101 +
   1.102 +int PhasesStack::count() const {
   1.103 +  return _next_phase_level;
   1.104 +}
   1.105 +
   1.106 +
   1.107 +TimePartitions::TimePartitions() {
   1.108 +  _phases = new (ResourceObj::C_HEAP, mtGC) GrowableArray<PausePhase>(INITIAL_CAPACITY, true, mtGC);
   1.109 +  clear();
   1.110 +}
   1.111 +
   1.112 +TimePartitions::~TimePartitions() {
   1.113 +  delete _phases;
   1.114 +  _phases = NULL;
   1.115 +}
   1.116 +
   1.117 +void TimePartitions::clear() {
   1.118 +  _phases->clear();
   1.119 +  _active_phases.clear();
   1.120 +  _sum_of_pauses = Tickspan();
   1.121 +  _longest_pause = Tickspan();
   1.122 +}
   1.123 +
   1.124 +void TimePartitions::report_gc_phase_start(const char* name, const Ticks& time) {
   1.125 +  assert(_phases->length() <= 1000, "Too many recored phases?");
   1.126 +
   1.127 +  int level = _active_phases.count();
   1.128 +
   1.129 +  PausePhase phase;
   1.130 +  phase.set_level(level);
   1.131 +  phase.set_name(name);
   1.132 +  phase.set_start(time);
   1.133 +
   1.134 +  int index = _phases->append(phase);
   1.135 +
   1.136 +  _active_phases.push(index);
   1.137 +}
   1.138 +
   1.139 +void TimePartitions::update_statistics(GCPhase* phase) {
   1.140 +  // FIXME: This should only be done for pause phases
   1.141 +  if (phase->level() == 0) {
   1.142 +    const Tickspan pause = phase->end() - phase->start();
   1.143 +    _sum_of_pauses += pause;
   1.144 +    _longest_pause = MAX2(pause, _longest_pause);
   1.145 +  }
   1.146 +}
   1.147 +
   1.148 +void TimePartitions::report_gc_phase_end(const Ticks& time) {
   1.149 +  int phase_index = _active_phases.pop();
   1.150 +  GCPhase* phase = _phases->adr_at(phase_index);
   1.151 +  phase->set_end(time);
   1.152 +  update_statistics(phase);
   1.153 +}
   1.154 +
   1.155 +int TimePartitions::num_phases() const {
   1.156 +  return _phases->length();
   1.157 +}
   1.158 +
   1.159 +GCPhase* TimePartitions::phase_at(int index) const {
   1.160 +  assert(index >= 0, "Out of bounds");
   1.161 +  assert(index < _phases->length(), "Out of bounds");
   1.162 +
   1.163 +  return _phases->adr_at(index);
   1.164 +}
   1.165 +
   1.166 +bool TimePartitions::has_active_phases() {
   1.167 +  return _active_phases.count() > 0;
   1.168 +}
   1.169 +
   1.170 +bool TimePartitionPhasesIterator::has_next() {
   1.171 +  return _next < _time_partitions->num_phases();
   1.172 +}
   1.173 +
   1.174 +GCPhase* TimePartitionPhasesIterator::next() {
   1.175 +  assert(has_next(), "Must have phases left");
   1.176 +  return _time_partitions->phase_at(_next++);
   1.177 +}
   1.178 +
   1.179 +
   1.180 +/////////////// Unit tests ///////////////
   1.181 +
   1.182 +#ifndef PRODUCT
   1.183 +
   1.184 +class TimePartitionPhasesIteratorTest {
   1.185 + public:
   1.186 +  static void all() {
   1.187 +    one_pause();
   1.188 +    two_pauses();
   1.189 +    one_sub_pause_phase();
   1.190 +    many_sub_pause_phases();
   1.191 +    many_sub_pause_phases2();
   1.192 +    max_nested_pause_phases();
   1.193 +  }
   1.194 +
   1.195 +  static void validate_pause_phase(GCPhase* phase, int level, const char* name, const Ticks& start, const Ticks& end) {
   1.196 +    assert(phase->level() == level, "Incorrect level");
   1.197 +    assert(strcmp(phase->name(), name) == 0, "Incorrect name");
   1.198 +    assert(phase->start() == start, "Incorrect start");
   1.199 +    assert(phase->end() == end, "Incorrect end");
   1.200 +  }
   1.201 +
   1.202 +  static void one_pause() {
   1.203 +    TimePartitions time_partitions;
   1.204 +    time_partitions.report_gc_phase_start("PausePhase", 2);
   1.205 +    time_partitions.report_gc_phase_end(8);
   1.206 +
   1.207 +    TimePartitionPhasesIterator iter(&time_partitions);
   1.208 +
   1.209 +    validate_pause_phase(iter.next(), 0, "PausePhase", 2, 8);
   1.210 +    assert(time_partitions.sum_of_pauses() == Ticks(8) - Ticks(2), "Incorrect");
   1.211 +    assert(time_partitions.longest_pause() == Ticks(8) - Ticks(2), "Incorrect");
   1.212 +
   1.213 +    assert(!iter.has_next(), "Too many elements");
   1.214 +  }
   1.215 +
   1.216 +  static void two_pauses() {
   1.217 +    TimePartitions time_partitions;
   1.218 +    time_partitions.report_gc_phase_start("PausePhase1", 2);
   1.219 +    time_partitions.report_gc_phase_end(3);
   1.220 +    time_partitions.report_gc_phase_start("PausePhase2", 4);
   1.221 +    time_partitions.report_gc_phase_end(6);
   1.222 +
   1.223 +    TimePartitionPhasesIterator iter(&time_partitions);
   1.224 +
   1.225 +    validate_pause_phase(iter.next(), 0, "PausePhase1", 2, 3);
   1.226 +    validate_pause_phase(iter.next(), 0, "PausePhase2", 4, 6);
   1.227 +
   1.228 +    assert(time_partitions.sum_of_pauses() == Ticks(3) - Ticks(0), "Incorrect");
   1.229 +    assert(time_partitions.longest_pause() == Ticks(2) - Ticks(0), "Incorrect");
   1.230 +
   1.231 +    assert(!iter.has_next(), "Too many elements");
   1.232 +  }
   1.233 +
   1.234 +  static void one_sub_pause_phase() {
   1.235 +    TimePartitions time_partitions;
   1.236 +    time_partitions.report_gc_phase_start("PausePhase", 2);
   1.237 +    time_partitions.report_gc_phase_start("SubPhase", 3);
   1.238 +    time_partitions.report_gc_phase_end(4);
   1.239 +    time_partitions.report_gc_phase_end(5);
   1.240 +
   1.241 +    TimePartitionPhasesIterator iter(&time_partitions);
   1.242 +
   1.243 +    validate_pause_phase(iter.next(), 0, "PausePhase", 2, 5);
   1.244 +    validate_pause_phase(iter.next(), 1, "SubPhase", 3, 4);
   1.245 +
   1.246 +    assert(time_partitions.sum_of_pauses() == Ticks(3) - Ticks(0), "Incorrect");
   1.247 +    assert(time_partitions.longest_pause() == Ticks(3) - Ticks(0), "Incorrect");
   1.248 +
   1.249 +    assert(!iter.has_next(), "Too many elements");
   1.250 +  }
   1.251 +
   1.252 +  static void max_nested_pause_phases() {
   1.253 +    TimePartitions time_partitions;
   1.254 +    time_partitions.report_gc_phase_start("PausePhase", 2);
   1.255 +    time_partitions.report_gc_phase_start("SubPhase1", 3);
   1.256 +    time_partitions.report_gc_phase_start("SubPhase2", 4);
   1.257 +    time_partitions.report_gc_phase_start("SubPhase3", 5);
   1.258 +    time_partitions.report_gc_phase_end(6);
   1.259 +    time_partitions.report_gc_phase_end(7);
   1.260 +    time_partitions.report_gc_phase_end(8);
   1.261 +    time_partitions.report_gc_phase_end(9);
   1.262 +
   1.263 +    TimePartitionPhasesIterator iter(&time_partitions);
   1.264 +
   1.265 +    validate_pause_phase(iter.next(), 0, "PausePhase", 2, 9);
   1.266 +    validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 8);
   1.267 +    validate_pause_phase(iter.next(), 2, "SubPhase2", 4, 7);
   1.268 +    validate_pause_phase(iter.next(), 3, "SubPhase3", 5, 6);
   1.269 +
   1.270 +    assert(time_partitions.sum_of_pauses() == Ticks(7) - Ticks(0), "Incorrect");
   1.271 +    assert(time_partitions.longest_pause() == Ticks(7) - Ticks(0), "Incorrect");
   1.272 +
   1.273 +    assert(!iter.has_next(), "Too many elements");
   1.274 +  }
   1.275 +
   1.276 +  static void many_sub_pause_phases() {
   1.277 +    TimePartitions time_partitions;
   1.278 +    time_partitions.report_gc_phase_start("PausePhase", 2);
   1.279 +
   1.280 +    time_partitions.report_gc_phase_start("SubPhase1", 3);
   1.281 +    time_partitions.report_gc_phase_end(4);
   1.282 +    time_partitions.report_gc_phase_start("SubPhase2", 5);
   1.283 +    time_partitions.report_gc_phase_end(6);
   1.284 +    time_partitions.report_gc_phase_start("SubPhase3", 7);
   1.285 +    time_partitions.report_gc_phase_end(8);
   1.286 +    time_partitions.report_gc_phase_start("SubPhase4", 9);
   1.287 +    time_partitions.report_gc_phase_end(10);
   1.288 +
   1.289 +    time_partitions.report_gc_phase_end(11);
   1.290 +
   1.291 +    TimePartitionPhasesIterator iter(&time_partitions);
   1.292 +
   1.293 +    validate_pause_phase(iter.next(), 0, "PausePhase", 2, 11);
   1.294 +    validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 4);
   1.295 +    validate_pause_phase(iter.next(), 1, "SubPhase2", 5, 6);
   1.296 +    validate_pause_phase(iter.next(), 1, "SubPhase3", 7, 8);
   1.297 +    validate_pause_phase(iter.next(), 1, "SubPhase4", 9, 10);
   1.298 +
   1.299 +    assert(time_partitions.sum_of_pauses() == Ticks(9) - Ticks(0), "Incorrect");
   1.300 +    assert(time_partitions.longest_pause() == Ticks(9) - Ticks(0), "Incorrect");
   1.301 +
   1.302 +    assert(!iter.has_next(), "Too many elements");
   1.303 +  }
   1.304 +
   1.305 +  static void many_sub_pause_phases2() {
   1.306 +    TimePartitions time_partitions;
   1.307 +    time_partitions.report_gc_phase_start("PausePhase", 2);
   1.308 +
   1.309 +    time_partitions.report_gc_phase_start("SubPhase1", 3);
   1.310 +    time_partitions.report_gc_phase_start("SubPhase11", 4);
   1.311 +    time_partitions.report_gc_phase_end(5);
   1.312 +    time_partitions.report_gc_phase_start("SubPhase12", 6);
   1.313 +    time_partitions.report_gc_phase_end(7);
   1.314 +    time_partitions.report_gc_phase_end(8);
   1.315 +    time_partitions.report_gc_phase_start("SubPhase2", 9);
   1.316 +    time_partitions.report_gc_phase_start("SubPhase21", 10);
   1.317 +    time_partitions.report_gc_phase_end(11);
   1.318 +    time_partitions.report_gc_phase_start("SubPhase22", 12);
   1.319 +    time_partitions.report_gc_phase_end(13);
   1.320 +    time_partitions.report_gc_phase_end(14);
   1.321 +    time_partitions.report_gc_phase_start("SubPhase3", 15);
   1.322 +    time_partitions.report_gc_phase_end(16);
   1.323 +
   1.324 +    time_partitions.report_gc_phase_end(17);
   1.325 +
   1.326 +    TimePartitionPhasesIterator iter(&time_partitions);
   1.327 +
   1.328 +    validate_pause_phase(iter.next(), 0, "PausePhase", 2, 17);
   1.329 +    validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 8);
   1.330 +    validate_pause_phase(iter.next(), 2, "SubPhase11", 4, 5);
   1.331 +    validate_pause_phase(iter.next(), 2, "SubPhase12", 6, 7);
   1.332 +    validate_pause_phase(iter.next(), 1, "SubPhase2", 9, 14);
   1.333 +    validate_pause_phase(iter.next(), 2, "SubPhase21", 10, 11);
   1.334 +    validate_pause_phase(iter.next(), 2, "SubPhase22", 12, 13);
   1.335 +    validate_pause_phase(iter.next(), 1, "SubPhase3", 15, 16);
   1.336 +
   1.337 +    assert(time_partitions.sum_of_pauses() == Ticks(15) - Ticks(0), "Incorrect");
   1.338 +    assert(time_partitions.longest_pause() == Ticks(15) - Ticks(0), "Incorrect");
   1.339 +
   1.340 +    assert(!iter.has_next(), "Too many elements");
   1.341 +  }
   1.342 +};
   1.343 +
   1.344 +class GCTimerTest {
   1.345 +public:
   1.346 +  static void all() {
   1.347 +    gc_start();
   1.348 +    gc_end();
   1.349 +  }
   1.350 +
   1.351 +  static void gc_start() {
   1.352 +    GCTimer gc_timer;
   1.353 +    gc_timer.register_gc_start(1);
   1.354 +
   1.355 +    assert(gc_timer.gc_start() == 1, "Incorrect");
   1.356 +  }
   1.357 +
   1.358 +  static void gc_end() {
   1.359 +    GCTimer gc_timer;
   1.360 +    gc_timer.register_gc_start(1);
   1.361 +    gc_timer.register_gc_end(2);
   1.362 +
   1.363 +    assert(gc_timer.gc_end() == 2, "Incorrect");
   1.364 +  }
   1.365 +};
   1.366 +
   1.367 +void GCTimerAllTest::all() {
   1.368 +  GCTimerTest::all();
   1.369 +  TimePartitionPhasesIteratorTest::all();
   1.370 +}
   1.371 +
   1.372 +#endif

mercurial