@ledsun blog

Hのキーがhellで、Sのキーがslaveだ、と彼は思った。そしてYのキーがyouだ。

JITが効くまでに時間が掛かるのではないか?

いろいろなRubyでπを計算して速さを比べる - @ledsun blog で比較したところTruffle RubyよりCRubyの方がずっと速かったです。 なぜでしょうか? 例えば Ruby 3.0のJITの特性 - @ledsun blog でCRuby 3.0 の MJIT を試した時は実行時間が20秒を超えたあたりから MJIT での高速化が明確に効き始めました。

次のスクリプトを作って試してみました。

スクリプト

require "bigdecimal"
require "benchmark"

def pi
  prec = 100
  conv = 3
  a = BigDecimal("1")
  b = BigDecimal("1") / BigDecimal("2").sqrt(prec)
  t = BigDecimal("1") / 4
  p = BigDecimal("1")

  for n in 1..conv do
    an = (a + b) / 2
    b = (a * b).sqrt(prec)
    t -= p * (an - a) * (an - a)
    p *= 2
    a = an
  end
end

Benchmark.bmbm do |x|
  x.report do
    ARGV[0].to_i.times do 
      pi
    end
  end
end

求めるπの精度は上げずに計算回数を増やします。 計算回数は引数で与えます。 これを次のシェルスクリプトから実行します。

rbenv local 3.1.2
ruby --version
ruby pi.rb $1
rbenv local truffleruby+graalvm-22.2.0
ruby --version
ruby pi.rb $1

結果

ledsun@MSI:~/ruby-pi►./run.sh 1
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
       user     system      total        real
   0.004428   0.000000   0.004428 (  0.004427)
truffleruby 22.2.0, like ruby 3.0.3, GraalVM CE Native [x86_64-linux]
       user     system      total        real
   1.489403   0.011044   1.500447 (  0.455772)
ledsun@MSI:~/ruby-pi►./run.sh 10
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
       user     system      total        real
   0.040624   0.000000   0.040624 (  0.040635)
truffleruby 22.2.0, like ruby 3.0.3, GraalVM CE Native [x86_64-linux]
       user     system      total        real
   2.938930   0.025063   2.963993 (  0.904666)
ledsun@MSI:~/ruby-pi►./run.sh 100
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
       user     system      total        real
   0.389929   0.012847   0.402776 (  0.402843)
truffleruby 22.2.0, like ruby 3.0.3, GraalVM CE Native [x86_64-linux]
       user     system      total        real
   4.807394   0.055102   4.862496 (  1.456071)
ledsun@MSI:~/ruby-pi►./run.sh 1000
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
       user     system      total        real
   4.020903   0.000522   4.021425 (  4.021559)
truffleruby 22.2.0, like ruby 3.0.3, GraalVM CE Native [x86_64-linux]
       user     system      total        real
  19.241751   0.696200  19.937951 (  6.099974)
ledsun@MSI:~/ruby-pi►./run.sh 10000
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
       user     system      total        real
  40.903658   0.010000  40.913658 ( 40.913753)
truffleruby 22.2.0, like ruby 3.0.3, GraalVM CE Native [x86_64-linux]
       user     system      total        real
  76.209975   3.488461  79.698436 ( 40.424835)

計算回数1万回、実行時間40秒でTruffleRubyが勝ちました!

CRubyとTruffleRubyの実行速度の線グラフ

グラフにするとほとんど同じ性能にみえます。 面白いです。

グラフを書くのに参考にしたサイト

追記

よく考えたら両対数グラフにしないと上手く表現できなさそうです。

CRubyとTruffleRubyの実行速度の両対数グラフ

CRubyの実行時間が線形に増えているのに対して、TruffleRubyが何かしら頑張っているのがわかります。 そして10000くらいで頑張りが限界に達していることもわかります。

グラフを書いたときのgnuplotのデータと指示です。

1 0.004427 0.455772
10 0.040635 0.904666
100 0.402843 1.456071
1000 4.021559 6.099974
10000 40.913753 40.424835
gnuplot> plot "test.dat" using 1:2 with lines title "CRuby", "test.dat" using 1:3 with lines title "TruffleRuby"
gnuplot> set logscale x
gnuplot> set logscale y
gnuplot> set yrange [0.001: 41]