package com.anjlab.ping.services.profiler; import static java.lang.Integer.toHexString; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import org.apache.tapestry5.plastic.MethodAdvice; import org.apache.tapestry5.plastic.MethodInvocation; public class ProfilingAdvice implements MethodAdvice { private static final Map<String, Leaf> topTraces = new HashMap<String, Leaf>(); private static final Stack<Leaf> stack = new Stack<Leaf>(); private String className; public ProfilingAdvice(String className) { this.className = className; } public void advise(MethodInvocation invocation) { long startTime = 0; String signature = getMethodSignature(className, invocation); try { Leaf leaf; Leaf root = stack.isEmpty() ? null : stack.peek(); if (root == null) { if (!topTraces.containsKey(signature)) { topTraces.put(signature, new Leaf(signature, new ProfilerMetric())); } leaf = topTraces.get(signature); } else { if (!root.hasChild(signature)) { leaf = new Leaf(signature, new ProfilerMetric()); root.addChild(leaf); } leaf = root.getChild(signature); } stack.push(leaf); startTime = System.currentTimeMillis(); invocation.proceed(); } finally { long endTime = System.currentTimeMillis(); Leaf leaf = stack.pop(); leaf.getMetric().invocationCount++; leaf.getMetric().totalTimeMillis += endTime - startTime; } } private String getMethodSignature(final String intfName, MethodInvocation invocation) { StringBuilder builder = new StringBuilder(); builder.append(intfName); builder.append("."); builder.append(invocation.getMethod().getName()); builder.append("("); for (int i = 0; i < invocation.getMethod().getParameterTypes().length; i++) { builder.append(invocation.getMethod().getParameterTypes()[i].getSimpleName()); builder.append(","); } if (invocation.getMethod().getParameterTypes().length > 0) { builder.deleteCharAt(builder.length() - 1); } builder.append(")"); return builder.toString(); } public static Map<String, Leaf> dumpPlainMetrics() { Map<String, Leaf> result = new HashMap<String, Leaf>(); addMetrics(result, topTraces.values()); return result; } private static void addMetrics(Map<String, Leaf> result, Collection<Leaf> leafs) { for (Leaf leaf : leafs) { result.put(leaf.getMethodName(), leaf); addMetrics(result, leaf.getChildren().values()); } } public static Map<String, Leaf> dumpCallStack(List<String> tracePath) { Map<String, Leaf> result = new HashMap<String, Leaf>(); Leaf leaf = getLeaf(tracePath); if (leaf == null) { for (String key : topTraces.keySet()) { result.put(key, topTraces.get(key)); } return result; } Map<String, Leaf> slice = leaf.getChildren(); for (String key : slice.keySet()) { result.put(key, slice.get(key)); } return result; } public static Leaf getLeaf(List<String> tracePath) { Leaf leaf = null; Map<String, Leaf> slice = topTraces; for (String code : tracePath) { leaf = null; for (String key : slice.keySet()) { if (toHexString(key.hashCode()).equals(code)) { leaf = slice.get(key); break; } } if (leaf == null) { return null; } slice = leaf.getChildren(); } return leaf; } public static void clear() { topTraces.clear(); } }