@ledsun blog

無味の味は佳境に入らざればすなわち知れず

MJITとYJITはπの計算には効かないらしい

JITが効くまでに時間が掛かるのではないか? - @ledsun blog で、TruffleRubyはJITが効くまでに40秒の実行時間が必要という仮説を立てました。 YJITや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.bm do |x|
  x.report do
    ARGV[0].to_i.times do 
      pi
    end
  end
end
rbenv local 3.1.2
ruby --version
echo "ruby"
ruby pi.rb 10000
echo "ruby --yjit"
ruby --yjit pi.rb 10000
echo "ruby --mjit"
ruby --mjit pi.rb 10000

結果

ledsun@MSI:~/ruby-pi►./run_mjit_yjit.sh
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
ruby
       user     system      total        real
  41.028472   0.010352  41.038824 ( 41.040139)
ruby --yjit
       user     system      total        real
  40.443960   0.000000  40.443960 ( 40.444085)
ruby --mjit
       user     system      total        real
  40.718051   0.007965  41.406107 ( 40.723440)

特に変わりませんでした。 5万回でもかわりません。

ledsun@MSI:~/ruby-pi►./run_mjit_yjit.sh
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
ruby
       user     system      total        real
  81.505591   0.002163  81.507754 ( 81.508523)
ruby --yjit
       user     system      total        real
  81.272216   0.004975  81.277191 ( 81.277804)
ruby --mjit
       user     system      total        real
  82.383351   0.010723  83.412363 ( 82.390819)

πの計算がJITに向かないのかもしれません。 もし、向かないとしたら、なぜ向かないのかは何もわかりません。

追記

このツイートをもらって気がつきました。 πの計算というか、処理のほとんどがBigDecimalなのでJITが効かないみたいです。

Rubyの新しいJIT「MJIT」で早速遊んでみた(翻訳)|TechRacho by BPS株式会社

MJITはRubyYARVバイトコードのブロックの1つを受け取り、基本的にはそれをインラインバージョンのCコードに変換し、これが解釈時に実行されることになります。

とあるように、MJITはCコンパイラコンパイルして高速化していたと記憶しています。 「BigDecimalは元々Cで実装されているので、JITが効かない」はありそうに思えます。