001: /*
002: * FindBugs - Find Bugs in Java programs
003: * Copyright (C) 2003-2007 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.log;
021:
022: import java.util.Comparator;
023: import java.util.Map;
024: import java.util.Stack;
025: import java.util.TreeSet;
026: import java.util.concurrent.ConcurrentHashMap;
027: import java.util.concurrent.atomic.AtomicLong;
028:
029: import edu.umd.cs.findbugs.SystemProperties;
030:
031: /**
032: * @author pugh
033: */
034: public class Profiler {
035:
036: final static boolean REPORT = SystemProperties
037: .getBoolean("profiler.report");
038:
039: private static Profiler instance = new Profiler();
040:
041: private Profiler() {
042: };
043:
044: public static Profiler getInstance() {
045: return instance;
046: }
047:
048: static class Clock {
049: final Class<?> clazz;
050:
051: long startTimeNanos;
052:
053: long accumulatedTime;
054:
055: Clock(Class<?> clazz, long currentNanoTime) {
056: this .clazz = clazz;
057: startTimeNanos = currentNanoTime;
058: }
059:
060: void accumulateTime(long currentNanoTime) {
061: accumulatedTime += currentNanoTime - startTimeNanos;
062: }
063:
064: void restartClock(long currentNanoTime) {
065: startTimeNanos = currentNanoTime;
066: }
067:
068: }
069:
070: ThreadLocal<Stack<Clock>> startTimes = new ThreadLocal<Stack<Clock>>() {
071: @Override
072: public Stack<Clock> initialValue() {
073: return new Stack<Clock>();
074: }
075: };
076:
077: ConcurrentHashMap<Class<?>, AtomicLong> profile = new ConcurrentHashMap<Class<?>, AtomicLong>();
078:
079: public void start(Class<?> c) {
080: long currentNanoTime = System.nanoTime();
081:
082: Stack<Clock> stack = startTimes.get();
083: if (!stack.isEmpty())
084: stack.peek().accumulateTime(currentNanoTime);
085: stack.push(new Clock(c, currentNanoTime));
086: // System.out.println("push " + c.getSimpleName());
087:
088: }
089:
090: public void end(Class<?> c) {
091: // System.out.println("pop " + c.getSimpleName());
092: long currentNanoTime = System.nanoTime();
093:
094: Stack<Clock> stack = startTimes.get();
095: Clock ending = stack.pop();
096: if (ending.clazz != c) {
097: throw new AssertionError("Asked to end timing for " + c
098: + " but top of stack is " + ending.clazz
099: + ", remaining stack is " + stack);
100: }
101: ending.accumulateTime(currentNanoTime);
102: if (!stack.isEmpty()) {
103: Clock restarting = stack.peek();
104: restarting.restartClock(currentNanoTime);
105: }
106: long accumulatedTime = ending.accumulatedTime;
107: if (accumulatedTime == 0)
108: return;
109: AtomicLong counter = profile.get(c);
110: if (counter == null) {
111: counter = new AtomicLong();
112: AtomicLong counter2 = profile.putIfAbsent(c, counter);
113: if (counter2 != null)
114: counter = counter2;
115: }
116: counter.addAndGet(accumulatedTime);
117: }
118:
119: static class Pair<V1, V2> {
120: final V1 first;
121:
122: final V2 second;
123:
124: Pair(V1 first, V2 second) {
125: this .first = first;
126: this .second = second;
127: }
128:
129: @Override
130: public String toString() {
131: return first + ":" + second;
132: }
133: }
134:
135: public void report() {
136: if (!REPORT)
137: return;
138: try {
139: Comparator<Pair<Class<?>, AtomicLong>> c = new Comparator<Pair<Class<?>, AtomicLong>>() {
140:
141: public int compare(Pair<Class<?>, AtomicLong> o1,
142: Pair<Class<?>, AtomicLong> o2) {
143: long v1 = o1.second.get();
144: long v2 = o2.second.get();
145: if (v1 < v2)
146: return -1;
147: if (v1 > v2)
148: return 1;
149: return o1.first.getName().compareTo(
150: o2.first.getName());
151: }
152:
153: };
154: TreeSet<Pair<Class<?>, AtomicLong>> treeSet = new TreeSet<Pair<Class<?>, AtomicLong>>(
155: c);
156: for (Map.Entry<Class<?>, AtomicLong> e : profile.entrySet()) {
157: treeSet.add(new Pair<Class<?>, AtomicLong>(e.getKey(),
158: e.getValue()));
159: }
160: Pair<Class<?>, AtomicLong> prev = null;
161: for (Pair<Class<?>, AtomicLong> e : treeSet) {
162: System.out.printf("%7d %s\n",
163: e.second.get() / 1000000, e.first
164: .getSimpleName());
165: if (false && prev != null)
166: System.out
167: .println(c.compare(prev, e) + " "
168: + prev.second.get() + " "
169: + e.second.get());
170: prev = e;
171: }
172: } catch (RuntimeException e) {
173: System.out.println(e);
174: }
175: }
176: }
|