tags:

views:

6488

answers:

8

As documented here, on x86 systems. Java's System.nanoTime() returns the time value using a cpu specific counter. Now consider the following case I use to measure time of a call -

long time1= System.nanotime();
foo();
long time2 = System.nanotime();
long timeSpent = time2-time1;

Now in a multi core system, it could be that after measuring time1, the thread is scheduled to a different processor whose counter is less than that of the previous cpu. Thus we could get a value in time2 which is less than time1. Thus we would get a negative value in timeSpent.

Considering this case, isnt it that System.nanotime is pretty much useless for now?

Edit: I know that changing the system time doesnt affect nanotime. that is not the problem i describe above. The problem is that each cpu will keep a different counter since it was turned on. This counter can be lower on the 2nd cpu compared to the first cpu. Since the thread can be scheduled by the OS to the 2nd cpu after getting time1, the value of timeSpent may be incorrect and even negative.

A: 

No its not..it just depends on your CPU, check High Precision Event Timer for how/why things are differently treated according to CPU.

Basically, read the source of your Java and check what your version does with the function, and if it works against the cpu you will be running it on.

IBM even suggests you use it for performance benchmarking. (2008 post but updated)

Ric Tokyo
As all implementation defined bahaviour, "caveat emptor!"
David Schmitt
A: 

The Java 5 documentation also recommends using this method for the same purpose.

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

Java 5 API Doc

+2  A: 

This doesn't seem to be a problem on a Core 2 Duo running Windows XP and JRE 1.5.0_06.

In a test with three threads I don't see System.nanoTime() going backwards. The processors are both busy, and threads go to sleep occasionally to provoke moving threads around.

[EDIT] I would guess that it only happens on physically separate processors, i.e. that the counters are synchronized for multiple cores on the same die.

starblue
It probably wont happen all the time, but due to the way nanotime() is implemented the possibility is always there.
pdeva
I would guess that it only happens on physically separate processors, i.e. that the counters are synchronized for multiple cores on the same die.
starblue
+10  A: 

I did a bit of searching and found that if one is being pedantic then yes it might be considered useless...in particular situations...it depends on how time sensitive your requirements are...

Check out this quote from the Java Sun site:

The real-time clock and System.nanoTime() are both based on the same system call and thus the same clock.

With Java RTS, all time-based APIs (for example, Timers, Periodic Threads, Deadline Monitoring, and so forth) are based on the high-resolution timer. And, together with real-time priorities, they can ensure that the appropriate code will be executed at the right time for real-time constraints. In contrast, ordinary Java SE APIs offer just a few methods capable of handling high-resolution times, with no guarantee of execution at a given time. Using System.nanoTime() between various points in the code to perform elapsed time measurements should always be accurate.

Java also has a caveat for the nanoTime() method:

This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary time (perhaps in the future, so values may be negative). This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are made about how frequently values change. Differences in successive calls that span greater than approximately 292.3 years (263 nanoseconds) will not accurately compute elapsed time due to numerical overflow.

It would seem that the only conclusion that can be drawn is that nanoTime() cannot be relied upon as an accurate value. As such, if you do not need to measure times that are mere nano seconds apart then this method is good enough even if the resulting returned value is negative. However, if you're needing higher precision, they appear to recommend that you use JAVA RTS.

So to answer your question...no nanoTime() is not useless....its just not the most prudent method to use in every situation.

mezoid
> this method is good enough even if the resulting returned value is negative. I dont get this, if the value in timespent is negative, then how is it useful at all in measuring the time taken in foo()?
pdeva
its ok because all you are worried about is the absolute value of the difference. ie if your measurement is time t where t = t2 - t1 then you want to know |t|....so what if the value is negative...even with the multi core problem the impact is rarely going to be a few nanoseconds anyway.
mezoid
Also, according to the Java docs, you can still get a negative value even on a single core machine since you have no guarantee of when your code will be executed..."the value represents nanoseconds since some fixed but arbitrary time (perhaps in the future, so values may be negative)"...
mezoid
mezoid: If that was true, i.e. if the "fixed time" could change at any moment, then nanoTime would be completely useless because you have no way to tell. If the fix point is set during startup, it must not change and t2 must always be >= t1. Which means there is a bug.
Aaron Digulla
t2 >= t1 is also true if t0 (the start time) is < 0.
Aaron Digulla
To backup @Aaron: both t2 and t1 might be negative but (t2-t1) must not be negative.
J.F. Sebastian
aaron: that is exactly what my point is. t2-t1 should never be negative otherwise we have a bug.
pdeva
A: 

Your question boils down to "did the guys who implemented the JVM for the box I am using implement this system function correctly".

The answer is "Geez, one would hope so!".

Having said that, if System.nanoTime in fact does glitch on muti-core machines, it wouldn't be the first JVM bug requiring a fix.

+1  A: 

Linux corrects for discrepancies between CPUs, but windows does not.

I suggest you assume System.nanoTime() is only accurate to around 1 micro-second.

A simple way to get a longer timing is to call foo() 1000 or more times and divide the time by 1000

Peter Lawrey
Could you provide a reference (behaviour on Linux and Windows)?
J.F. Sebastian
+2  A: 

You might like this better:

http://juliusdavies.ca/nanotime/

But it copies a DLL or Unix .so (shared object) file into the current user's home directory so that it can call JNI.

Some background information is on my site at:

http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html

Julius Davies
+1 for referencing and appears to be correct. Welcome to stack overflow :)
Russell
A: 

Absolutely not useless. Timing aficionados correctly point out the multi-core problem, but in real-word applications it is often radically better than currentTimeMillis().

When calculating graphics positions in frame refreshes nanoTime() leads to MUCH smoother motion in my program.

And I only test on multi-core machines.

Yuvi Masory