/* * Copyright (c) 2011, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.core.utilities.performance; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; /** * Instances of the class <code>PerformanceManager</code> provide support for measuring the * performance of a piece of code. * <p> * The expected code pattern for using this class is as follows: * * <pre> * PerformanceManager.Timer timer = PerformanceManager.getInstance().start(OPERATION_IDENTIFIER); * try { * // code to be measured * } finally { * timer.end(); * } * </pre> * * @coverage dart.tools.core.utilities */ public class PerformanceManager { /** * Instances of the class <code>Timer</code> implement an object that maintains information about * a single measurement that is in progress. */ public class Timer { /** * The name of the operation being measured by this timer. */ private String name; /** * The time at the beginning of the operation. */ private long startTime; /** * Initialize a newly created timer to time an operation with the given name. * * @param name the name of the operation being measured */ public Timer(String name) { this.name = name; startTime = System.currentTimeMillis(); } /** * Record the end of the operation being measured by this timer. */ public void end() { recordMetric(System.currentTimeMillis() - startTime, name, 1); } /** * Record the end of the operation being measured by this timer. * * @param work the amount of work completed by the operation */ public void end(int work) { recordMetric(System.currentTimeMillis() - startTime, name, work); } } /** * Instances of the class <code>Metric</code> implement an object that maintains information about * some number of measurements of a single piece of code. */ private static class Metric { /** * The name of the metric. */ private String name; /** * The number of times the metric has been measured. */ private int count; /** * The total amount of work performed by the operation. */ private int totalWork; /** * The total amount of time taken by the operation. */ private long totalTime; /** * The minimum amount of time (per unit of work) taken by a single measurement. */ private long minTime; /** * The maximum amount of time (per unit of work) taken by a single measurement. */ private long maxTime; /** * Initialize a newly created metric with the given name to have a single measurement of the * given duration as a result of performing the given amount of work. * * @param name the name of the metric * @param work the amount of work done for the first measurement * @param time the duration of the first measurement */ public Metric(String name, int work, long time) { this.name = name; count = 1; totalWork = work; totalTime = time; minTime = time / work; maxTime = time / work; } /** * Add a measurement of the give duration. * * @param work the amount of work done for the measurement being added * @param elapsedTime the duration of the measurement being added */ public void addTime(int work, long elapsedTime) { count++; totalWork += work; totalTime += elapsedTime; long timePerUnit = elapsedTime / work; minTime = Math.min(minTime, timePerUnit); maxTime = Math.max(maxTime, timePerUnit); } /** * Print this metric to the given print writer. * * @param writer the writer to which this metric is to be printed */ public void printOn(PrintWriter writer) { writer.print(name); writer.print(" = "); writer.print(minTime); writer.print(", "); writer.print(totalTime / totalWork); writer.print(", "); writer.print(maxTime); writer.print(" ms/unit of work ["); writer.print(count); writer.print("]"); } } /** * A table mapping metric names to metrics. */ private Map<String, Metric> metricMap = new HashMap<String, Metric>(); /** * The unique instance of this class. */ private static final PerformanceManager UNIQUE_INSTANCE = new PerformanceManager(); /** * Return the unique instance of this class. * * @return the unique instance of this class */ public static PerformanceManager getInstance() { return UNIQUE_INSTANCE; } /** * Prevent the creation of new instances of this class. */ private PerformanceManager() { super(); } /** * Print all of the metrics to the given print writer. * * @param writer the writer to which all of the metrics are to be printed */ public void printMetrics(PrintWriter writer) { synchronized (metricMap) { for (Metric metric : metricMap.values()) { metric.printOn(writer); writer.println(); } } writer.flush(); } /** * Start the measurement of the operation with the given name. * * @return the timer used to perform the measurement */ public Timer start(String name) { return new Timer(name); } /** * Record the end of the most recently started measurement. * * @param name the name of the measurement that just completed */ private void recordMetric(long elapsedTime, String name, int work) { synchronized (metricMap) { Metric metric = metricMap.get(name); if (metric == null) { metric = new Metric(name, work, elapsedTime); metricMap.put(name, metric); } else { metric.addTime(work, elapsedTime); } } } }