ysr@777: /* ysr@777: * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. ysr@777: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ysr@777: * ysr@777: * This code is free software; you can redistribute it and/or modify it ysr@777: * under the terms of the GNU General Public License version 2 only, as ysr@777: * published by the Free Software Foundation. ysr@777: * ysr@777: * This code is distributed in the hope that it will be useful, but WITHOUT ysr@777: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ysr@777: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ysr@777: * version 2 for more details (a copy is included in the LICENSE file that ysr@777: * accompanied this code). ysr@777: * ysr@777: * You should have received a copy of the GNU General Public License version ysr@777: * 2 along with this work; if not, write to the Free Software Foundation, ysr@777: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ysr@777: * ysr@777: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, ysr@777: * CA 95054 USA or visit www.sun.com if you need additional information or ysr@777: * have any questions. ysr@777: * ysr@777: */ ysr@777: ysr@777: # include "incls/_precompiled.incl" ysr@777: # include "incls/_coTracker.cpp.incl" ysr@777: ysr@777: COTracker* COTracker::_head = NULL; ysr@777: double COTracker::_cpu_number = -1.0; ysr@777: ysr@777: void ysr@777: COTracker::resetPeriod(double now_sec, double vnow_sec) { ysr@777: guarantee( _enabled, "invariant" ); ysr@777: _period_start_time_sec = now_sec; ysr@777: _period_start_vtime_sec = vnow_sec; ysr@777: } ysr@777: ysr@777: void ysr@777: COTracker::setConcOverhead(double time_stamp_sec, ysr@777: double conc_overhead) { ysr@777: guarantee( _enabled, "invariant" ); ysr@777: _conc_overhead = conc_overhead; ysr@777: _time_stamp_sec = time_stamp_sec; ysr@777: if (conc_overhead > 0.001) ysr@777: _conc_overhead_seq.add(conc_overhead); ysr@777: } ysr@777: ysr@777: void ysr@777: COTracker::reset(double starting_conc_overhead) { ysr@777: guarantee( _enabled, "invariant" ); ysr@777: double now_sec = os::elapsedTime(); ysr@777: setConcOverhead(now_sec, starting_conc_overhead); ysr@777: } ysr@777: ysr@777: void ysr@777: COTracker::start() { ysr@777: guarantee( _enabled, "invariant" ); ysr@777: resetPeriod(os::elapsedTime(), os::elapsedVTime()); ysr@777: } ysr@777: ysr@777: void ysr@777: COTracker::update(bool force_end) { ysr@777: assert( _enabled, "invariant" ); ysr@777: double end_time_sec = os::elapsedTime(); ysr@777: double elapsed_time_sec = end_time_sec - _period_start_time_sec; ysr@777: if (force_end || elapsed_time_sec > _update_period_sec) { ysr@777: // reached the end of the period ysr@777: double end_vtime_sec = os::elapsedVTime(); ysr@777: double elapsed_vtime_sec = end_vtime_sec - _period_start_vtime_sec; ysr@777: ysr@777: double conc_overhead = elapsed_vtime_sec / elapsed_time_sec; ysr@777: ysr@777: setConcOverhead(end_time_sec, conc_overhead); ysr@777: resetPeriod(end_time_sec, end_vtime_sec); ysr@777: } ysr@777: } ysr@777: ysr@777: void ysr@777: COTracker::updateForSTW(double start_sec, double end_sec) { ysr@777: if (!_enabled) ysr@777: return; ysr@777: ysr@777: // During a STW pause, no concurrent GC thread has done any ysr@777: // work. So, we can safely adjust the start of the current period by ysr@777: // adding the duration of the STW pause to it, so that the STW pause ysr@777: // doesn't affect the reading of the concurrent overhead (it's ysr@777: // basically like excluding the time of the STW pause from the ysr@777: // concurrent overhead calculation). ysr@777: ysr@777: double stw_duration_sec = end_sec - start_sec; ysr@777: guarantee( stw_duration_sec > 0.0, "invariant" ); ysr@777: ysr@777: if (outOfDate(start_sec)) ysr@777: _conc_overhead = 0.0; ysr@777: else ysr@777: _time_stamp_sec = end_sec; ysr@777: _period_start_time_sec += stw_duration_sec; ysr@777: _conc_overhead_seq = NumberSeq(); ysr@777: ysr@777: guarantee( os::elapsedTime() > _period_start_time_sec, "invariant" ); ysr@777: } ysr@777: ysr@777: double ysr@777: COTracker::predConcOverhead() { ysr@777: if (_enabled) { ysr@777: // tty->print(" %1.2lf", _conc_overhead_seq.maximum()); ysr@777: return _conc_overhead_seq.maximum(); ysr@777: } else { ysr@777: // tty->print(" DD"); ysr@777: return 0.0; ysr@777: } ysr@777: } ysr@777: ysr@777: void ysr@777: COTracker::resetPred() { ysr@777: _conc_overhead_seq = NumberSeq(); ysr@777: } ysr@777: ysr@777: COTracker::COTracker(int group) ysr@777: : _enabled(false), ysr@777: _group(group), ysr@777: _period_start_time_sec(-1.0), ysr@777: _period_start_vtime_sec(-1.0), ysr@777: _conc_overhead(-1.0), ysr@777: _time_stamp_sec(-1.0), ysr@777: _next(NULL) { ysr@777: // GCOverheadReportingPeriodMS indicates how frequently the ysr@777: // concurrent overhead will be recorded by the GC Overhead ysr@777: // Reporter. We want to take readings less often than that. If we ysr@777: // took readings more often than some of them might be lost. ysr@777: _update_period_sec = ((double) GCOverheadReportingPeriodMS) / 1000.0 * 1.25; ysr@777: _next = _head; ysr@777: _head = this; ysr@777: ysr@777: if (_cpu_number < 0.0) ysr@777: _cpu_number = (double) os::processor_count(); ysr@777: } ysr@777: ysr@777: // statics ysr@777: ysr@777: void ysr@777: COTracker::updateAllForSTW(double start_sec, double end_sec) { ysr@777: for (COTracker* curr = _head; curr != NULL; curr = curr->_next) { ysr@777: curr->updateForSTW(start_sec, end_sec); ysr@777: } ysr@777: } ysr@777: ysr@777: double ysr@777: COTracker::totalConcOverhead(double now_sec) { ysr@777: double total_conc_overhead = 0.0; ysr@777: ysr@777: for (COTracker* curr = _head; curr != NULL; curr = curr->_next) { ysr@777: double conc_overhead = curr->concOverhead(now_sec); ysr@777: total_conc_overhead += conc_overhead; ysr@777: } ysr@777: ysr@777: return total_conc_overhead; ysr@777: } ysr@777: ysr@777: double ysr@777: COTracker::totalConcOverhead(double now_sec, ysr@777: size_t group_num, ysr@777: double* co_per_group) { ysr@777: double total_conc_overhead = 0.0; ysr@777: ysr@777: for (size_t i = 0; i < group_num; ++i) ysr@777: co_per_group[i] = 0.0; ysr@777: ysr@777: for (COTracker* curr = _head; curr != NULL; curr = curr->_next) { ysr@777: size_t group = curr->_group; ysr@777: assert( 0 <= group && group < group_num, "invariant" ); ysr@777: double conc_overhead = curr->concOverhead(now_sec); ysr@777: ysr@777: co_per_group[group] += conc_overhead; ysr@777: total_conc_overhead += conc_overhead; ysr@777: } ysr@777: ysr@777: return total_conc_overhead; ysr@777: } ysr@777: ysr@777: double ysr@777: COTracker::totalPredConcOverhead() { ysr@777: double total_pred_conc_overhead = 0.0; ysr@777: for (COTracker* curr = _head; curr != NULL; curr = curr->_next) { ysr@777: total_pred_conc_overhead += curr->predConcOverhead(); ysr@777: curr->resetPred(); ysr@777: } ysr@777: return total_pred_conc_overhead / _cpu_number; ysr@777: }