| /* |
| * Copyright 2009 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 |
| * |
| * 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.gwt.dev.util; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * A counter which records bunch of statistics for frequently occuring |
| * operations. Calculates: count, total time, average time, maximum time |
| * & slow operations. |
| */ |
| public class PerfCounter { |
| private static class OperationStats { |
| private long count = 0; |
| private boolean isCounter = false; |
| private long maxTimeNanos = 0; |
| private long slowCount = 0; |
| private long totalSlowTimeNanos = 0; |
| private long totalTimeNanos = 0; |
| |
| @Override |
| public String toString() { |
| StringBuilder result = new StringBuilder(); |
| |
| if (!isCounter) { |
| result.append(count); |
| result.append("/"); |
| result.append(totalTimeNanos / 1000000000.0); |
| result.append("/"); |
| result.append(totalTimeNanos / 1000000000.0 / count); |
| result.append("/"); |
| result.append(maxTimeNanos / 1000000000.0); |
| result.append("/"); |
| result.append(slowCount); |
| result.append("/"); |
| result.append(totalSlowTimeNanos * 1.0 / totalTimeNanos); |
| result.append(" "); |
| result.append( |
| "(count/total_time/avg_time/max_time/slow_count/slow_ratio)"); |
| } else { |
| result.append(count); |
| result.append(" (count)"); |
| } |
| |
| return result.toString(); |
| } |
| } |
| |
| /** |
| * Flag for enabling performance logging. |
| */ |
| private static boolean enabled = |
| Boolean.parseBoolean(System.getProperty("gwt.perfcounters")); |
| |
| private static final ThreadLocal<Map<String, Long>> operationsStartTime = |
| new ThreadLocal<Map<String,Long>>() { |
| @Override |
| protected Map<String, Long> initialValue() { |
| return new HashMap<String, Long>(); |
| } |
| }; |
| |
| private static final Map<String, OperationStats> operationStats = |
| new HashMap<String, OperationStats>(); |
| |
| /** |
| * Record the end of the operation. |
| */ |
| public static void end(String operation) { |
| if (!enabled) { |
| return; |
| } |
| end(operation, 1 * 1000000000 /* 1 sec */); |
| } |
| |
| /** |
| * Record the end of the operation. |
| */ |
| public static void end(String operation, long slowThresholdNano) { |
| if (!enabled) { |
| return; |
| } |
| long finishTime = System.nanoTime(); |
| |
| Map<String, Long> startTimes = operationsStartTime.get(); |
| |
| Long startTime; |
| |
| synchronized (startTimes) { |
| startTime = startTimes.remove(operation); |
| } |
| |
| Preconditions.checkNotNull(startTime); |
| |
| synchronized (operationStats) { |
| OperationStats stats = getStats(operation); |
| |
| stats.count++; |
| long elapsedTime = finishTime - startTime.longValue(); |
| stats.totalTimeNanos += elapsedTime; |
| stats.maxTimeNanos = Math.max(stats.maxTimeNanos, elapsedTime); |
| if (elapsedTime > slowThresholdNano) { |
| stats.slowCount++; |
| stats.totalSlowTimeNanos += elapsedTime; |
| } |
| } |
| } |
| |
| /** |
| * Increment counter. |
| */ |
| public static void inc(String operation) { |
| synchronized (operationStats) { |
| OperationStats stats = getStats(operation); |
| stats.count++; |
| stats.isCounter = true; |
| } |
| } |
| |
| public static void print() { |
| if (!enabled) { |
| return; |
| } |
| System.out.println("------------- Perf Counters -------------"); |
| synchronized (operationStats) { |
| List<String> keys = new ArrayList<String>(operationStats.keySet()); |
| Collections.sort(keys); |
| for (String operation : keys) { |
| System.out.println(operation + ": " + operationStats.get(operation)); |
| } |
| } |
| System.out.println("-----------------------------------------"); |
| } |
| |
| /** |
| * Start operation. |
| */ |
| public static void start(String operation) { |
| if (!enabled) { |
| return; |
| } |
| Map<String, Long> startTimes = operationsStartTime.get(); |
| |
| synchronized (startTimes) { |
| Preconditions.checkState(!startTimes.containsKey(operation)); |
| long startTime = System.nanoTime(); |
| startTimes.put(operation, new Long(startTime)); |
| } |
| } |
| |
| private static OperationStats getStats(String operation) { |
| OperationStats stats = operationStats.get(operation); |
| if (stats == null) { |
| stats = new OperationStats(); |
| operationStats.put(operation, stats); |
| } |
| return stats; |
| } |
| } |