0

A run a simple test JDK 1.7.0_45 (Windows 7, 64bit):

Test 1:

long start = System.nanoTime();
for (int i=0; i < 1000000; i++) {
    System.currentTimeMillis();
}

elapsed = System.nanoTime() - start;

Versus Test 2:

long start = System.nanoTime();
long adjust = 313231;
for (int i=0; i < 1000000; i++) {
    long result = System.currentTimeMillis() + adjust;
}

elapsed = System.nanoTime() - start;

On my system, first test ran at around 28 nano/call. The second at around 1250 nano/call. That is a whopping 44x overhead. Can anyone explain such a huge difference?

5
  • 2
    optimizer knows that System.currentTimeMillis(); doesn't have side effects and just optimized the entire "native" call Commented Jul 16, 2014 at 10:38
  • I dont agree, you can create another call to wrap System.currentMillis() with my own and still get around the same 28 nano/call. The optimizer does call my wrapper method but addition adds a lot more overhead. I would expect addition to be faster. I am not sure I buy the optimizer eliminating the call altogether. Commented Jul 16, 2014 at 10:41
  • Why should the call in the first block be made? The result is never used. It will get optimized in a sense of "removed". Commented Jul 16, 2014 at 10:49
  • 1
    This is silly. Why don't you look at the generated byte code? My prediction is the compiler threw out the call, but it's easy enough for you to check.
    – david.pfx
    Commented Jul 16, 2014 at 14:19
  • Well, I dont think it is that silly. What if the method actually does something behind the scenes. I guess it is possible that compiler knows that currentTimeMillis() does and figured out that the statement does nothing and therefore avoided the call. But what if uit was my own native call that actually does something outside of the VM and I want to ignore the result of the call. I would have to do more experimentation. But I think in this case the compiler understands that calling currentTimeMillis() in this loop can be avoided. Commented Jul 16, 2014 at 15:36

1 Answer 1

3

Look at the generated byte code. One obvious explanation would be that your first call to currentTimeMillis() is so obviously useless that the optimizer removed it altogether, and the second isn't. There are countless similar and less similar possible reasons, and speculating about them without looking at what's actually going on is pretty useless.

5
  • Well I wrapped System.currentTimeMillis() with my call and return its value and use that in the loop and still get around 28 nano/call. The optimizer calls my call for sure, but the overhead is still in adition. Just seems like a lot more then I would expect, 44+ times? Just seems a lot. Commented Jul 16, 2014 at 10:43
  • I confirmed that the optimizer did not remove the call and calls my wrapped method around System.currentTimeMillis(). Anyway, puzzling. Commented Jul 16, 2014 at 10:47
  • Can you provide more information about how you confirmed that? Commented Jul 16, 2014 at 10:48
  • Keep a class local variable and assign result of System.currentTimeMillis() to the variable. Print it out affter all the runs have been done and convert to timestamp which shows last date. Commented Jul 16, 2014 at 11:02
  • My mistake. I think the answer is correct. The optimizer is eliminating the call somehow. I verified it by moving the location of result variable into a class scope and the overhead jumped from 28 nanos to over 1200 just by moving the variable declaration from method scope to class scope when calling System.currentMillis(). So I think the optimizer is eliminating the call altogether. Commented Jul 16, 2014 at 11:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.