简体   繁体   中英

Getting method execution time from Stack Trace

I have a small system sampler project that I have made in Java.

I want to find a way to get the method execution time (self-time) of methods from all threads, similar to VisualVM. However, I simply don't want to use any instrumentation.

So I have two main questions, a broad question and something slightly more specific for my case:

Broad question: Is there a way to calculate self-time of a method using solely Java + JMX? If yes, how accurate is your implementation?

More specific to my problem question: In my project, I can get the CPU time spent per method by sampling all thread stack traces, getting the delta CPU time between the samples and applying that to the top frame of the stack (in my data structure).

Could I infer a basic execution from this data and the length between samples?

Here is a simplified version of my code:

private static final ThreadMXBean MX = ManagementFactory.getThreadMXBean();
private long lastCpuTime;
private Map<Long, ThreadTimerData> threadCache = new HashMap<Long, ThreadTimerData>();

public void sample()
{
    final ThreadInfo[] threadInfos = MX.getThreadInfo( MX.getAllThreadIds(), Integer.MAX_VALUE );
    for( ThreadInfo threadInfo : threadInfos )
    {
        final long threadId = threadInfo.getThreadId();
        ThreadTimerData data = threadCache.get(threadId); // Just assume we already have this in our Map.

        final StackTraceElement[] trace = threadInfo.getStackTrace();
        if( trace == null )
        {
            continue;
        }

        final long cpuTime = MX.getThreadCpuTime( threadId );
        data.update(trace[0].getClassName() + "." + trace[0].getMethodName(), cpuTime - lastCpuTime); // Another map, holding the name string against the delta. 
    }

    lastCpuTime = cpuTime;
}

The sample method is being called at a 200ms interval (within it's own thread) -- this can be changed.

I believe I found the solution for those curious:

Essentially, if any element (method on the stack frame) is on top of the stack it is technically executing. We need to measure for how long this element has been there for, so we sample the stack trace at an interval. This also answers the 2nd part of my first question, the accuracy depends on the interval -- a shorter interval would mean a more meaningful self-time as there's a lesser chance another element appeared and disappeared on the stack between any two samples.

But I digress a bit, we get the time difference between the two sample times (ideally using nano second precision) and this gives us how long the method has been executing. We aggregate this after several samples until the method has stopped executing (when the element leaves the stack trace) or just called something else (a new element has been pushed onto the stack).

Once the stack has changed, we repeat the process. Everything on the stack is using CPU time, additionally. The tricky part of all of this is creating the most efficient data structure to store, retrieve and update the methods from the stack.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM