Ruby Performance Revisited 6

Posted by Ron Valente Thu, 21 Feb 2008 04:28:00 GMT

For this post I used a code snippet I found from a fellow programmer, Antonio Cangiano, that ran the tests again myself because I couldnt believe my eyes of the benchmarks run by that user.

Fibonacci Language Shootout:

Languages

  • Ruby 1.8.6
  • Ruby 1.9.0 (Development Release)
  • Python 2.5.1
  • Perl 5.8.8
  • Java 1.5.0
  • C++

Below are the languages and the times that each took to run the code. The code for each languages is below near the end of the post.

Ruby 1.8.6

real 0m44.965s

Python 2.5.1

real 0m28.283s

Ruby 1.9.0

real 0m11.352s

C++

real 0m0.765s

Java

real 0m0.638s

Perl

real 0m70.383s

I will be comparing this performance of Ruby and Python to a program written in C. Below is the code used in these examples. Feel free to comment. I am running further tests using statistical analysis to make the output exhibit less of a standard deviation.

Python

def fib(n):
   if n == 0 or n == 1:
      return n
   else:
      return fib(n-1) + fib(n-2)

for i in range(36):
    fib(i)

Ruby

def fib(n)
  if n == 0 || n == 1
    n
  else
    fib(n-1) + fib(n-2)
  end
end

36.times do |i|
  fib(i)
end

Below is the source code for the fib sequence written in C++. Paul Solt recommended that the tests be performed without and writing to STDOUT due to the variability and slow down caused by writing to STDOUT. Since this was done for the C++ code it was done for the rest of the examples above. For the record there was no increase in speed when the output was removed.

C++

#include <stdio.h>
#include <iostream>

int fib( int n ) { 
    if( n== 0 || n == 1 ) { 
        return n; 
    } else {
        return fib( n -1) + fib( n-2); 
    }
}

int main() { 
    for( int i = 0; i < 36; i++ ) {
        fib(i);
    }
    return 0; 
}

Java

public class fibtest {
    public static void main(String[] args) { 
        for(int i=0; i<36; i++) {
            fib(i);     
        }
    }
    public static int fib(int n) {
        if( n == 0 || n == 1 )
            return n; 
        } else {
            return fib(n-1) + fib(n-2);
        }
    }
}

Perl

sub fib { return $[0] if $[0] == 0 || $_[0] == 1; fib($[0]-1) + fib($[0]-2); }

for($i=0;$i<36;$i++) { fib($i); }

I would like to extend my thanks to the developers that submitted, or contributed to this post in anyway.

Ruby & Python Code

Paul Solt - C Developer

Java & Perl Code - Jason Koppe

Trackbacks

Use the following link to trackback from your own site:
http://www.sysadminschronicles.com/trackbacks?article_id=ruby-performance-revisited&day=20&month=02&year=2008

Comments

Leave a comment

  1. Paul Solt about 1 hour later:

    Awesome stuff!

  2. Paul Solt about 2 hours later:

    I think the results are largely dependent on the type of code you run. In order to get a better sense of the actually performance benefits you should try running your performance tests with different types of functions/algorithms.

    The Fibonacci algorithm you used is recursive and there are different improvements that the compiler/interpreters can do to make it faster, but they may not all do it. This is probably why there’s a huge speed difference.

    Also, the reason you didn’t see any performance increase when you removed the print statement is because the time to do the calculation is much greater than the time needed for output.

  3. Jason Koppe about 3 hours later:

    Good comments… The increase in speed for the recursive function calls is very interesting – to have such a substantial decrease in time from 1.8.4 to 1.9 is cool. What modifications to an interpreter could decrease the running time that much? I wonder about the (dis)advantages of external memoization and if it’s practiced in any compiled or interpreted language runtimes.

    Ron, how did you measure the running times for these?

    I’m interested to see how perl compares with your time measurement – and after that, PowerShell :) I’m also interested to see the running time comparisons for all of these scripting languages (not really too concerned with the compiled languages) for non-recursive algorithms.

    In my basic tests, Sun’s Java jdk-1.5.0_14-fcs completed in 0.894 seconds and perl-5.8.8-30.fc8 completed in 112.039 seconds; Ron can you add this code to your post?

    Java(0.638s):

    public class fibtest { public static void main(String[] args){ for(int i=0; i<36; i++) fib(i); } public static int fib(int n) { if( n == 0 || n == 1 ) return n; else return fib(n-1) + fib(n-2); } }

    Perl(70.383s):

    sub fib { return $[0] if $[0] == 0 || $_[0] == 1; fib($[0]-1) + fib($[0]-2); }

    for($i=0;$i<36;$i++) { fib($i); }

  4. Jason Koppe about 4 hours later:

    Oh, heres how i tested the runtimes

    [root@localhost scriptingtest]# java ms && java fibtest && java ms
    1203579932308
    1203579932946
    [root@localhost scriptingtest]# java runtime
    1203579932308
    1203579932946
    0.638s
    [root@localhost scriptingtest]# java ms && perl fibtest.pl && java ms
    1203579954835
    1203580025218
    [root@localhost scriptingtest]# java runtime
    1203579954835
    1203580025218
    70.383s
    [root@localhost scriptingtest]# java ms && echo “” && java ms
    1203580373737

    1203580373896
    [root@localhost scriptingtest]# java runtime
    1203580373737

    1203580373896
    0.159s


    [root@localhost scriptingtest]# cat runtime.java
    import java.util.Scanner; public class runtime { public static void main(String[] args){ Scanner i = new Scanner(System.in); long s = i.nextLong(); long e = i.nextLong(); System.out.println(((e-s)/1000.0)+”s”); } }

  5. Ron about 14 hours later:

    Jason, That was very interesting to see the results of Java and Perl matched up, I will add the code and performance tests to the post.

    Paul, Exactly, I would like to runs some more in-depth tests this weekend.

  6. Jason Koppe about 17 hours later:

    You should run the java/perl code in the same test environment for a more accurate comparison.

Comments