According to its documentation, System.nanoTime returns nanoseconds from some fixed but arbitrary start time. However, on all x64 machines, I tried the code below, there were temporary transitions moving this fixed start time. There may be some flaw in my method to get the correct time using an alternative method (here, currentTimeMillis). However, the main purpose of measuring relative times (durations) is also adversely affected.
I ran into this problem trying to measure delays when comparing different queues with LMAX Disruptor, where sometimes very negative delays occur. In these cases, the start and end time stamps were created by different threads, but the delay was calculated after the completion of these threads.
My code here takes time using nanoTime, computes a fixed origin in currentTimeMillis time, and compares this origin between calls. And since I have to ask a question here: what is wrong with this code? Why does he abide by contract breaches with a fixed origin? Or is it not so?
import java.text.*; public class TimeCoherencyTest { static final int MAX_THREADS = Math.max( 1, Runtime.getRuntime().availableProcessors() - 1); static final long RUNTIME_NS = 1000000000L * 100; static final long BIG_OFFSET_MS = 2; static long startNanos; static long firstNanoOrigin; static { initNanos(); } private static void initNanos() { long millisBefore = System.currentTimeMillis(); long millisAfter; do { startNanos = System.nanoTime(); millisAfter = System.currentTimeMillis(); } while ( millisAfter != millisBefore); firstNanoOrigin = ( long) ( millisAfter - ( startNanos / 1e6)); } static NumberFormat lnf = DecimalFormat.getNumberInstance(); static { lnf.setMaximumFractionDigits( 3); lnf.setGroupingUsed( true); }; static class TimeCoherency { long firstOrigin; long lastOrigin; long numMismatchToLast = 0; long numMismatchToFirst = 0; long numMismatchToFirstBig = 0; long numChecks = 0; public TimeCoherency( long firstNanoOrigin) { firstOrigin = firstNanoOrigin; lastOrigin = firstOrigin; } } public static void main( String[] args) { Thread[] threads = new Thread[ MAX_THREADS]; for ( int i = 0; i < MAX_THREADS; i++) { final int fi = i; final TimeCoherency tc = new TimeCoherency( firstNanoOrigin); threads[ i] = new Thread() { @Override public void run() { long start = getNow( tc); long firstOrigin = tc.lastOrigin;
Now I have made small changes. Basically, I bind nanoTime calls between two currentTimeMillis calls to see if a thread has been ported (which should take more than the current TimeMillis resolution). In this case, I ignore the loop cycle. In fact, if we know that nanoTime is fast enough (like on newer architectures like Ivy Bridge), we can copy to currentTimeMillis with nanoTime.
Now long jumps of 10 ms have disappeared. Instead, we count when we get more than 2 ms from the first source per stream. On the computers that I tested, for a run time of 100, there are always about 200,000 transitions between calls. It is for these cases that I think that either currentTimeMillis or nanoTime may be inaccurate.
java multithreading nanotime
Ralf h
source share