在性能调优时,往往遇到需要统计一个方法中每一行代码的执行时间,从而快速排查出到底是哪一行代码耗时过长,而且往往这个方法是在一个非常大的循环中,用简单的System.currentTimeMillis是不行的,AOP、Profiler之类的工具又太笨重了,这时可以利用一个简单的小程序解决问题:
在需要调试的方法中隔几行插入Timer.set(数字或字符)方法,程序结束前调用Timer.print()方法就行了。 因为目的只是排查方法执行时间,调试完成后可以将set()方法注释掉,然后利用Eclipse的查错功能将所有Timer.set()方法找出来删除。如果不介意方法中的垃圾代码,也可以直接将set()方法体改为"return;",对性能影响不大(当参数为数字时)。
public class Timer {//NOSONAR
private static String lastMark = "start";
private static long lastTime = System.nanoTime();
private static final MaptimeMap = new LinkedHashMap();
private static final MaptimeHappenCount = new LinkedHashMap();
public static void set(int mark) {
set("" + mark);
};
public static void set(String mark) {
long thisTime = System.nanoTime();
String key = lastMark + "->" + mark;
Long lastSummary = timeMap.get(key);
if (lastSummary == null)
lastSummary = 0l;
timeMap.put(key, System.nanoTime() - lastTime + lastSummary);
Long lastCount = timeHappenCount.get(key);
if (lastCount == null)
lastCount = 0L;
timeHappenCount.put(key, ++lastCount);
lastTime = thisTime;
lastMark = mark;
};
public static void print() {
for (Entryentry : timeMap.entrySet()) {
System.out.println(// NOSONAR
String.format("%20s, Total times:%20s, Repeat times:%20s, Avg times:%20s ", entry.getKey(),
entry.getValue(), timeHappenCount.get(entry.getKey()),
entry.getValue() / timeHappenCount.get(entry.getKey())
));
}
}
}