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に向かないのかもしれません。 もし、向かないとしたら、なぜ向かないのかは何もわかりません。
追記
truffleruby の bigdecimal は ruby の bigdecimal と同じものを使っているようですので、差が出づらいのではないかと思いました。https://t.co/TXNiqFrsO2
— VM持田 (@mike_neck) September 6, 2022
このツイートをもらって気がつきました。 πの計算というか、処理のほとんどがBigDecimalなのでJITが効かないみたいです。
Rubyの新しいJIT「MJIT」で早速遊んでみた(翻訳)|TechRacho by BPS株式会社
MJITはRubyのYARVバイトコードのブロックの1つを受け取り、基本的にはそれをインラインバージョンのCコードに変換し、これが解釈時に実行されることになります。
とあるように、MJITはCコンパイラでコンパイルして高速化していたと記憶しています。 「BigDecimalは元々Cで実装されているので、JITが効かない」はありそうに思えます。