Scala vs. Groovy: static typing is key to performance
Thursday September 6, 2007 by Derek Young
I was curious about the performance of two of the JVM based languages, Scala and Groovy, relative to Java itself. I suspected that by having more type information available at compile time Scala’s bytecode would look more like the output of javac and therefore have performance closer to that of straight Java.
I started with the Java version of the (somewhat notorious) Ray tracer language comparison benchmark that has been used to compare the performance of various languages. The benchmark generates a ray traced image of recursively positioned spheres. I took the minimal optimization version and ported it into both Scala and Groovy.
I kept the code as close to the Java version as possible. Neither Scala nor Groovy supports Java/C style
for loops, so I substituted the recommended loops in each language. Groovy doesn’t support inner classes so I had to pull some code out to the top level. Groovy uses BigDecimal for floating point literals, so I suffixed them all with “d” to make them doubles. I left all type declarations in the Groovy version, although Groovy programs are typically not written this way.
|ray.groovy||2h 31m 42s|
I was expecting the Groovy code to run longer than the Scala code but was shocked at the actual difference. All three versions of the code produce identical images: (fullsize here)
Because Scala knows the types of all variables, it produces floating point operations for floats and integer operations for ints, like Java. The compiled output of Groovy treats everything dynamically, determining at runtime which functions to use for simple operations and using objects like
java.lang.Double instead of
double. The more the bytecode looks like Java code the better it will perform.
Unlike most software, a ray tracer executes almost entirely in its own code, not in any external libraries or waiting for I/O. This highlights the difference between the three compilers, but most software will see less of a difference.
The Scala timings demonstrate that algorithms can be coded in Scala without much loss in performance, even for critical areas of code.
I should point out it’s possible I made a mistake in the translation from Java to Groovy, but I tried to make it as fair as I could. I would be interested in hearing if there is something I should have done differently that explains the difference.
All times recorded with
time from the command line, which does include startup overhead. With over a 2 hour difference this doesn’t matter.
OS: Ubuntu Feisty
time groovy ray.groovy 8 512
scala scalaRay 8 512
java ray 8 512