code: package edu.berkeley.nlp.util;
  
  import java.util.LinkedHashMap;
  import java.util.LinkedList;
  import java.util.Map;
  
  /**
   * 4/2/09: StopWatchSet should be re-entrant (can call begin("foo") twice) and
   * thread-safe.
   */
  public class StopWatchSet {
  	// For measuring time of certain types of events.
  	// Shared across all threads.
  	private static Map<String, StopWatch> stopWatches = new LinkedHashMap<String, StopWatch>();
  
  	// A stack of stop-watches (one per thread)
  	private static ThreadLocal<LinkedList<Pair<String, StopWatch>>> lastStopWatches = new ThreadLocal() {
  		@Override
  		protected LinkedList<Pair<String, StopWatch>> initialValue() {
  			return new LinkedList();
  		}
  	};
  
  	public synchronized static StopWatch getWatch(String s) {
  		return MapUtils.getMut(stopWatches, s, new StopWatch());
  	}
  
  	public static void begin(String s) {
  		// Create a new stop watch for reentrance and thread safety
  		lastStopWatches.get().addLast(new Pair(s, new StopWatch().start()));
  	}
  
  	public static void end() {
  		Pair<String, StopWatch> pair = lastStopWatches.get().removeLast();
  		pair.getSecond().stop();
  		// Add it
  		synchronized (stopWatches) {
  			getWatch(pair.getFirst()).add(pair.getSecond());
  		}
  	}
  
  	public synchronized static OrderedStringMap getStats() {
  		OrderedStringMap map = new OrderedStringMap();
  		for (String key : stopWatches.keySet()) {
  			StopWatch watch = getWatch(key);
  			map.put(key, watch + " ("
  					+ new StopWatch(watch.n == 0 ? 0 : watch.ms / watch.n)
  					+ " x " + watch.n + ")");
  		}
  		return map;
  	}
  }
  