package com.jsonde.profiler; import com.jsonde.api.methodCall.MethodCallDto; import com.jsonde.api.methodCall.MethodCallDtoFactory; import com.jsonde.api.methodCall.MethodCallSummaryDto; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class ThreadLocalProfiler { private int maxMethodCallGraphSize = 2000; private final Profiler profiler; public ThreadLocalProfiler(Profiler profiler) { this.profiler = profiler; } private boolean isProfilerCode; private int level = 0; private int count = 0; private LinkedList<MethodCallDto> methodCallsQueue = new LinkedList<MethodCallDto>(); private List<MethodCallDto> finishedMethodCalls = new ArrayList<MethodCallDto>(maxMethodCallGraphSize); private MethodCallSummaryDto contextMethodCallSummary; // todo: find out why some method ids are missing? private MethodCallSummaryDto rootContextMethodCallSummary; protected void preEnterConstructorImpl(long methodId) { enterMethodImpl(methodId, null, null); } protected void enterConstructorImpl(long methodId, Object object, Object[] arguments) { if (isProfilerCode) return; try { isProfilerCode = true; MethodCallDto contextMethodCallDto = methodCallsQueue.element(); if (methodId == contextMethodCallDto.methodId) { if (null != object) { contextMethodCallDto.actualClassId = profiler.generateClassIdAndRegisterIfAbsent(object.getClass()); contextMethodCallDto.flags |= 1 << MethodCallDto.ACTUAL_CLASS_ID_SET_FLAG; } } } finally { isProfilerCode = false; } } protected void enterMethodImpl(long methodId, Object object, Object[] arguments) { if (isProfilerCode) return; try { isProfilerCode = true; level++; //MethodCallDto currentMethodCallDto = new MethodCallDto(profiler.generateMethodCallId(), methodId); MethodCallDto currentMethodCallDto = MethodCallDtoFactory.getMethodCallDtoFromPool(); currentMethodCallDto.methodCallId = profiler.generateMethodCallId(); currentMethodCallDto.methodId = methodId; currentMethodCallDto.executionTime = System.currentTimeMillis(); if (null != object) { Class clazz = object.getClass(); long classId = profiler.generateClassIdAndRegisterIfAbsent(clazz); currentMethodCallDto.actualClassId = classId; currentMethodCallDto.flags |= 1 << MethodCallDto.ACTUAL_CLASS_ID_SET_FLAG; } if (level > 1) { currentMethodCallDto.callerId = methodCallsQueue.element().methodCallId; currentMethodCallDto.flags |= 1 << MethodCallDto.CALLER_ID_SET_FLAG; } methodCallsQueue.addFirst(currentMethodCallDto); { // todo implement cpu profiling stuff MethodCallSummaryDto currentMethodCallSummary; if (null == contextMethodCallSummary) { currentMethodCallSummary = new MethodCallSummaryDto(); rootContextMethodCallSummary = currentMethodCallSummary; } else { currentMethodCallSummary = contextMethodCallSummary.getCallee(methodId); } contextMethodCallSummary = currentMethodCallSummary; contextMethodCallSummary.methodId = methodId; contextMethodCallSummary.invocationCount++; contextMethodCallSummary.startTime = System.nanoTime(); } } finally { isProfilerCode = false; } } public void dump() { System.out.println(Thread.currentThread().getId() + " thread level is " + level); System.out.println(count); System.out.println(contextMethodCallSummary); System.out.println(rootContextMethodCallSummary); } protected void leaveMethodImpl(boolean isVoid, boolean isThrowsException, Object result) { if (isProfilerCode) return; try { isProfilerCode = true; // debug(false); level--; count++; MethodCallDto contextMethodCallDto = methodCallsQueue.removeFirst(); contextMethodCallDto.executionTime = System.currentTimeMillis() - contextMethodCallDto.executionTime; if (!isVoid) contextMethodCallDto.flags |= 1 << MethodCallDto.RETURN_VALUE_FLAG; if (isThrowsException) contextMethodCallDto.flags |= 1 << MethodCallDto.THROW_EXCEPTION_FLAG; finishedMethodCalls.add(contextMethodCallDto); { // Begin cpu profiler stuff if (isThrowsException) contextMethodCallSummary.exceptionCount++; contextMethodCallSummary.executionTime += System.nanoTime() - contextMethodCallSummary.startTime; } if (0 == level) { // Method call graph building finished profiler.processMethodCall(finishedMethodCalls, rootContextMethodCallSummary, true); count = 0; finishedMethodCalls.clear(); rootContextMethodCallSummary = null; } else { // Method call graph building in progress if (0 == count % maxMethodCallGraphSize) { if (0 == count % (maxMethodCallGraphSize * 5)) { profiler.processMethodCall(finishedMethodCalls, rootContextMethodCallSummary, false); } else { profiler.processMethodCall(finishedMethodCalls, null, false); } finishedMethodCalls.clear(); } } contextMethodCallSummary = contextMethodCallSummary.caller; } finally { isProfilerCode = false; } } public int getMaxMethodCallGraphSize() { return maxMethodCallGraphSize; } public void setMaxMethodCallGraphSize(int maxMethodCallGraphSize) { this.maxMethodCallGraphSize = maxMethodCallGraphSize; // todo resize finishedMethodCalls } }