Thursday, July 11, 2013

Performance of checking computer clock

Very often we check computer clock using either System.currentTimeMillis() or System.nanoTime(). Often we call these methods to check how long certain part of our program runs to improve performance. But how much does the call of mentioned methods cost? Or by other words

How long does it take to ask "What time is it now?"

I asked myself this question and wrote the following program.

public static void main(String[] args) {
long tmp = System.nanoTime();
long before = System.nanoTime();
for (int i = 0; i < 1000_000_000; i++) {
// do the call
}

long after = System.nanoTime();
System.out.println((after - before) / 1000_000);
}

Then I replaced the comment "do the call" with interesting code fragments and measured the time. Here are my results.

Code Elapsed time, ms
nothing 5
call of foo() {return 0;} 5
f+=f 320
call of foo() {return f+=f;} where f is a class level static variable initiated to System.nanoTime() 325
call of System.nanoTime() 19569
call of System.currenTimeMillis() 22639

This means that:

  1. method that just returns constant is not executed at all. Call of method that returns 0 takes exactly the same time as doing nothing.
  2. call of method itself does not take time. Execution of f+=f and call of method that does the same take exactly the same time. We have to say "thanks" to JVM that optimizes code at runtime and  uses JIT.
  3. Call of currentTimeMillis() is about 10% heavier than nanoTime()
  4. Both methods of taking time are comparable with ~65 arithmetic operations. 

Conclusions

  1. Checking computer clock itself can take time when it is used for measurement of performance of relatively small pieces of code. So, we should be careful doing this. 
  2. Using nanoTime() is preferable when checking time period not only because it gives higher precision and is not sensitive to changing of computer clock but also because it runs faster. Moreover this method returns more correct results because it is using monotonic clock. It guaranties that if you perform 2 consequent calls the second call returns number greater than previous that is not guaranteed when executing currentTimeMillis().
  3. Do not try to optimize code by manual inlining of your logic. JVM does it for us at runtime. Indeed running arithmetic operation directly or by calling method that contains only this operation take exactly the same time. 

Acknowledgements

I would like to thank Arnon Klein for his valuable comments.