| /* |
| * Copyright 2008 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.List; |
| |
| /** |
| * Performs basic recording/logging of performance metrics for internal |
| * development purposes. |
| * |
| * <p> |
| * This class differs from {@link com.google.gwt.core.ext.TreeLogger TreeLogger} |
| * by providing an interface more suitable for metrics-oriented logging. |
| * </p> |
| * |
| * <p> |
| * Performance logging can be enabled by setting the system property, |
| * {@code gwt.perflog=true}. |
| * </p> |
| * |
| */ |
| public class PerfLogger { |
| |
| private static class Timing { |
| |
| String message; |
| |
| long startTimeNanos; |
| |
| long totalTimeNanos; |
| |
| Timing parent = null; |
| |
| List<Timing> subTimings = new ArrayList<Timing>(); |
| |
| boolean messageOnly; |
| |
| Timing(Timing parent, String message) { |
| this.parent = parent; |
| this.message = message; |
| this.startTimeNanos = System.nanoTime(); |
| } |
| |
| Timing() { |
| } |
| |
| boolean isRoot() { |
| return parent == null; |
| } |
| } |
| |
| /** |
| * Flag for enabling performance logging. |
| */ |
| private static boolean enabled = Boolean.parseBoolean(System.getProperty("gwt.perflog")); |
| |
| private static ThreadLocal<Timing> currentTiming = new ThreadLocal<Timing>() { |
| @Override |
| protected Timing initialValue() { |
| return new Timing(); |
| } |
| }; |
| |
| /** |
| * Ends the current timing. |
| */ |
| public static void end() { |
| if (!enabled) { |
| return; |
| } |
| long endTimeNanos = System.nanoTime(); |
| Timing timing = currentTiming.get(); |
| if (timing.isRoot()) { |
| System.out.println("Tried to end a timing that was never started!\n"); |
| return; |
| } |
| timing.totalTimeNanos = endTimeNanos - timing.startTimeNanos; |
| |
| Timing newCurrent = timing.parent; |
| currentTiming.set(newCurrent); |
| if (newCurrent.isRoot()) { |
| printTimings(); |
| newCurrent.subTimings = new ArrayList<Timing>(); |
| } |
| } |
| |
| /** |
| * Logs a message without explicitly including timer information. |
| * |
| * @param message a not <code>null</code> message |
| */ |
| public static void log(String message) { |
| if (enabled) { |
| start(message); |
| currentTiming.get().messageOnly = true; |
| end(); |
| } |
| } |
| |
| /** |
| * Starts a new timing corresponding to {@code message}. You must call {@link |
| * #end} for each corresponding call to {@code start}. You may nest timing |
| * calls. |
| * |
| * @param message a not <code>null</code> message. |
| */ |
| public static void start(String message) { |
| if (!enabled) { |
| return; |
| } |
| Timing current = currentTiming.get(); |
| Timing newTiming = new Timing(current, message); |
| current.subTimings.add(newTiming); |
| currentTiming.set(newTiming); |
| } |
| |
| private static String getIndentString(int level) { |
| StringBuffer str = new StringBuffer(level * 2); |
| for (int i = 0; i < level; ++i) { |
| str.append(" "); |
| } |
| return str.toString(); |
| } |
| |
| private static void printTiming(Timing t, int depth) { |
| if (!t.isRoot()) { |
| StringBuffer msg = new StringBuffer(getIndentString(depth - 1)); |
| msg.append("[perf] "); |
| msg.append(t.message); |
| if (!t.messageOnly) { |
| msg.append(" "); |
| msg.append(t.totalTimeNanos / 1000000); |
| msg.append("ms"); |
| } |
| System.out.println(msg); |
| } |
| |
| ++depth; |
| for (Timing subTiming : t.subTimings) { |
| printTiming(subTiming, depth); |
| } |
| } |
| |
| private static void printTimings() { |
| printTiming(currentTiming.get(), 0); |
| } |
| } |