ミラクルリナックス社にて。いつも会場の提供ありがとうございます。
第10回のテーマは「コンパイルと最適化」。Ruby 1.9 ではスクリプトはパースされて一旦構文木(AST)を経由して VM の命令列にコンパイルされます。なのでここで言うコンパイルは構文木のノードを辿って命令列に変換することをいいます。
それから命令列はよくバイトコードと呼ばれますが、Rubyの命令語は VALUE 列だからとか、ささださんがなにか抵抗があるとかいう事情により iseq (多分 instruction sequence)と言うようです。
ではいつものように箇条書きで。
- まずは型。
- compile.c が今回の本丸
- コンパイル時に一次利用される型、マクロ等
- LINK_ELEMENT(struct iseq_link_element)
- LINK_ANCHOR(struct iseq_link_anchor)
- linked list 毎にダミーのheadとtailポインタをまとめたもの。
- DECL_ANCHOR と INIT_ANCHOR
- LINK_ANCHOR を定義して、空のリストを表現するように初期化するマクロ
- ADD_TRACE, ADD_LABEL, ADD_INSN, ADD_INSN1...
- LINK_ANCHOR に要素を追加するマクロ。ADD_INSN1 とかは命令語のオペランド数毎にマクロがある。
- gdb でコールツリーを辿りながら実演。以下のような感じ。
- parse_option
- rb_iseq_new_main
- rb_iseq_new_with_opt
- rb_iseq_new_with_bopt_and_opt (ブロックオプション付き?)
- prepare_iseq_build
- klass = 0 は ObjectSpace.each_object から隠す work around
- set_relation cref_stack などを継承してる。
- rb_iseq_compile_node <- ここからコンパイル開始。深くなるので一旦リセット
- prepare_iseq_build
- rb_iseq_new_with_bopt_and_opt (ブロックオプション付き?)
- rb_iseq_new_with_opt
- rb_iseq_new_main
- rb_iseq_compile_node
- iseq_compile_each
- iseq_setup
- 最適化について。
- 不要なジャンプ命令を除去する peephole optimization。
- 特化命令、命令融合、オペランド融合。
- スタックキャッシングというやつはよく読めなかった。
- defined? のコンパイルがちょっとおもしろい
- おまけとしてよしおかさんが oprofile の使いかたの解説と、ruby の make test-all した時の2次キャッシュミスする場所をさがして prefetch 命令をインラインアセンブラで埋め込んで性能改善してみる実例を発表
今回はちょっと発表側もやりました(defined? のところ)。当日とっさに思い付いたネタなのでさわださんが発表している間せっせとコードリーディングしてました。なので命令融合の実演のところとかメモが不足。
あと ust でみてみたら声もターミナルの字も小さすぎた。まあそれでも思ったほど緊張してコチコチにはならなかったし、最初はこんなものか。もっとスクリーンとか参加者の様子をみる余裕ができるといいんでしょうきっと。
次回は 2/14 で「YARVの命令ディスパッチと実行コンテキスト」だそうです。