0

In "Java Performance The Definite Guide" there's an example showing problems with writing a microbenchmark. The code is something like this:

public void test(){
    double l;
    long then = System.currentTimeMillis();
    for (int i = 0; i < n; i++) {
        l = fib(50);
    }
    long now = System.currentTimeMillis();
    System.out.println("Time: " + (now - then));
}

The book mentions that "A smart compiler will end up executing this code" :

long then = System.currentTimeMillis();
long now = System.currentTimeMillis();
System.out.println("Elapsed time: " + (now - then));

I see that "l" is a local unused variable, and it would make sense to ignore it , but I don't see how it's done or how to prove that it works like this. I tried running the code and it seems that the fib() method is executed. I also looked at the .class file and all the lines are included. How do I check that it works as mentioned above ?

6
  • Compilers have different optimization settings and there are different compilers. Also it depends on your fib() method. If the method doesn't use any variables of a class and is fully self-contained, then it will be optimized away. As soon as it has sideeffects on the state of an object, the compiler has to execute it. Commented Feb 6, 2016 at 19:28
  • The compiler would require to know that fib() is a pure function. If it is, then it is safe to remove the loop and the variable. If the compiler has this information, it can safely optimize it. Commented Feb 6, 2016 at 19:31
  • Also printing counts as a side effect. Commented Feb 6, 2016 at 19:33
  • There is no such check as that would be contradicting. If you are able to detect whether the code has been executed, the compiler can’t optimize it away. The compiler elides the code when it makes no difference (besides performance). Commented Feb 6, 2016 at 19:39
  • fib() is a recursive implementation of fibonacci and no printing , so yes it's a "pure function". Commented Feb 6, 2016 at 20:09

2 Answers 2

3

You are mixing up the Java source code to bytecode compiler (like javac) and HotSpot’s Just-In-Time compiler. javac doesn’t perform optimizations, therefore you won’t see optimizations in the .class files.

It’s the HotSpot engine, or generally the JVM, which will perform optimizations based on analysis of the code and the program’s runtime behavior. You can’t see these effects (besides a performance difference), because anything you can do to detect a difference, like placing a print statement (or anything with a side effect) or setting a breakpoint inside the method, will disable the optimization, as, of course, optimizations must not change the semantic of the running program.

However, the result of the detection method may still be a disguise. When you place a statement like System.out.println("hello"); inside your method, the string "hello" will be printed accordingly, but seeing the hello message doesn’t prove that the numeric calculation did happen, if its result is still unused.

Sign up to request clarification or add additional context in comments.

Comments

0

To check what the compiler does, you can disassemble the class with javap -c. Relevant parts of the output from disassembling the compiled version of your code:

   0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
   3: lstore        4
   5: iconst_0
   6: istore        6
   8: iload         6
  10: iload_1
  11: if_icmpge     27
  14: aload_0
  15: bipush        50
  17: invokevirtual #3                  // Method fib:(I)D
  20: dstore_2
  21: iinc          6, 1
  24: goto          8
  27: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J

The for-loop starts at 8, increasing the loop-counter is at 21, looping at 24.

However, I tried converting this to C and compiling with gcc -c -O3, then the entire for-loop is removed.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.