2

Is the Java compiler smart enough to optimize loop below, by extracting the

Double average = new Double( totalTime / callCount ); 

out of the for loop?

public double computeSD( Set values, int callCount, long totalTime ) {
  double diffs = 0.0d; 
  for( Iterator i=values.iterator(); i.hasNext(); ) {
    double value = ( ( Double )i.next() ).doubleValue(); 
    Double average = new Double( totalTime / callCount ); 
    diffs += ( value – average.doubleValue() ) * ( value – average.doubleValue() );
  } 
  double variance = diffs / callCount;
  return Math.sqrt( variance );
}
Charles
  • 50,943
  • 13
  • 104
  • 142
Lydon Ch
  • 8,637
  • 20
  • 79
  • 132
  • 1
    Flow analysis at the JIT compiler end would easily tell you that the `Double` objects aren't escaping anywhere, so only their contained values are being used. I dare say that the function above should be easy to optimise in the fashion sought by the OP. – C. K. Young Mar 06 '10 at 03:33
  • I doubt it. Using a primitive double, and making callCount and totalTime final might help, but I still doubt it. – Thilo Mar 06 '10 at 03:34
  • 1
    @Thilo: Using `final` for local variables has no effect on the bytecode. Certainly, the constancy or not of a variable is for the JIT compiler to determine. – C. K. Young Mar 06 '10 at 03:37
  • 1
    In order to help the compiler, make as many variables final as possible. As far as I can see, you can make i, value, average, values, callCount, totalTime, and variance final. – Chris Dennett Mar 06 '10 at 03:47
  • 2
    @Chris Dennett: Yes and no. Making local variables `final` is mostly an aid to the programmer, to discourage (disallow) them from reassigning a variable (which does help the compiler). But if you actually assign to each local variable once only as a habit, then the presence or absence of `final` doesn't change the bytecode output at all. (The story is different with fields. I do have a policy of making as many fields `final` as possible.) – C. K. Young Mar 06 '10 at 03:51

5 Answers5

4

Java will not and can not extract it from the loop. Any use of the 'new' keyword will always result in a new object being created. You would be better off using Double.valueOf()

See the javadoc for Double.valueOf(double):

"Returns a Double instance representing the specified double value. If a new Double instance is not required, this method should generally be used in preference to the constructor Double(double), as this method is likely to yield significantly better space and time performance by caching frequently requested values."

If you used this method it would return the same object every time, thus reducing the number of objects created and increasing performance.

However, using valueOf is still not the answer for you!

valueOf is still a method call, and method calls do not get optimized away. It will call valueOf every iteration of the loop. Look through your method and count the method calls. Right now it is 6, including hasNext and new Double, which is similar to a method call. These will all happen every time, and no java optimization will change that. You are better off refactoring to remove as many method calls as possible from the loop.

Mysticial
  • 464,885
  • 45
  • 335
  • 332
Dan Bliss
  • 1,694
  • 13
  • 10
4

Nothing prevents the bytecode compiler (java->bytecode) from performing optimizations. When I worked at Symantec, and they did a Java IDE, the compiler write did look into putting some optimizations into our compiler but said nobody (in the outside world) seemed to be interested and the focus was on the Just In Time (JIT) compiler that is roughly the same as HotSpot in modern Sun VMs.

There is nothing that prevents a bytecode compiler from performing optimizations, but I am not aware of any that do so. There is huge focus on runtime optimizations, but those are pretty much hidden at runtime.

So, the source->bytecode compiler probably does not optimize it but the VM probably does. If you are on something like an Android then it probably performs no runtime optimization.

TofuBeer
  • 60,850
  • 18
  • 118
  • 163
2

This may seem like an obvious optimization at first, but I don't think so, since it involves object instantiation. Granted, it's an instantiation of an immutable primitive box type, but that still doesn't guarantee that there's no side effect.

I don't think any current compiler can optimize this. For this to be optimized, the compiler must be told that some classes have special properties (which can be a dangerous proposition given that things may change in the future). That is, the compiler must be told specifics of the API. This can not be optimized at the language-level alone.

If you use double, however, it's much more likely to be optimized (e.g. using the loop-invariant code motion technique).

polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
2

If you really want to be sure, the answers to this question tell you how to see the native code that the JIT compiler produces.

Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

Not really. The compiler just writes out byte-code. If anything optimized the code, it'd be the Java Virtual machine and that probably depends on the platform, implementation and execution conditions...

Frank V
  • 25,141
  • 34
  • 106
  • 144
  • Are you sure that Java compilers don't do even obvious optimizations? – Mike Daniels Mar 06 '10 at 03:24
  • 2
    @Mike: The JIT compiler does. The source-to-bytecode compiler doesn't, but that's because it's not the place of the bytecode to be optimised, since it has to go through the JIT anyway. – C. K. Young Mar 06 '10 at 03:29
  • 2
    @Matthew: Impedance mismatch alert---you and I are thinking of the JIT compiler, whereas I think Frank is only thinking of javac. The JIT compiler is where the heavyweight optimisations occur. – C. K. Young Mar 06 '10 at 03:31
  • 1
    Ok. So the JIT will do the optimization. Based on the code above, how will it optimize the byte code on execution? – Lydon Ch Mar 06 '10 at 03:59
  • The bytecode compiler really didn't perform a lot of obvious optimisations a while back, as I recall. When I was developing a 4k game for a competition (my hard disk crashed and I lost lots of progress -- argh!) I found out many interesting things which reduced the size of the source code significantly. For instance, trying to be clever with variables by placing them outside of the current iterative loop and reusing them often makes the code bigger. The 4k game applet is here if anyone wants to see: http://codeknight.net/t4k/ :) – Chris Dennett Mar 06 '10 at 05:30