Index: dev/core/src/com/google/gwt/dev/util/PerfLogger.java
===================================================================
--- dev/core/src/com/google/gwt/dev/util/PerfLogger.java	(revision 0)
+++ dev/core/src/com/google/gwt/dev/util/PerfLogger.java	(revision 0)
@@ -0,0 +1,156 @@
+/*
+ * 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 {
+
+    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 final String message;
+
+    private boolean messageOnly;
+
+    private final Timing parent;
+
+    private final long startTimeNanos;
+
+    private final List<Timing> subTimings = new ArrayList<Timing>();
+
+    private long totalTimeNanos;
+
+    public Timing(String message) {
+      Timing myParent = currentTiming.get();
+      currentTiming.set(this);
+      if (myParent != null) {
+        myParent.subTimings.add(this);
+      }
+      this.parent = myParent;
+      this.message = message;
+      this.startTimeNanos = System.nanoTime();
+    }
+
+    public void end(long endTimeNanos) {
+      totalTimeNanos = endTimeNanos - startTimeNanos;
+      currentTiming.set(parent);
+      if (parent == null) {
+        printTimings();
+      }
+    }
+
+    public void setMessageOnly() {
+      this.messageOnly = true;
+    }
+
+    private void printTiming(int depth) {
+      StringBuffer msg = new StringBuffer(getIndentString(depth));
+      msg.append("[perf] ");
+      msg.append(message);
+      if (!messageOnly) {
+        msg.append(" ");
+        msg.append(totalTimeNanos / 1000000.0);
+        msg.append("ms");
+      }
+      System.out.println(msg);
+
+      ++depth;
+      for (Timing subTiming : subTimings) {
+        subTiming.printTiming(depth);
+      }
+    }
+
+    private void printTimings() {
+      printTiming(0);
+    }
+  }
+
+  private static ThreadLocal<Timing> currentTiming = new ThreadLocal<Timing>();
+
+  /**
+   * Flag for enabling performance logging.
+   */
+  private static boolean enabled = Boolean.parseBoolean(System.getProperty("gwt.perflog"));
+
+  /**
+   * Ends the current timing.
+   */
+  public static void end() {
+    if (!enabled) {
+      return;
+    }
+    long endTimeNanos = System.nanoTime();
+    Timing timing = currentTiming.get();
+    if (timing == null) {
+      System.out.println("Tried to end a timing that was never started!\n");
+      return;
+    }
+    timing.end(endTimeNanos);
+  }
+
+  /**
+   * Logs a message without explicitly including timer information.
+   * 
+   * @param message a not <code>null</code> message
+   */
+  public static void log(String message) {
+    if (!enabled) {
+      return;
+    }
+    start(message);
+    currentTiming.get().setMessageOnly();
+    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;
+    }
+    new Timing(message);
+  }
+
+}
