2013-02-09
あなとみー おぶ mrubyのJIT (その1)
|ふと思い立ってものすごく影の薄いmrubyのJITの内部構造を説明することにしました。mrubyのJITは正式名称がないというとてもかわいそうなmrubyのフォークですが、オリジナルのmrubyの1〜3割(倍じゃないのに注意)速いようです。ここにあります、 https://github.com/miura1729/mruby
さて、mrubyのJITはTracing JITなるものを使っています。第一回目はTracing JITの説明をしたいと思います。コードの解説はしないので、そういうのが読みたい人はTwrtter (@miura1729)かコメントで続きはよとつっついてください。
Tracing JITは今やLuaJIT, Pypyをはじめとするいろんな処理系で使われていますが、あまり解説記事はないようです。ただ、http://dodgson.org/omo/t/?date=20080510 が素晴らしくて他に書きようがないという話かもしれません。これを読んでもらえればいいのですが、mrubyのJITはもっと手を抜いているのでmrubyのJITに即して説明します。
mrubyのJITはこんな感じで動きます。
- mrubyのVM本体(mrb_run)でどの命令を実行しようかなー?と選ぶ直前のタイミングで制御を取り上げる
こんだけです。ただ、すべての命令列をコンパイルすると、初期化でコンパイルしたけど二度と通らないという悲しいことになりますので、命令が実行した回数を数えて一定数(現状1000回)以上になったらコンパイルするようにしています。
とっても単純でいいのですが、いろいろ疑問もわくことと思います。
では答えていきます。
コンパイルされたコードを呼び出してその後、VMがちゃんと続きが出来るかということですが、そうなるように作っています(答えになってない気もする)。LuaJITとかだとVMで更新しないといけない情報をコンパイル時に管理してVMに戻るタイミングで更新しているようです。一方、mrubyのJITは常にmrubyのVMの状態をコンパイルされたコードで更新しながら実行しています。簡単ですが、変数をレジスタに割り当てるとか出来なくて遅いです。
条件分岐命令とかはどうするかですが、ここで説明するのは難しいのでまた次回以降に説明します。キーワードはガードです。気になる人は、http://dodgson.org/omo/t/?date=20080510 を読んでください。
mrubyは手抜きなので輪を掛けてますが、Tracing JITは普通のAOTより遅くなると思いっます。じゃあ、化け物LuaJITは?と思われると思いますが、あれは二段熟カレーならぬ二段コンパイルをしているはずです。特に重いと思った所をじっくりコンパイルします。Pypyはどうやってるだろう?
そういうことで今回はおわり。まだ勢いがあるので第二回はあることでしょう
続く