Reputation: 1087
I was experimenting with predicates. I tried to implement the predicate for serializing issues in distributed systems. I wrote a simple example where the test function just returns true. I was measuring the overhead, and I stumbled upon this interesting problem. Accessing array in for loop is 10 times slower compared to direct access.
class Test {
public boolean test(Object o) { return true; }
}
long count = 1000000000l;
Test[] test = new Test[3];
test[0] = new Test();
test[1] = new Test();
test[2] = new Test();
long milliseconds = System.currentTimeMillis();
for(int i = 0; i < count; i++){
boolean result = true;
Object object = new Object();
for(int j = 0; j < test.length; j++){
result = result && test[j].test(object);
}
}
System.out.println((System.currentTimeMillis() - milliseconds));
However, the following code is almost 10 times faster. What can be the reason?
milliseconds = System.currentTimeMillis();
for(int i=0 ; i < count; i++) {
Object object = new Object();
boolean result = test[0].test(object) && test[1].test(object) && test[2].test(object);
}
System.out.println((System.currentTimeMillis() - milliseconds));
Benchmark results on my i5.
4567 msec for for loop access
297 msec for direct access
Upvotes: 3
Views: 547
Reputation: 20059
You are committing almost every basic mistake you can make with a microbenchmark.
Upvotes: 1
Reputation: 13957
Due to the predictable result of test(Object o)
the compiler is able to optimize the second piece of code quite effectively. The second loop in the first piece of code makes this optimization impossible.
Compare the result with the following Test
class:
static class Test {
public boolean test(Object o) {
return Math.random() > 0.5;
}
}
... and the loops:
long count = 100000000l;
Test[] test = new Test[3];
test[0] = new Test();
test[1] = new Test();
test[2] = new Test();
long milliseconds = System.currentTimeMillis();
for(int i = 0; i < count; i++){
boolean result = true;
Object object = new Object();
for(int j = 0; j < test.length; j++){
result = result && test[j].test(object);
}
}
System.out.println((System.currentTimeMillis() - milliseconds));
milliseconds = System.currentTimeMillis();
for(int i=0 ; i < count; i++) {
Object object = new Object();
boolean result = test[0].test(object) && test[1].test(object) && test[2].test(object);
}
System.out.println((System.currentTimeMillis() - milliseconds));
Now both loops require almost the same time:
run:
3759
3368
BUILD SUCCESSFUL (total time: 7 seconds)
p.s.: check out this article for more about JIT compiler optimizations.
Upvotes: 1
Reputation: 288
If loop header takes one unit time to execute the in first solution loop header evaluations takes 3N units of time. While in direct access it takes N.
Other than loop header overhead in first solution 3 && conditions per iteration to evaluate while in second there are only 2.
And last but not the least Boolean short-circuit evaluation which causes your second, faster example, to stop testing the condition "prematurely", i.e. the entire result evaluates to false if first && condition results false.
Upvotes: 0