Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
mrubyのJIT
三浦英樹
(miura1729)
自己紹介
ここから南に行った知多半島の武豊町で水道
屋をやっています
仕事の合間にmrubynのJITコンパイラをこそこ
そ作っています。作る理由はストレス解消って
感じです
mrubyのJITとは
mrubyにパッチを当ててJITコンパイルをおこなうようにしたものです
コード生成にXbyakを使わせてもらっています。
(使いやすくて安定していてお勧め)
基本的に32bitのCygwinで開発しているのでそれが一番安...
mruby流れ
構文解析
コード生成
バイトコードインタプリタ
AST
RITE バイトコード列
構文解析
コード生成
バイトコードインタプリタ
AST
RITE バイトコード列
mruby流れ
主にこの部分に
手を入れる
バイトコード列の例
irep 0x20160790 nregs=11 nlocals=4 pools=3 syms=5 reps=1
file: benchmark/bm_fib.rb
14 000 OP_ENTER 2:0:0:0:0:0:0...
バイトコードインタプリタの構成
命令のフェッチ
MOVE
命令の実行命令の実行命令の実行命令の実行
SEND ADD LOADI CALL
素朴な考え
命令のフェッチ
MOVE
命令の実行命令の実行命令の実行命令の実行
SEND ADD LOADI CALL
この部分の実行した機械語をどこかに覚えておい
て再実行すれば速くなるんじゃね?
こんな感じ
命令のフェッチ
MOVE
命令の実行命令の実行命令の実行命令の実行
SEND ADD LOADI CALL
MOVE
命令の生成命令の生成命令の生成命令の生成
SEND ADD LOADI CALL
既に生成された命令があれば
それ...
ループはいつか終わる(普通は)
これだけではうまくいかない
引数に整数かと思ったら文字列がやってきた
ポリモーフィズムとか
そこでガードを導入する
実行の前提条件をチェックする、仕組み
 ・ やっていることはただのif文
(機械語だから条件判定と条件ブランチ)
 
 ・ 前提条件の例
    レジスタに入っているデータ型
    レジスタに入っているクラス
レジスタ...
mrubyのVMの状態の例
mrb->c      VMのコンテクスト(Fiberとかを使わない限り変化しない)
mrb->c->ci    メソッドの呼び出し履歴
proc 現在実行中のブロック/メソッドのProcオブジェクト
irep 現在...
Tracing JITのまとめ
(メソッドレベルのJITと比べて)
いい所
  いつでもVMに戻れるから実装の面倒な部分をVMに丸投げできる。
実装が面倒な機能満載のRubyにはありがたい特徴
  開発初期の段階からすべてのRubyプログラムが...
なんとか速くする
なにも工夫しないTracing JITはやっぱり遅い
  多分、オリジナルのインタプリタの方が速い
そこで、なんとか速くする工夫をしないといけない
  工夫のしどころはいろいろある 
    (なにせLuaJIT、PypyはT...
ガードを無くす
単純な例
OP_LOADI R3, 1
OP_ADD R2, 1, :+
OP_ADDでR3がFIXNUMであるかのチェックはいらない
レジスタの型を覚えておき、確定するならガードを生成しない
→ これは既に実装済み
もっと複雑...
余計なメモリアクセスを減らす
単純な例
OP_LOADI R3, 1
OP_ADD R2, 1, :+
R3は1であることをコンパイル時に覚えておき(コードは生成しない)、
ADD命令生成時にR3は1である情報を利用して即値を使う機械語を生
成...
メソッド呼び出しを無くす
mrubyのメソッド呼び出しはとにかく重い。
Tracing JITだからコンパイルしても同じことをしないといけない
  → じゃあ軽くしようと思うけどすごく困難
     例外とかバックトレースとか考えると仕方が無い...
面倒くさいRubyの機能
 ・ メソッドの再定義 (make testで使いまくり)
 ・ Fiber (h2oで使いまくり)
 ・ send (optcarrot(ファミコンエミュレータ)で使いまくり)
 ・ Procオブジェクト
 ・ ev...
おしまい
ありがとうございました
Upcoming SlideShare
Loading in …5
×

mrubyのJIT

2,040 views

Published on

名古屋Ruby会議 03のスライド

Published in: News & Politics
  • Hey guys! Who wants to chat with me? More photos with me here 👉 http://www.bit.ly/katekoxx
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

mrubyのJIT

  1. 1. mrubyのJIT 三浦英樹 (miura1729)
  2. 2. 自己紹介 ここから南に行った知多半島の武豊町で水道 屋をやっています 仕事の合間にmrubynのJITコンパイラをこそこ そ作っています。作る理由はストレス解消って 感じです
  3. 3. mrubyのJITとは mrubyにパッチを当ててJITコンパイルをおこなうようにしたものです コード生成にXbyakを使わせてもらっています。 (使いやすくて安定していてお勧め) 基本的に32bitのCygwinで開発しているのでそれが一番安心です。 一応、32bitのLinuxでもそこそこ動きますし、64bitのLinuxでもちょっと 動きます オリジナルのmrubyの1~10倍くらいの速度だと思います。CRubyと比 べると速かったり遅かったりです。だいたい、4倍くらいでしょうか。
  4. 4. mruby流れ 構文解析 コード生成 バイトコードインタプリタ AST RITE バイトコード列
  5. 5. 構文解析 コード生成 バイトコードインタプリタ AST RITE バイトコード列 mruby流れ 主にこの部分に 手を入れる
  6. 6. バイトコード列の例 irep 0x20160790 nregs=11 nlocals=4 pools=3 syms=5 reps=1 file: benchmark/bm_fib.rb 14 000 OP_ENTER 2:0:0:0:0:0:0 15 001 OP_LOADSELF R4 15 002 OP_STRING R5 L(0) ; "" 15 003 OP_GETCONST R6 :Irep 15 004 OP_MOVE R7 R1 ; R1:ele 15 005 OP_GETUPVAR R8 1 0 15 006 OP_SEND R6 :disasm 2 15 007 OP_STRCAT R5 R6 15 008 OP_STRING R6 L(2) ; " n" 15 009 OP_STRCAT R5 R6 15 010 OP_SEND R4 :print 1 16 011 OP_GETUPVAR R4 1 0 16 012 OP_MOVE R5 R2 ; R2:i 16 013 OP_SEND R4 :reg_type 1 16 014 OP_LAMBDA R5 I(+1) 2 16 015 OP_SENDB R4 :each 0 16 016 OP_RETURN R4 normal
  7. 7. バイトコードインタプリタの構成 命令のフェッチ MOVE 命令の実行命令の実行命令の実行命令の実行 SEND ADD LOADI CALL
  8. 8. 素朴な考え 命令のフェッチ MOVE 命令の実行命令の実行命令の実行命令の実行 SEND ADD LOADI CALL この部分の実行した機械語をどこかに覚えておい て再実行すれば速くなるんじゃね?
  9. 9. こんな感じ 命令のフェッチ MOVE 命令の実行命令の実行命令の実行命令の実行 SEND ADD LOADI CALL MOVE 命令の生成命令の生成命令の生成命令の生成 SEND ADD LOADI CALL 既に生成された命令があれば それを実行 実行できないなら インタプリタのループに戻る 生成された機械語 実行 機械語 書き込み
  10. 10. ループはいつか終わる(普通は) これだけではうまくいかない 引数に整数かと思ったら文字列がやってきた ポリモーフィズムとか
  11. 11. そこでガードを導入する 実行の前提条件をチェックする、仕組み  ・ やっていることはただのif文 (機械語だから条件判定と条件ブランチ)    ・ 前提条件の例     レジスタに入っているデータ型     レジスタに入っているクラス レジスタの値  (→ if文とかループもこれを使う) ・ 前提が当てはまらなかったらVMに戻る    VMの状態を設定する必要がある (面倒)
  12. 12. mrubyのVMの状態の例 mrb->c      VMのコンテクスト(Fiberとかを使わない限り変化しない) mrb->c->ci    メソッドの呼び出し履歴 proc 現在実行中のブロック/メソッドのProcオブジェクト irep 現在実行中のメソッド/ブロックのプログラムコードと           その付加情報(定数とかシンボルテーブルとか) pc 現在実行中の命令 syms シンボルテーブル pool 定数テーブル mrb->c->stack レジスタ(昔はregsという変数があったが今は無い) VMに戻るときはこの辺の変数を正しく設定する必要がある  常に整合を保つのではなく、VMに戻るときというのがミソ メソッド呼び出し・戻りとVMに戻る直前が主な更新ポイント LuaJITだとVMをアセンブラで書いて状態を変更しやすくしている
  13. 13. Tracing JITのまとめ (メソッドレベルのJITと比べて) いい所   いつでもVMに戻れるから実装の面倒な部分をVMに丸投げできる。 実装が面倒な機能満載のRubyにはありがたい特徴   開発初期の段階からすべてのRubyプログラムが動くのでモチベー ションが高い 悪い所  いつでもVMに戻れるようにいろいろ変数を設定する必要があるか ら遅い。  CとかLLVMを生成しようとすると何かと困難
  14. 14. なんとか速くする なにも工夫しないTracing JITはやっぱり遅い   多分、オリジナルのインタプリタの方が速い そこで、なんとか速くする工夫をしないといけない   工夫のしどころはいろいろある      (なにせLuaJIT、PypyはTracing JITだし) 速くする方針はだいたいこんな所   ・ ガードを無くす   ・ 余計なメモリアクセスを無くす   ・ メソッド呼び出しを無くす
  15. 15. ガードを無くす 単純な例 OP_LOADI R3, 1 OP_ADD R2, 1, :+ OP_ADDでR3がFIXNUMであるかのチェックはいらない レジスタの型を覚えておき、確定するならガードを生成しない → これは既に実装済み もっと複雑なものは簡単にはいかないので静的に型推論を行う必要が あると思われる → これはまだ(興味がある人は後で話しましょう)
  16. 16. 余計なメモリアクセスを減らす 単純な例 OP_LOADI R3, 1 OP_ADD R2, 1, :+ R3は1であることをコンパイル時に覚えておき(コードは生成しない)、 ADD命令生成時にR3は1である情報を利用して即値を使う機械語を生 成する → これは既に実装済み もっと複雑なものはレジスタ割り当て(たとえばLiner Scan Register Allocation)を利用する必要があるでしょう。 → これはまだ(興味がある人は後で話しましょう)
  17. 17. メソッド呼び出しを無くす mrubyのメソッド呼び出しはとにかく重い。 Tracing JITだからコンパイルしても同じことをしないといけない   → じゃあ軽くしようと思うけどすごく困難      例外とかバックトレースとか考えると仕方が無い そこで、メソッド呼び出しを無くす(インライン化する)というアプローチが有効    インライン化にも2つの方針がある     ・ C言語で実装されたメソッドをmrubyのメソッド呼び出し   のプロトコルを無視して呼び出す       → 例外が発生しないことが前提          簡単ですごく効果がある(数割速くなるとかざら) ・ mrubyで書かれたメソッドをインライン化する       → これはまだ実装していない          すごく大変。(興味がある人は後で話しましょう)
  18. 18. 面倒くさいRubyの機能  ・ メソッドの再定義 (make testで使いまくり)  ・ Fiber (h2oで使いまくり)  ・ send (optcarrot(ファミコンエミュレータ)で使いまくり)  ・ Procオブジェクト  ・ eval (require代わりに使ったりするから無視するわけにはいかない) だいたい自己書き換えコードかVMに丸投げで解決 あと、Cで実装されたメソッドでtarget_classをnullにするとcontextを更新出来る機能がとて も役に立っている(すごく込み入った話なので省略)
  19. 19. おしまい ありがとうございました

×