Basic thread profiling methodology

The underlying thread profiling technique we'll be looking at here involves periodically "polling" the JVM to ask it for the current point of execution of all currently alive threads. This is a kind of "passive" profiling technique in which we don't need to modify the code that we are profiling. (A technique that we won't be considering in this article is to "actively" inject code at key points for the purpose of profiling1.) The basic thread profiling procedure is thus as follows:

It's clear from this description that profiling isn't "free". Asking the JVM to take the stack trace snapshots, in addition to any processing we then do, has an impact.

It's also clear that this is essentially a sampling approach. We won't be able to tell with complete accuracy how long a thread spends in a particular place. For example, say we repeat the above process 20 times a second. When we are told that a thread is in a particular place and that place was different from the last time we sampled, that means that it has been there for some period between 0 and 1/20 seconds. (And even if it's the same place, we don't know that the thread actually stayed there for the whole time between the two instances when we sampled.) So we have to make some kind of best guess. Generally, the least effort option (and one that is good enough) is to simply assume that the method was running for the full 1/20 second (or whatever the sample period). The more frequently we sample, the more accurate our profile will be, but the more impact our profiling routine will have on the server or application that we're trying to profile.

Many systems can also provide us with information on how much CPU time (in user and kernel mode) a given thread has consumed. But even if we request this information, we are usually left with the same problem: if a thread has used X nanoseconds of CPU time since the last sample, we still don't know if that consumption all went on the line or method now being executed.

What this generally boils down to is:

For profiling a long-running server that executes similar functions over and over, this is actually quite good news. We can generally sample fairly infrequently (say, between 1 and 5 times a second), and simply leaving things going for a few hours to get enough samples. This will give us a good picture of generally where the server is spending its time.

Well, that's enough theory. On the next page, we'll look at how to profile threads in Java.


1. For example, at class loading we could inject code on entry to and exit from methods we were interested in, in order to measure how often threads were inside that method. This technique is more fiddly, although possible, in Java. Where the information sought is not very granular, this technique can minimise the impact of profiling, but it is generally less flexible than the technique we'll discuss here.