[Android] For-Loop Performance Oddity
- by Jack Holt
I just noticed something concerning for-loop performance that seems to fly in the face of the recommendations given by the Google Android team. Look at the following code:
package com.jackcholt;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class Main extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
loopTest();
finish();
}
private void loopTest() {
final long loopCount = 1228800;
final int[] image = new int[8 * 320 * 480];
long start = System.currentTimeMillis();
for (int i = 0; i < (8 * 320 * 480); i++) {
image[i] = i;
}
for (int i = 0; i < (8 * 320 * 480); i++) {
image[i] = i;
}
Log.i("loopTest", "Elapsed time (recompute loop limit): " + (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
for (int i = 0; i < 1228800; i++) {
image[i] = i;
}
for (int i = 0; i < 1228800; i++) {
image[i] = i;
}
Log.i("loopTest", "Elapsed time (literal loop limit): " + (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
for (int i = 0; i < loopCount; i++) {
image[i] = i;
}
for (int i = 0; i < loopCount; i++) {
image[i] = i;
}
Log.i("loopTest", "Elapsed time (precompute loop limit): " + (System.currentTimeMillis() - start));
}
}
When I run this code I get the following output in logcat:
I/loopTest( 726): Elapsed time (recompute loop limit): 759
I/loopTest( 726): Elapsed time (literal loop limit): 755
I/loopTest( 726): Elapsed time (precompute loop limit): 1317
As you can see the code that seems to recompute the loop limit value on every iteration of the loop compares very well to the code that uses a literal value for the loop limit. However, the code that uses a variable which contains the precomputed value for the loop limit is significantly slower than either of the others. I'm not surprised that accessing a variable should be slower that using a literal but why does code that looks like it should be using two multiply instructions on every iteration of the loop so comparable in performance to a literal?
Could it be that because literals are the only thing being multiplied, the Java compiler is optimizing out the multiplication and using a precomputed literal?