javamultithreadingthread-sleepsystem-clockcpu-time

Reliable cross-platform way to obtain the method time in Java


This question is not about benchmark.

I have a java thread cycle that should to operate close to a period time T:

public class MyRunnable implements Runnable {

    private final long period = 10000L; //period T, in this case 10 secs

    public void run() {
        while() {
            long startTime = this.getTime();

            this.doStuff();

            long endTime = this.getTime();
            long executionTime = endTime - startTime;
            if(executionTime < this.period) {
                long sleepTime = (this.period - executionTime);
                try {
                     Thread.sleep(sleepTime);
                } catch(InterruptedException iex) {/*handle iex*/}
            }
        }
    }

    private long getTime() {
        return System.currentTimeMillis();
    }

    private void doStuff() {/*do stuff*/}

} 

Of course, depending on the schedule premption choices, Thread.sleep(sleepTime) could be slightly greater than sleepTime. But, in average, this approach provides a close averaged approximation to the period T.

The problem

The method:

private long getTime() {
    return System.currentTimeMillis();
}

provides the wall clock reference time. If the machine's clock changes, forward or backwards, this implementation fails to provide a close approximation for the period T. For instance:

long t1 = getTime();
Thread.sleep(30000);
long t2 = getTime();
System.out.println(t2 - t1);

prints something like 204283 if someone manually changes the clock three minutes ahead while Thread.sleep(30000) "runs".

Since the system clock is always changing (timeserver synchronization, system load, user settings, etc...) using System.currentTimeMillis() is not realiable enough for my needs.

Failed solution

In order to provide a more robust time reference I tried the following implementation for getTime method:

long getTime() {
    long result;
    ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
    if (mxBean.isThreadCpuTimeSupported()) {
        result = mxBean.getCurrentThreadCpuTime()/1000000L;
    } else {
        throw new RuntimeException("unsupported thread cpu time");
    }
    return result;
}

The problem of getCurrentThreadCpuTime is that the resulting amount of time is the CPU time consumed by the Thread, not the time left at that instant. Time left when the Thread is sleeping or blocked is not taken in account. For example:

long t1 = getTime();
Thread.sleep(30000);
long t2 = getTime();
System.out.println(t2 - t1);

surprising prints "0" (zero) by the getCurrentThreadCpuTime getTime's implementation.

What I want

I guess that what I need is something like this:

private long getTime() {
    long cpuCycles = getAmountOfCPUCyclesSinceTheProgramStarted();
    long cpuFrequency = getCPUFrequency();
    long result = cpuCycles / cpuFrequency;
    return result;
}

The problem is that I didn't found a java way to implement getAmountOfCPUCyclesSinceTheProgramStarted() and getCPUFrequency() in a cross platform fashion.

Finally, my question is: how to obtain the spent time of a method in java in a reliable and cross-platform way?


Solution

  • Try using System.nanoTime(), it seems to be what you are looking for.

    From the docs:

    This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time.