2019年1月7日月曜日

Ruby2.6 で MJIT に入門してみた

概要

Ruby 2.6 から JIT の機能が追加されました
簡単に説明すると Ruby の関数の一部コードを C 言語に変換しコンパイル -> 実行することで Ruby の処理を高速化できるという機能です (詳細はこちら)
今回は 2.6 のインストールから実際に JIT を有効にして Ruby スクリプトを実行してみました

環境

  • Ubuntu 16.04 (on Vagrant)
  • ruby 2.6.0p0

ruby 2.6 のインストール

rvm ではすでに 2.6 が公開されているので rvm を使ってインストールします

  • sudo apt -y install gnupg2
  • gpg2 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
  • \curl -sSL https://get.rvm.io | bash -s stable
  • /home/vagrant/.rvm/bin/rvm install ruby-2.6
  • /home/vagrant/.rvm/bin/rvm alias create default ruby-2.6.0

すでに .profile に PATH の追加はされているので再ログインしましょう

  • ruby -v

ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-linux]
こんな感じでバージョンが表示されれば OK です

試してみる

いろいろなコードを書いて MJIT を有効にした場合 (--jit) とそうでない場合の速度がどうなるか試してみました
内容はすべて同じで 1 から 1 億までの数字を合計する処理になります

実験1

  • vim test1.rb
puts 100000000.times.inject { |sum, i| sum + i }
  • time ruby test1.rb
real    0m6.942s
user    0m6.924s
sys     0m0.016s
  • time ruby --jit test1.rb
real    0m7.326s
user    0m13.856s
sys     0m0.432s

何回か試してみましたが JIT を有効にしたほうが時間がかかってしまいました

実験2

  • vim test1.rb
def calc
  sum = 0
  100000000.times do |i|
    sum = sum + i
  end
  return sum
end

puts calc
  • time ruby test2.rb
real    0m4.882s
user    0m4.860s
sys     0m0.012s
  • time ruby --jit test2.rb
real    0m4.959s
user    0m9.332s
sys     0m0.328s

これも JIT を有効にしたほうが若干遅い結果になってしまいました
inject を使わないで計算するほうが単純に早くなりました

実験3

  • vim test3.rb
def calc(c)
  sum = 0
  c.times do |i|
    sum = sum + i
  end
  return sum
end

puts calc(100000000)
  • time ruby test3.rb
real    0m4.861s
user    0m4.848s
sys     0m0.008s
  • time ruby --jit test3.rb
real    0m4.550s
user    0m8.544s
sys     0m0.308s

ループさせる回数を引数で取るようにしています
これで試したところ JIT を有効にしたほうが早くなりました
何度か試しても JIT を有効にしたほうが早かったので間違いないと思います

その他

実行時に --jit-verbose=2 --jit-save-temps を指定すると JIT の処理を追いつつ生成された C のコードを /tmp 配下に保存することができます
デバッグしたいときに使いましょう

  • time ruby --jit --jit-verbose=2 --jit-save-temps test3.rb

最後に

いろいろなコードを書いて JIT を有効にした場合とそうでない場合で速度を比較してみました
書いてみてわかったこととしては

  • すべてのケースで速くなるわけではない
  • JIT に適したコーディングを意識する必要がありそう

この辺りは使用する場合に考える必要がありそうです
また試してはいないのですが C に変換しコンパイルする処理は gcc や clang を使っているようなので単純にマシンのスペックにも影響するかもしれません

少し前に inline を使った手法を紹介しましたが、2.6 以降であれば inline を使わずに高速化することができると思います
ただ MJIT は直接 C が書けるわけではないので直接 C のライブラリを使いたい場合などは inline を使う感じになると思います
そのあたりは使い分けかなと思います

参考サイト

0 件のコメント:

コメントを投稿