Friday 22 April 2011

Another simplistic Groovy and Java comparison

I noticed that the home page for one of our web apps was very slow and that the speed decrease was directly (linear) related to the number of items on the page. This was good and gave me a good place to start.

The webapp is a Groovy web app using Spring (not grails) and is backed by the most excellent mongodb.

So, firing up jprofiler and just hydrating a bunch of items that would appear on the home page showed it took 903 seconds to load 7143 items. Wow - too slow. Looking at the netIO threads shows that only 16.5 seconds are spent waiting for Mongo. Considering there are hundeds of thousands of lookups (each item is pretty large and has many associations), I was pleasantly surprised.

This unfortunately meant the cost was in my code :) shucks.

The cpuview in jprofiler didn't really point out any obvious candidates (i.e. the time was spread equally amongst lots of methods).

The code itself is written in groovy and uses a lot of closures and method calls. I thought I would run a little experiment myself to see exactly how much this costs. Turns out that it costs *a lot*.

The experiment basically called a gazillion loops, which is pretty similar to the code I am profiling. The performance code:

package sandbox.performance;
public class TestPerformance {
private static final int ITERATIONS = 1000000;
public static void main(String[] args) {
long groovyDuration = testGroovy();
long javaDuration = testJava();

System.out.println("Groovy: " + groovyDuration + ", java: " + javaDuration);
}

private static long testJava() {
JavaClass counter = new JavaClass();
long start = System.currentTimeMillis();


for (int i=0; i
counter.callPlusOneTenTimesTenTimes();

}
long end = System.currentTimeMillis();
return end - start;
}

private static long testGroovy() {
GroovyClass counter = new GroovyClass();

long start = System.currentTimeMillis();

for (int i=0; i
counter.callPlusOneTenTimesTenTimes();

}
long end = System.currentTimeMillis();
return end - start;
}
}

JavaClass:

package sandbox.performance;

class JavaClass {

int callPlusOneTenTimesTenTimes() {
int total = 0;
for (int i = 0; i < 10; i++) {
total += callPlusOneTenTimes();
}
return total;
}

int callPlusOneTenTimes() {
int total = 0;
for (int i = 0; i < 10; i++) {
total += plusOne(i);
}
return total;
}

int plusOne(int x) {
return x + 1;
}
}

GroovyClass:

package sandbox.performance

class GroovyClass {

int callPlusOneTenTimesTenTimes() {
int total = 0
0..10.each { total += callPlusOneTenTimes()}

total
}

int callPlusOneTenTimes() {
int total = 0
0..10.each { int x -> total += plusOne(x)}

total
}

int plusOne(int x) {
x + 1
}
}

(I wish I could figure out the tags for code!)

The results were pretty terrifying: Groovy: 1759, java: 4

Wow - groovy is 439.75 times slower!!!

(This is running on ubuntu 11.04 with sun-java6-jdk and groovy-1.7.5)

And whilst this test is pretty simple it turns out to be pretty similar to the production
code. Time to rewrite it in Java I guess!



No comments:

Post a Comment