System.nanoTime(): good or evil?

I’ve read quite a bit about System.nanoTime() in Java 1.5+, both on this forum and on the web, and here’s a bit of what I’ve learned:

  1. nanoTime attempts to use the most precise timer available, but can only be used to measure time intervals (not walltime) – fortunately, this is all you need in a game.

  2. I’ve read that nanoTime uses QueryPerformanceCounter and some have suggested that this can cause strage results on multi-core machines as well as on machines (like many laptops) that vary the clockspeed of the cpu

  3. somewhat in conflict with (2), I’ve also read that QueryPerformanceCounter is preferred to RDTSC (on Intel chips) since RDTSC does NOT take into account changes in clock speed (thus implying that QPC does…)

  4. In a simple loops that executes System.nanoTime() and stores the result in an array, I see values as low as 1.2 micro seconds, but values as high as 5000 micro seconds if I run the loop for 10000 iterations or so. Some people have noted that varying the clock speed of the CPU can cause discontinuities in the results of nanoTime(), so perhaps that explains the results, but it could also presumably be due to the OS running other processes.

The bottom line is: is there any consensus as to whether System.nanoTime() is good or evil? If evil, is there a suggested alternative timer?

If you need that level of accuracy in timing then its good.

As for what it exactly does underneath, thats platform dependent but if you see it actually create wrong results and you can reproduce it, you should bug report it.

QPC is pretty fragile. TGT is way more robust. However, its resolution is “only” 1msec.

LWJGL’s timer uses TGT on Windows (and currentTimeMillis elsewhere, because that already gives you a 1msec res on mac/linux).

It’s extremely trivial to reproduce. Use it on a dual core amd processor. After a while, the returned value starts diverging more and more as it retrieves it from a random core.

It basically makes the method totally worthless.

Has this been bug reported with the example? And is it a question of nanoTime not functioning properl, or Windows not functioning properly?

I wouldnt call it totally worthless in any case as I\'m using it quite successfully in my BHO client at the moment. Ofcourse I\'m only using it for split second timing. Timing in lower resolutions I do with System.currentTime Millis.

You could try to correct the diverging values a bit, although it won’t be extremely fast…


public class Clock
{
   private static final long max_difference_in_ns = 25L * 1000000L; // must be fairly high (Win98=55ms -> 120ms, WinXP=10ms -> 25ms)
   private static final long started_in_ms;
   private static final long started_in_ns;
   private static long correction_in_ns = 0L;

   static
   {
      started_in_ms = System.currentTimeMillis();
      started_in_ns = System.nanoTime();
   }

   public static final long nanoTime()
   {
      long elapsed_in_ns = System.nanoTime() - started_in_ns;
      long elapsed_in_ms = System.currentTimeMillis() - started_in_ms;

      long difference_in_ns = (elapsed_in_ms * 1000000L) - (elapsed_in_ns);

 // converge with factor 0.15

      if(difference_in_ns > max_difference_in_ns)
         correction_in_ns += difference_in_ns * 15 / 100;
      else if(difference_in_ns < -max_difference_in_ns)
         correction_in_ns -= difference_in_ns * 15 / 100;

      return correction_in_ns + elapsed_in_ns;
   }

   public static final long getTimingErrorNanos()
   {
      long elapsed_in_ns = System.nanoTime() - started_in_ns;
      long elapsed_in_ms = System.currentTimeMillis() - started_in_ms;

      return (elapsed_in_ms * 1000000L) - elapsed_in_ns;
   }

   public static final long getTimingCorrectionNanos()
   {
      return correction_in_ns;
   }
}

[quote=“Jeff,post:5,topic:29786”]
Unfortunately, I’m far too lazy and selfish to report it. :wink:

Dual core AMDs does something nasty with the timing. It’s a well known issue. Some games (painkiller, for example) won’t run at all unless you disable one core for them, and nanoTime works horribly bad unless you disable one core.
AMD, of course, claims it’s not a bug. People who depend on the timing the way they do are the people who get it wrong, but they did release a “fix” for it that’s basically just a program that synchronizes the timers every now and then.

The source code (scroll down) for my Infinite Mario Bros game contains a pretty bad work around for the bug after detecting it (ie after time has gone BACKWARDS once, as it does with nanoTime)

Hm it has occurred to me that you should be able to detect the divergence and start tracking two sets of values if you’re clever… but then again, who needs more than 1ms accuracy anyway?

Cas :slight_smile:

How would you know which one you read?

but you usually query the time on the gameloop-thread.
and shouldnt one thread stay on the same core usually?

I know nothing about dual core CPUs, but I can imagine software knows nothing about them having 2 cores… CPU just feeds data back the same way as normal ones. Again, this is only a assumption, as if there were difference new software should be written just for them.

no, not unless you set thread affinity - which you dont.

After reading this topic, I switched from System.nanoTime() to System.currentTimeMillis(), and my game runs alot smoother.

So, yes, System.nanoTime() is evil.

Note that the resolution of currentTimeMillis depends on the OS.
-win9x 50-55msec
-nt/2k/xp 10msec
-linux/mac 1msec

Heh, we’ve been whining for years for a high precision timer, and now it turns out to be evil.

I preferrably use LWJGL’s timer. You get 1ms precision regardless of OS and it just works.

[quote]-win9x 50-55msec
[/quote]
I’ve never seen such low precision on win9x, I always got about 10 ms precision on win98.

I always got 50-55msec on win98se.

However, you can sleep() less than that.

And I also prefer lwjgl’s timer. :wink:

nanoTime() seems to be a far better option than currentTimeMillis(), at least on Windows. As mentioned above, on Windows the Timer has a 50 ms resolution, far too less for games. But I never ran nanoTime() for a long time or on other PCs with AMD or somewhat. So it might have its drawbacks.

Regarding other timers, I am using 2D only and no GL or such stuff, can you suggest any timer to use? Or is the LWJGL Timer independent from 3D rendering?

-JAW

[quote] As mentioned above, on Windows the Timer has a 50 ms resolution…
[/quote]
That is, if you are running an ancient version of Windows which hardly anyone uses anymore. I myself never experienced timing resolutions that low, even on Win98 (which doesn’t mean no Win9x installation has timing resolutions that bad, though).

[quote]Regarding other timers, I am using 2D only and no GL or such stuff, can you suggest any timer to use? Or is the LWJGL Timer independent from 3D rendering?
[/quote]
I don’t think the LWJGL timer depends on OpenGL usage, but it seems to be a bit of overkill to use LWJGL only for its timer.
Why not use Slick too while you’re at it, if you need a good timer and the benefits of OpenGL combined with easy to use 2D rendering? :slight_smile:

I have measured currentTimeMillis() being 50 - 55 ms on Windows XP. Maybe it depends on some hardware like mainboard or processor. Maybe its just with Intel processors, or AMD, or such. I cant tell. But I am sure a lot of XP users can copy that currentTimeMillis performs poor on XP.

Or is it a Java 5 problem? Do you use the newest Version?

-JAW

I use XP pro and have a resolution of 20ms.