mrubyのContextThreading化 その5 最終回

こまごまとした修正と若干のパフォーマンスチューニングを入れて、O3コンパイルでmake testを通過できるようにしておいた。
https://github.com/mirichi/mruby/tree/ct
この時点でAOベンチ(O3コンパイル)比較は
元のmruby:6分8秒(368秒)
ContextThreading:6分9秒(369秒)
となり、俺程度の技術力ではContextThreadingの効果は見込めないという状態である。
ディスパッチ関連で無駄があるとすれば間接分岐になってしまっているあたりだが、これをcall-retに再修正するためには例外の機構をごっそり入れ替える必要がある。具体的にはスタックの操作が発生するからsetjmpをメソッド呼び出しごとに入れるか、例外をインラインアセンブラで処理するか、という感じになるだろう。前者は恐らく大変遅いが、後者は大変手間である。

ContextThreadingを試してみた個人的印象では、現在のCPUは間接分岐はペナルティが発生しやすいから遅いが、Pentium4世代と比べるとペナルティのサイクル数が減っているため、他のオーバーヘッドを追加してでも間接分岐を減らすというアプローチは以前と比べて微妙になっている。減らすなら徹底的に無くさないといけない。それをするにはCPUアーキテクチャにかなり依存したインラインアセンブラを駆使したコーディングが必要になるし、労力も相当なものになりメンテもしにくくなる。ていうかメンテできなくなる。
mrubyは現時点では効率を追い求めた実装では無いから、まず間違いなくContextThreading化よりもCレベルで効率改善したほうが効果が高い。Cレベルで限界まで行った後で、もう一歩、というならやってみる価値もあるかもしれないが、その場合はもうJIT化するほうがいいだろう。
もともとの設計からContextThreadingを前提にしてあれば、まだメンテしやすくなる可能性もある。mrubyをどう設計すればContextThreadingがやりやすくなるのかはよくわからないが、そもそもコードの実行時生成が必要だからアーキテクチャコンパイラ依存の設計になるのは避けられない。それはmrubyというソフトウェアの方針を根本から覆すことになり、おそらく受け入れられることは無い。もっと別のモノであればそういう可能性もあるが、それならやっぱりJIT化してしまえと思う。アーキテクチャコンパイラ依存でコード生成という要素はJITと同じなのだから。
ContextThreadingはたぶん、こうしたら間接分岐がなくなって速くなるんじゃね?みたいなヒラメキ一発のネタであって、ソフトウェア一般に適用できるようなシロモノでは無い。適用事例をほとんど見かけないところを見ると間違いなかろう。やたら難しいし。

ということで全5回にわたるmrubyのContextThreading化はこれにて終了とする。
VMというものをいじるのはmrubyが初めてだったから試行錯誤だったが、シンプルな作りのおかげで何とかmake testを通すところまでできた。速くないのは残念だ。こういうネタは論文にできたら面白いのだろうけど、俺論文とか書いたことないし。ブログのコヤシにしておく。
mrubyのVMについての理解はかなり進んだと思うから、あんまり無茶なことをしないで高速化できそうなネタがあればまたチャレンジしていきたい。pull requestして取り込んでもらえそうなものじゃないとちょっと寂しい。

ところで俺自身はmrubyべったりな人では無くて、そもそもDXRuby作者だから、このブログとかTwitterとかチェックしててもここ最近ほどのmrubyネタ密度には今後はならないと思う。あんまり放置するわけにもいかないし、他のこともやりたいし。
とはいえ結局Ruby関連にはなるんだろうけど。