Tuesday, March 04, 2008

JRuby Performance

During my lunch today, I solved Problem 12 from Project Euler. As usual, I wrote the solution in Ruby and was surprised by just how long it took to calculate. It made me decide to try JRuby.

First, a note about the problem and my solution. The problem was to find the first triangle number (where the n_th triangle number is 1+2+3...+n) that has at least 500 divisors. My solution was pretty brute force. I took each triangle number and computed its prime factorization. For example 28 = 2^2 * 7^1. Thus the number of factors is (2+1)*(1+1) = 6. Generally if N = A^a * B^b * ... where A,B,.. are primes, then the number of factors is (a+1)*(b+1)*...

With all of that in mind, why did I think JRuby would be faster than Ruby on a problem like this? This kind of calculation is well suited for JVM optimizations: unwinding of loops, JIT'ing of the code, etc. Thus I thought this might be the kind of problem where the JVM could make JRuby run a lot faster than Ruby. Boy was I wrong!

In general, I found JRuby to take twice as long as plain ol' Ruby (or C Ruby as the JRuby folks like to call it.) This was true on Windows, where Ruby is considered to have a poor implementation by many, and on OSX.

This made me thing that my conjecture was wrong to begin with. Maybe this was not the kind of code that the JVM could do much with. I re-wrote the algorithm in Java and re-ran it. It was exponentially faster in Java than in Ruby or JRuby. Indeed, the JVM was able to optimize the runtime execution of the code and make it fly.

Is this what I should have expected? Is JRuby generally much slower than Ruby? I really thought that part of the idea behind JRuby was to leverage the JVM to make Ruby faster.


Charles Oliver Nutter said...

Hello! Perhaps you can give us more information about your environment. What version of JRuby? Use 1.1RC2 or higher for best performance. What version of Java? Sun's Java 6 is recommended. What command-line flags? Enabling the server VM with -J-server is very important.

At any rate we'd appreciate you filing a bug for this. JRuby's performance *should* be better than Ruby 1.8.6, especially on benchmarks like this. So I consider it being slower a bug, and I'd like to get it fixed before 1.1 final. Email me at charles.nutter@sun.com or file a bug in our JIRA bug tracker here: http://jira.codehaus.org/browse/JRUBY

Michael said...

Here is my info version. I will file a bug as you suggested. Also, I tried the -J-server. It had little effect, probably because of the JVM I am using.

$ jruby -version
ruby 1.8.6 (2008-02-16 rev 5944) [x86-jruby1.1RC2]

$ java -version
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build pwi32devifx-20070531a (SR4 + IY99287 + IY99356 + IY98136))
IBM J9 VM (build 2.3, J2RE 1.5.0 IBM J9 2.3 Windows Server 2003 x86-32 j9vmwi3223ifx-20070525 (JIT enabled)
J9VM - 20070524_12771_lHdSMR
JIT - 20070109_1805ifx1_r8
GC - WASIFIX_2007)
JCL - 20070131

Charles Oliver Nutter said...

Ok, then either J9 is significantly slower than Sun's JVM, or you're one of the lucky few who's discovered a performance bottleneck! Once you file the bug with a link to the code you used to compare JRuby and Ruby 1.8.6, I'm sure we can make quick work of it.

And you are right in your optimism: JRuby should be faster, especially for this kind of algorithm.