Recursive Fibonacci Benchmark using top languages on Github

December 29, 2024 ยท View on GitHub

Top 10: JavaScript, Python, Java, TypeScript, C#, Php, C++, C, Shell, Ruby reference

Others: Go, Rust, Swift, Crystal, Pony, Ada, Pascal, Fortran, Kotlin, Clojure, Scala, Mono, R, Dart, Julia, D, Nim, Cython, Python3, PyPy, Ruby jit, OCaml, Lisp, Haskell, Erlang, Elixir, Escript, Dart, Scheme, Lua, Perl, Perl6, Bash, Emoji

The code performs a recursive fibonacci to the 47th position with the result of 2,971,215,073.

Fibonacci can be written many different ways. The goal of this project is to compare how each language handles the exact same code.

Here is the Ruby version:

def fib(n)
  return n if n <= 1
  fib(n - 1) + fib(n - 2)
end

puts fib(47)

Here is the Crystal version:

def fib(n)
  return n if n <= 1
  fib(n - 1) + fib(n - 2)
end

puts fib(47_u64)

To keep a level playing field, only common "release" flags are used in the compilation step. This allows for compiler optimizations like inlining and constant propogation but removes anything considered dangerous i.e. bypassing out of bounds checks.

All tests are run on:

  • Hetzner CCX23 - 4 vCPU
  • Processor: Intel Xeon 3.1Ghz
  • Memory: 16 GiB
  • OS: Ubuntu 24.04
  • Docker Base Image: ubuntu:24.04

How to run them

You can run the tests using Docker: docker run -it drujensen/fib

By default, it will compile and run all languages 5 times. Totals are calculated by adding the average compile and run times.

To only run a subset of the languages, provide a list of extensions and optionally the count:

docker run -it drujensen/fib ./run.sh s,c,cpp,go,rs,swift 5

To run in the background using screen:

screen
docker run drujensen/fib > results.txt 2>&1
  • Detach from the session by pressing Ctrl+A followed by D.
  • You can reattach to the session later with:
screen -r

NOTE: Please see issues with benchmarks like this. Its original goal was to compare at a macro level how much faster Crystal is to Ruby. Any language faster than Assembly is performing unrolling type optimizations. Modern languages like Go, Swift and Crystal have bounds checking which have safety built-in, but also have a cost associated with runtime performance.

Results

Last benchmark was ran on December 05, 2024

Natively compiled, statically typed

LanguageRunTimeRunCompileTimeCompileExt
C4.723./fib0.112gcc -O3 -o fib fib.cc
C++4.750./fib0.139g++ -O3 -o fib fib.cppcpp
V4.718./fib4.450v -prod -o fib fib.vv
Fortran6.204./fib0.130gfortran -O3 -o fib fib.f03f03
Ada6.591./fib0.220gnat make -O3 -gnatp -o fib fib.adbadb
Rust7.750./fib0.358rustc -C opt-level=3 fib.rsrs
Mojo8.706./fib0.241mojo build fib.mojomojo
Odin8.751./fib0.087odin build fib.odin -file -0:speedodin
Zig9.299./fib6.882zig build-exe -OReleaseFast ./fib.zigzig
Assembly9.342./fib0.025gcc -no-pie -O3 -o fib fib.ss
Pony10.226./fib0.879ponyc -s -b fib -p ./fib.ponypony
Pascal10.419./fib0.041fpc -O3 -Si ./fib.paspas
OCaml15.831./fib0.187ocamlopt -O3 -o fib fib.mlml
Swift17.390./fib1.411swiftc -O fib.swiftswift
Crystal17.420./fib3.106crystal build --release fib.crcr
Go17.842./fib1.107go build fib.gogo
D17.851./fib0.342dmd -release -of=fib fib.dd
Haskell18.094./fib0.001rm ./fib.o && ghc -O3 -o fib fib.hshs
Lisp24.747./fib0.979sbcl --load fib.lisplisp
Dart Compiled30.149./fib1.558dart compile exe -o fib ./fib.dartdartc
Cobol4380.596./fib0.133cobc -x -O3 -o fib ./fib.cblcbl

VM compiled bytecode, statically typed

LanguageRunTimeRunCompileTimeCompileExt
C#10.744dotnet ./bin/fib.dll2.015dotnet build -c Release -o ./bincs
Java12.307java Fib0.733javac Fib.javajava
Kotlin12.212java FibKt4.074kotlinc Fib.ktkt
Scala13.153scala Fib2.682scalac Fib.scalascala
Erlang27.976erl -noinput -noshell -s fib0.402erlc +native +'{hipe,[o3]}' fib.erlerl
Groovy68.604groovy Fib1.519groovyc Fib.groovygroovy

VM compiled before execution, mixed/dynamically typed

LanguageRunTimeRunExt
Clojure17.815clojure -M fib.cljccljc
Julia18.000julia -O3 fib.jljl
Bun21.312bun fib.jsbun
Dart29.984dart fib.dartdart
Node34.736node fib.jsjs
Elixir35.243ERL_COMPILER_OPTIONS='[native,{hipe, [o3]}]' elixir Fib.exsexs
Lua Jit37.837luajit fib.lualuajit
Python (PyPy)54.078pypy fib.pypypy
Ruby (jit)81.454ruby --jit fib.rbrbjit

Interpreted, dynamically typed

LanguageRunTimeRunExt
Escript28.380escript fib.eses
Scheme102.887guile fib.scmscm
Php157.312php fib.phpphp
Lua203.702lua fib.lualua
Ruby393.625ruby fib.rbrb
Python423.427python fib.pypy
Janet479.663janet ./fib.janetjanet
Perl1490.416perl fib.plpl
Raku1672.015rakudo fib.rakuraku
Tcl2230.883tclsh fib.tcltcl
R2575.249R -f fib.rr

Versions

All compilers are installed using apt or asdf on Ubuntu 24.04 docker image:

LanguageVersion
ada13.2.0
assembly13.2.0
bash5.2.21
bun1.1.38
crystal1.14.0
clojure1.12.0.1488
dart3.5.4
dmd2.109.1
dotnet9.0.101
elixir1.17.3
elm0.19.1
erlang27.1.2
fortran13.2.0
g++13.2.0
gcc13.2.0
gnucobol3.2.0
golang1.23.2
groovy4.0.24
guile3.0.10
haskell9.8.3
janet1.36.0
javaopenjdk-23
julia1.11.1
K3.6
kotlin2.1.0
ldc1.39.0
lua5.4.7
luajit2.1.1
mojo24.5.0
nim2.2.0
nodejs23.3.0
ocaml5.2.1
odindev-2024-11
pascal3.2.2
perl5.40.0
php8.4.1
pony0.58.7
powershell-core7.4.6
python3.12.0
pypy7.3.17
r4.4.2
rakudo2024.10
ruby3.3.6
rust1.83.0
sbcl2.4.11
scala3.3.4
swift6.0.2
tcl9.0.0
v0.4.8
zig0.13.0