k0kubun/ruby-jit-challenge 完了報告

16.85倍はやいベンチマーク結果
16.85倍はやい僕のJIT

RubyKaigi 2023 お疲れ様でした。非常に面白かったですね。k0kubun さんのRJITについての発表が面白かったので ruby-jit-challange をやりました。無事完走できたので感想記事を書こうと思います(激ウマギャグ)

※: ベンチマークから rjit が抜かれてる理由は後述

RJIT / ruby-jit-challenge ってなに

k0kubun さんが RubyJIT を書けるような機構を作ってくれました。それをRJITと呼びます。RJIT を手を動かして体験できるチュートリアルが公開されています。親切なREADME、命令列をJITするところ以外の部分、機械語生成用のヘルパーも用意されておりおもてなしの精神がすごい。みんなぜひやりましょう

github.com

なお冒頭で16倍はやいっていっていますが、特定ベンチマークにしか対応しておらず、そのへんの ruby スクリプトのうち1%もまともに動かないような状態だと思います。これをちゃんと全部カバーするとどんどん遅くなるんでしょうね……。

やろうかなと思っている人へ

やりましょうとは言いましたがやる人が挫折しないようにアドバイスを。

ヒントは見るべき

README にヒントがありますがヒントを見るのをためらわないでください。私はCコンパイラ自作ちょっとやってみたし、MRI の実装眺めたり適当にいじったりしたこともあるからヒントなしでいけるか〜とか思ったけど全然いけませんでした。ヒントなしで要求されることは例えば以下のようなことになります。

  • YARV の命令列を見て意味がわかる
  • 命令の name 以外の情報がどこにあるかわかる
  • nil や false や Integer が RVALUE としてどういう byte 表現になっているかわかる
  • スタックマシンを前提としたアセンブリがどんなもんかわかる
  • RJIT Compiler 上から必要なデータに触れればいいかわかる

(他にもあったような気がするがぱっと出てこない)

上述の知識がないという自覚がある人はヒントをガンガン読んでそこから学べばよいと思いました

やってみたらプロセスが返ってこなくなった

実質アセンブリ書いてるようなもんなのでSEGVとかcfp不一致とかでひたすら怒られるわけですが。ruby/ruby とかでそんなことが起きても特に問題なくプロセス終了してくれるじゃないですか。今回はそういう安全機構も自分で書かないとだめらしいです(というのを飲み会で聞いた気がするが間違ってたらすみません)。そんなことやってられないので踏んだら docker コンテナをまるごと落としましょう。だいたい以下のようなコマンドをやってました

# bin/ruby の引数とかオプションは開発状況に合わせてお好みで。
$ docker run --platform linux/amd64 -it -v "$(pwd):/app" k0kubun/rjit bash -c "bin/ruby --rjit-dump-disasm test/lt.rb" 

# かえってこなかったら別タブでこんな感じに。grep とかは一意に指定できる程度にどうぞ
$ docker ps | grep k0kubun | awk '{print $1}' | xargs docker kill

bin/bench で rjit が落ちる

なんか僕の環境だと落ちました。test/fib.rb の時点で落ちるけど。k0kubun さんに報告しているのであんまり深追いしていません。

どうだった?

面白かったですね。Cコンパイラ自作頓挫勢ですが、アセンブリDSLがよくできていて、文字列操作で書いてたのに比べてずいぶんきもちよかったです。実際何もかもを捨て去ったJITコンパイラだととりあえず10倍くらいはやいのがかけるってのは素直にすごいなーとなりました。そういえばCコンパイラよりもより局所的にアセンブリを書くことになるのでそういう意味でもこっちから入門したほうが楽かもしれません。

コンテンツ的に面白かったし自分がJIT書くってことが人生であると思ってなかったので id:k0kubun さんに感謝。また、こんなに面白かったのに完走報告がいままでなかったらしいのでみんなやればいいのに〜という感じで記事を書いています。

↓僕の実装です。まあ特に見る必要はなく本家の正解ブランチを見ればいいと思います。

github.com