Fibonacci(50): Rust slower than Go ?

I my previous blog post "Fibonnaci (50) : Java > C > C++ > D > Go > Terra (Lua) > LuaJit (Lua) ",  I compared language performance using Fibonnaci algorithm where Rust language was not included.

Rust language is being clamined to  be "a system programming language that runs blazingly fast, prevents almost all crashes*, and eliminates data races".

I thought of running same fibonnaci algorithm against Rust to see how blazingly fast is it.

You can find fib.rs source code here on lang-compare  on my github.  I compared it against fib.go and fib.c 

FIBONACCI - 50
Language C (gcc-4.9.1):
gcc-4.9 -O3 fib.c
/usr/bin/time -lp ./a.out 50
LANGUAGE C: 12586269025
real        52.87
user        52.83
sys          0.01
    557056  maximum resident set size
         0  average shared memory size
         0  average unshared data size
         0  average unshared stack size
       163  page reclaims
         0  page faults
         0  swaps
         0  block input operations
         0  block output operations
         0  messages sent
         0  messages received
         0  signals received
         0  voluntary context switches
       497  involuntary context switches

Language Go (go1.4beta1 darwin/amd64):
go build fib.go
/usr/bin/time -lp ./fib 50
LANGUAGE GO: 12586269025
real        96.56
user        96.47
sys          0.06
   1232896  maximum resident set size
         0  average shared memory size
         0  average unshared data size
         0  average unshared stack size
       300  page reclaims
         0  page faults
         0  swaps
         0  block input operations
         0  block output operations
         0  messages sent
         0  messages received
         0  signals received
      9010  voluntary context switches
      1338  involuntary context switches

Language Rust (0.13.0-nightly (45cbdec41 2014-11-07 00:02:18 +0000)):
/usr/local/bin/rustc --opt-level 3 fib.rs
/usr/bin/time -lp ./fib 50
LANGUAGE Rust: 12586269025
real       101.53
user       101.44
sys          0.01
   1040384  maximum resident set size
         0  average shared memory size
         0  average unshared data size
         0  average unshared stack size
       229  page reclaims
        46  page faults
         0  swaps
         0  block input operations
         0  block output operations
         0  messages sent
         0  messages received
         0  signals received
         1  voluntary context switches
       914  involuntary context switches

Surprisingly results are as below where CPU usage (real) is as C (52.87) > Go (96.56)  > Rust (101.53).

Language CPU(real) Memory(Max resident size)
C 52.87 544K
Go 96.56 1204K
Rust 101.53 1016K




NOTE:  Is there a better way to read command line argument and convert into integer?   I felt it was very painful to figure that out.

E.g.
In C language:
long n = atol(argv[1]);

In Go language:
n, _ := strconv.Atoi(os.Args[1])

In Rust language:
let args = os::args(); let args = args.as_slice(); let n :u64 = from_str::<u64>(args[1].as_slice()).unwrap();



7 comments:

  1. Considering how unoptimized the code is, this says more about how smart the compiler is at optimizing then anything else, and you're comparing to a still-in-development language to a released one. Try the following rust program (not to say this is optimal, it's just less bad):

    use std::os;
    // fib returns a function that returns
    // successive Fibonacci numbers.
    fn fib(n: u64) -> u64 {
    fn f(n: u64, a: u64, b: u64) -> u64 {
    if n == 0 {
    a
    }
    else {
    f(n-1, b, a+b)
    }
    }
    f(n, 0, 1)
    }

    fn main() {
    let args = os::args();
    let args = args.as_slice();
    let n :u64 = from_str::(args[1].as_slice()).unwrap();

    let result = fib(n);
    println!("LANGUAGE Rust: {0}", result);
    }

    ReplyDelete
  2. First off, optimized Rust isn't slower than Go. There should basically be no time when it is.

    Secondly, while I don't necessarily want to say don't use recursion, you definitely don't want to use u64 if you want your algorithm to run quickly. Use u32.

    ReplyDelete
  3. NOTE: Is there a better way to read command line argument and convert into integer?

    I submitted a pull request to your repository with a shorter version.

    I think if you handle the cases of there not being enough arguments passed, and the argument not being a number, you will not find the rust version more verbose

    ReplyDelete
  4. Thanks for the optimized version of the algorithm.

    I want to compare similarly implemented code in different language rather than language specific optimization. So I intentionally wrote the code this way. I could have compared with C++ const_expression/compile time computation.

    http://cpptruths.blogspot.com/2011/07/want-speed-use-constexpr-meta.html

    ReplyDelete
  5. You need more knowledge about the languages to be able to write such a benchmark fairly. I don't like the Computer Language Benchmarks Game very much, but it does at least ensure that the same algorithm is used across languages. It makes it pretty clear that Rust is on par with C++ and Go is slower. This is also clear if you examine how the languages are implemented internally.

    I'm not really arguing that there aren't certain algorithms that naively might be faster when written in Go than Rust, more that sensationalist titles like "Rust slower than Go?" are misleading and the conclusions are factually inaccurate.

    ReplyDelete
  6. How does Delphi XE7 compare?

    ReplyDelete
  7. Here's a free pascal implementation:

    program fib;

    uses
    Math,
    SysUtils;

    const
    SQRT5 = Sqrt(5);

    function fib(const n : Double) : Double;
    begin
    fib := (Power((1 + SQRT5), n) -
    Power((1 - SQRT5), n)) /
    (SQRT5 * Power(2, n));
    end;

    var
    iParam : Integer;

    begin
    iParam := Max(StrToIntDef(ParamStr(1), 0), 0);
    writeln('LANGUAGE PASCAL: ' + FloatToStr(fib(iParam)));
    end.

    Compile and run:

    $ fpc -ofib-pas -XXs -O3 fib.pas
    Free Pascal Compiler version 2.6.2 [2013/08/08] for x86_64
    Copyright (c) 1993-2012 by Florian Klaempfl and others
    Target OS: Linux for x86-64
    Compiling fib.pas
    Linking fib-pas
    /usr/bin/ld: warning: link.res contains output sections; did you forget -T?
    23 lines compiled, 0.3 sec

    $ time ./fib-pas 50
    LANGUAGE PASCAL: 12586269025

    real 0m0.001s
    user 0m0.001s
    sys 0m0.000s


    Yes, I'm cheating by using a different algorithm. ;-) Using the same recursive algorithm was slower with free pascal than Java and C++. I'd expect Delphi to be around about the same speed as Java and C++.

    ReplyDelete