There's a better way to run that benchmark - using the benchmark-ips
tool which is designed carefully to allow for optimising implementations of Ruby to do their work and will allow for the JIT to warm up.
require 'benchmark/ips'
def calculate(a, b, n = 40_000_000)
i = 0
c = 0
while i < n
a = a * 16807 % 2147483647
b = b * 48271 % 2147483647
c += 1 if (a & 0xffff) == (b & 0xffff)
i += 1
end
c
end
Benchmark.ips do |x|
x.iterations = 3
x.report("calculate") do |times|
calculate(65, 8921, 100_000)
end
end
raise unless calculate(65, 8921) == 588
ruby 2.6.0dev (2018-02-07 trunk 62270) [x86_64-darwin17]
Warming up --------------------------------------
calculate 9.000 i/100ms
calculate 9.000 i/100ms
calculate 9.000 i/100ms
Calculating -------------------------------------
calculate 893.647 (±10.3%) i/s - 4.419k in 5.003980s
calculate 872.846 (±12.7%) i/s - 4.275k in 5.000368s
calculate 934.028 (±10.1%) i/s - 4.599k in 5.002686s
ruby 2.6.0dev (2018-02-07 trunk 62270) [x86_64-darwin17] (+JIT)
Warming up --------------------------------------
calculate 10.000 i/100ms
calculate 18.000 i/100ms
calculate 18.000 i/100ms
Calculating -------------------------------------
calculate 3.174k (± 9.9%) i/s - 15.552k in 4.999483s
calculate 3.180k (± 8.2%) i/s - 15.786k in 5.002768s
calculate 3.085k (±14.8%) i/s - 14.958k in 5.002559s
rubinius 3.84 (2.3.1 3970f17d 2017-08-02 4.0.1) [x86_64-darwin17.0.0]
Warming up --------------------------------------
calculate 3.000 i/100ms
calculate 3.000 i/100ms
calculate 3.000 i/100ms
Calculating -------------------------------------
calculate 114.830 (± 8.7%) i/s - 570.000
calculate 114.671 (± 9.6%) i/s - 570.000
calculate 118.078 (± 7.6%) i/s - 588.000
jruby 9.1.13.0 (2.3.3) 2017-09-06 8e1c115 Java HotSpot(TM) 64-Bit Server VM 25.144-b01 on 1.8.0_144-b01 +jit [darwin-x86_64]
Warming up --------------------------------------
calculate 9.000 i/100ms
calculate 10.000 i/100ms
calculate 10.000 i/100ms
Calculating -------------------------------------
calculate 1.083k (±11.0%) i/s - 5.330k in 4.983511s
calculate 1.097k (±11.8%) i/s - 5.400k in 4.995296s
calculate 1.091k (±12.0%) i/s - 5.370k in 4.998160s
truffleruby 0.30.2, like ruby 2.3.5 <Java HotSpot(TM) 64-Bit Server VM 1.8.0_151-b12 with Graal> [darwin-x86_64]
Warming up --------------------------------------
calculate 112.000 i/100ms
calculate 157.000 i/100ms
calculate 188.000 i/100ms
Calculating -------------------------------------
calculate 352.284k (±15.6%) i/s - 1.646M in 4.979090s
calculate 352.140k (±15.0%) i/s - 1.707M in 4.987553s
calculate 360.077k (±13.6%) i/s - 1.755M in 4.988948s
Running that it looks like MJIT is over 3x faster! Which is very impressive and it's already doing better than both JRuby and Rubinius.
TruffleRuby is over 300x faster (I only mention it because it's my own implementation of a Ruby JIT), so there's still lots of rooms for optimisations, as the authors have already said themselves.