Tuesday, March 23, 2010

No time for Windows

I'm timing code on Windows and I notice calls take either 0ms or 15ms. Odd. A little research reveals the culprit: Windows. (Although apparently fixed in Windows 7.) How to address this?

If I am simply timing code I'll use System.nanoTime(), but in my case I am relying on a software clock buried deeply in a library which calls System.currentTimeMillis(). But I can fix that code!

I need to continue using wall-clock millis but I'd like actual millisecond granularity. My solution:

class ActualMillis {
    private final long millis = System.currentTimeMillis();
    private final long nanos = System.nanoTime();

    public long currentTimeMillis() {
        return millis + (System.nanoTime() - nanos) / 1000000;

The idea here is to record a snapshot of "now" at construction, and then use offsets from the snapshot on query. This addresses two issues at once:

  1. Millis have wall-clock accuracy but 15ms precision.
  2. Nanos have no accuracy but better than 1ms precision.

But still some things bother me:

  • Will this drift over long periods of time? I ran a series of tests over a few minutes or less, and there was no drift, but I have not tried full day or multi-day runs.
  • The contract for System.nanoTime() is difficult. I believe dividing by 1,000,000 obliterates problems like backwards time, but I cannot prove it (although Java 7 seems to address this).
  • What happens on different hardware than mine, on different JVMs (1.6.0_18), on different versions of Windows or perhaps if I just hold my breath wrong? I really cannot say.
  • The voodoo factor. This code is non-obvious and needs explication. I do not trust explications.

Other solutions very welcome.

Post a Comment