Inferring characteristics of the JVM threads implementation

The threads API of the JVM provides very limited control over the scheduling of the threads themselves, and this control is not guaranteed, but it is JVM implementation dependent. In order to better understand the way different implementations do thread scheduling, we devised a simple test application that within the constraints of the API itself tries to gather some information about the way the underlying JVM is handling scheduling of threads.

Design of the test application

The test application is composed of two classes:

tbegin = System.nanoTime();
while(!interrupted()) {
    counter++;
    if (counter/SAMPLERATE<t.length && counter%SAMPLERATE==0) 
        t[counter/SAMPLERATE]=System.nanoTime()-tbegin;
}

The source code can be found here.

Experiment conditions

The test was run on two systems:

The test length was set to 30 seconds to give chances of recording some number of contexts switches and the system activity was keep to a minimum in order to avoid as much as possible the noise introduced by other processes scheduled by the operating system.

Results

Linux system:




Windows system:




Analysis

A first general observation is that in both cases, the priority assigned to the threads did not really have a significant effect on the scheduling order. In both cases, threads with lower priority reached larger counts over the recorded time. The only clear exception was in the windows system for the thread with maximum priority ( =8 ), which kept running as far as samples were collected.

It is also noticeable, a clear distinction of active periods (with positive slope) and idle periods (flat curve, meaning the counter did not incremented during this time) in both cases, although the particular duration of the active/inactive periods is clearly OS dependent.

In the case of the windows system, there are some anomalies with the time values, due to the fact that the fuction nanoTime() did not return always increasing values.

The next couple of figures show the zooming of the previous ones, to give some more detail about the schedule:






For the linux case, the time a thread is active is constant and it is approximately 0.1 seconds. The idle periods are 0.8 seconds. Clearly the time-slot of different threads overlap. The figure also illustrates two scheduling periods, showing exactly the same sequence of thread activations, signaling a round-robin schedule, that looking back at the original picture, holds all the time except during the startup phase.




In the windows case, zooming on a period where most of the threads were active and not estrange measurements appear, it is interesting to observe that there is not overlap between threads, which makes us believe the JVM threads are actual OS threads. In many cases also, the termination and the beginning periods of consecutive threads coincide, reinforcing the previous conclusion. The active period of a thread is constant and is 0.19 seconds.



An improvement on the experiment

A nice suggestion we received was to modify the experiment to begin taking samples after some stabilization delay. The modification to the code is trivial and the results in the Linux case are shown in the following figures:







The interesting observation of the first graph is that threads with priority 2 and 3 achieved a slight larger rate of progress, having low priorities. The second one shows three scheduling cycles, where the same round-robin policy is observed with quantum of 0.1 seconds.