Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.
Rubiniusのしくみ
@highwide
表参道.rb #8
$whoami
@highwide (Twitter / GitHub)
(株)リブセンスでRailsを書いてます
最近は初めてのElasticsearchに四苦八苦しています
社内の「コンパイラ/インタプリタ」をテーマにしたLT大会で
Rub...
Rubiniusって何?
Rubyの処理系の1つ
CRuby: CによるRubyの実装

(MRI: Matz Ruby Implementation)
JRuby: JVMで動くRubyの実装
Rubinius:
作者: Evan Phoenixさん

(RubyKa...
Ruby6割 / C++3割
コンパイラの大半が
Rubyで書かれている?
どうやって動くの?
% cat hoge.rb
10.times do |n|
puts "No. #{n}"
end
% ./rubinius/bin/rbx hoge.rb
No. 0
No. 1
No. 2
No. 3
No. 4
No. 5
No. 6
N...
実行されるまでの流れ
Rubinius命令列
Rubyコード
トークン列
AST
LLVM命令列
機械語
バイトコード
コンパイル
必要に応じて
JITコンパイル
VM
実行
解釈
ちなみにMRI
YARV命令列
Rubyコード
トークン列
AST
バイトコード
コンパイル
YARV
実行
解釈
バイトコードコンパイルとは
RubyのコードをVMが理解できる命令列(バイト
コード)にコンパイルすること
ざっくり言うと
パーサがRubyのコードをバラして
AST(抽象構文木)を作って
ASTを命令列化して
命令列オブジェクトにして
プロパ...
バイトコードコンパイルの各段階を
「ステージ」と呼ぶそうです
http://rubinius.com/doc/ja/bytecode-compiler/
パーサがRubyのコードをバラして
(どう見てもMRIのパーサ)
ASTを作って
(コンパイル時に
-Aオプションで
ASTを見られる)
% ./rubinius/bin/rbx compile -A hoge.rb
@pre_exe: []
@name: :__script__
@file: "hoge.r...
ちょっと余談: コンパイル時に
-SオプションでS式を見られる
% ./rubinius/bin/rbx compile -S hoge.rb
[:script,
[:call,
[:lit, 10],
:times,
[:arglist,
[...
% ./rubinius/bin/rbx compile -B hoge.rb
============= :__script__ ==============
Arguments: 0 required, 0 post, 0 total
Ar...
% ./rubinius/bin/rbx compile -B hoge.rb
============= :__script__ ==============
Arguments: 0 required, 0 post, 0 total
Ar...
% ./rubinius/bin/rbx compile -B hoge.rb
============= :__script__ ==============
Arguments: 0 required, 0 post, 0 total
Ar...
言語のkernelが
Rubyで書かれている
ことがわかります
10.times do |n|
puts "No. #{n}"
end
コンパイルされた命令列を
C++で書かれた
VMが評価していきます
!RBIX
1933235666460458080
22
M
1
n
n
x
E
8
US-ASCII
...
ここからが
Rubiniusの真骨頂
JITコンパイルだー!
と思うのですが...
誤解しがちなこと

(僕が誤解していたこと)
「なぜRubiniusはLLVMでコンパイルする言語なのに
CやRustほど速くないの?」
"Rubinius doesn't compile Ruby down native code, instead
it uses a JIT to compile certain blocks of code, but only
wheneve...
すべてのコードを
JITコンパイルで
機械語にしているわけ
じゃなかった
RubiniusのJITコンパイル
特徴: Method JIT
> メソッドが何度も呼び出されるときに行なう最適化です。この方法だと,
一度コンパイルされたメソッドは再利用できますが,コンパイルには時間が
かかり,インライン化によってメソッド...
おさらい
Rubinius命令列
Rubyコード
トークン列
AST
LLVM命令列
機械語
C
必要に応じて
JITコンパイル
VM
実行
解釈
Ruby
C++
カーネルがRubyで
書かれているということは
ActiveSupportの
メソッドの移植なんて
こともできるのでは?
Rubyで
書かれているので
さくっと
「try!」実装する
なんてことも
できました!
class Object
----snip----
def try!(*a, &b)
if a.empty? && block_given?
if b.a...
本当はRubiniusに
ぼっちオペレーター
実装しようとしたのですが
parse.yが書けずに断念しました
&.
Rubinius
思った以上に
おもしろかったです!
"Rubinius はただの Ruby 処理系では
ない。Rubinius は Ruby コ ミュニティ
にとって価値ある学習リソースだ "
「Rubyのしくみ」p330
ありがとう
ございました
「お詫び」または

「Thank you for your マサカリ」
Rubiniusのコードを完全に追えたわけではなく、書
籍やドキュメント等の情報を元にしながらポイント
ごとに実装を見て、まとめました...。
おかしいなと思ったら是非ご指...
謝辞
社内でLTをやったあと、「Rubyのしくみ」
の原文や、Rubiniusのissueから、「すべて
のコードを機械語にJITコンパイルするわけ
ではない」ということを突き止めて説明して
くれた、同僚@na_o_ys氏にとっても感謝し
てい...
Web
https://github.com/rubinius/
http://rubinius.com/doc/ja/what-is-rubinius/

- Rubinius.com 「Rubiniusとは」
https://blog.en...
Prochain SlideShare
Chargement dans…5
×

3

Partager

Télécharger pour lire hors ligne

Rubinius Under a Microscope

Télécharger pour lire hors ligne

表参道.rb #8でLTしたRubiniusについてのスライドです。

Livres associés

Gratuit avec un essai de 30 jours de Scribd

Tout voir

Rubinius Under a Microscope

  1. 1. Rubiniusのしくみ @highwide 表参道.rb #8
  2. 2. $whoami @highwide (Twitter / GitHub) (株)リブセンスでRailsを書いてます 最近は初めてのElasticsearchに四苦八苦しています 社内の「コンパイラ/インタプリタ」をテーマにしたLT大会で Rubiniusについて調べたので、表参道.rbでも披露させてもら おうと今日はやってきました よろしくお願いします!
  3. 3. Rubiniusって何?
  4. 4. Rubyの処理系の1つ CRuby: CによるRubyの実装
 (MRI: Matz Ruby Implementation) JRuby: JVMで動くRubyの実装 Rubinius: 作者: Evan Phoenixさん
 (RubyKaigi3日目Keynoteスピーカー) 高速なRuby実行環境を目指している バイトコード仮想マシンがC++で実装 LLVMによるJITコンパイルの仕組みがある コンパイラの大半がRubyで書かれている
  5. 5. Ruby6割 / C++3割
  6. 6. コンパイラの大半が Rubyで書かれている? どうやって動くの?
  7. 7. % cat hoge.rb 10.times do |n| puts "No. #{n}" end % ./rubinius/bin/rbx hoge.rb No. 0 No. 1 No. 2 No. 3 No. 4 No. 5 No. 6 No. 7 No. 8 No. 9 例えば: この裏で行われていることは?
  8. 8. 実行されるまでの流れ Rubinius命令列 Rubyコード トークン列 AST LLVM命令列 機械語 バイトコード コンパイル 必要に応じて JITコンパイル VM 実行 解釈
  9. 9. ちなみにMRI YARV命令列 Rubyコード トークン列 AST バイトコード コンパイル YARV 実行 解釈
  10. 10. バイトコードコンパイルとは RubyのコードをVMが理解できる命令列(バイト コード)にコンパイルすること ざっくり言うと パーサがRubyのコードをバラして AST(抽象構文木)を作って ASTを命令列化して 命令列オブジェクトにして プロパティを設定して VMが読める「 .rbc」形式にします
  11. 11. バイトコードコンパイルの各段階を 「ステージ」と呼ぶそうです http://rubinius.com/doc/ja/bytecode-compiler/
  12. 12. パーサがRubyのコードをバラして (どう見てもMRIのパーサ)
  13. 13. ASTを作って (コンパイル時に -Aオプションで ASTを見られる) % ./rubinius/bin/rbx compile -A hoge.rb @pre_exe: [] @name: :__script__ @file: "hoge.rb" @body: Send @line: 1 @name: :times @privately: false @vcall_style: false @receiver: FixnumLiteral @line: 1 @value: 10 @block: Iter @line: 1 @locals: nil @body: SendWithArguments @line: 2 @name: :puts @privately: true @vcall_style: false @block: nil @receiver: Self @line: 2 ----snip----
  14. 14. ちょっと余談: コンパイル時に -SオプションでS式を見られる % ./rubinius/bin/rbx compile -S hoge.rb [:script, [:call, [:lit, 10], :times, [:arglist, [:iter, [:args, :n], [:call, nil, :puts, [:arglist, [:dstr, "No. ", [:evstr, [:lvar, :n]]]]]]]]]
  15. 15. % ./rubinius/bin/rbx compile -B hoge.rb ============= :__script__ ============== Arguments: 0 required, 0 post, 0 total Arity: 0 Locals: 0 Stack size: 2 Literals: 2: <compiled code>, :times Lines to IP: 1: 0..9 0000: push_int 10 0002: create_block #<Rubinius::CompiledCode __block__ file=hoge.rb> 0004: send_stack_with_block :times, 0 0007: pop 0008: push_true 0009: ret ---------------------------------------- ============== :__block__ ============== Arguments: 1 required, 0 post, 1 total Arity: 1 Locals: 1: n Stack size: 5 Literals: 3: "No. ", :to_s, :puts Line: 1 Lines to IP: 2: 0..14 0000: push_self 0001: push_literal "No. " 0003: push_local 0 0005: allow_private 0006: meta_to_s :to_s 0008: string_build 2 0010: allow_private 0011: send_stack :puts, 1 0014: ret ---------------------------------------- ASTを命令列化する (コンパイル時に -Bオプションで バイトコードを 見られる)
  16. 16. % ./rubinius/bin/rbx compile -B hoge.rb ============= :__script__ ============== Arguments: 0 required, 0 post, 0 total Arity: 0 Locals: 0 Stack size: 2 Literals: 2: <compiled code>, :times Lines to IP: 1: 0..9 0000: push_int 10 0002: create_block #<Rubinius::CompiledCode __block__ file=hoge.rb> 0004: send_stack_with_block :times, 0 0007: pop 0008: push_true 0009: ret def push_int(arg1) if arg1 > 2 and arg1 < 256 @stream << 4 << arg1 @current_block.add_stack(0, 1) @ip += 2 @instruction = 4 else case arg1 when -1 meta_push_neg_1 when 0 meta_push_0 when 1 meta_push_1 when 2 meta_push_2 else push_literal arg1 ----snip---- def send_stack_with_block(arg1, arg2) @stream << 57 << arg1 << arg2 @ip += 3 @current_block.add_stack(arg2+2, 1) @instruction = 57 end これらのバイトコードは、Rubyの DSLで表現されていて、仮想マシ ン(C++)の命令と対応している
  17. 17. % ./rubinius/bin/rbx compile -B hoge.rb ============= :__script__ ============== Arguments: 0 required, 0 post, 0 total Arity: 0 Locals: 0 Stack size: 2 Literals: 2: <compiled code>, :times Lines to IP: 1: 0..9 0000: push_int 10 0002: create_block #<Rubinius::CompiledCode __block__ file=hoge.rb> 0004: send_stack_with_block :times, 0 0007: pop 0008: push_true 0009: ret send_stack∼といった命令列に渡されるメソッド名は Rubiniusの中で、Rubyで定義されている ※組み込みクラスはC++で書かれているので一部C++で処理するものも。 def times return to_enum(:times) { self } unless block_given? i = 0 while i < self yield i i += 1 end self end rubinius/kernel/common/integer.rb バイトコード ※Rubiniusのビルド時に コンパイル済
  18. 18. 言語のkernelが Rubyで書かれている ことがわかります
  19. 19. 10.times do |n| puts "No. #{n}" end コンパイルされた命令列を C++で書かれた VMが評価していきます !RBIX 1933235666460458080 22 M 1 n n x E 8 US-ASCII 10 __script__ i 10 4 10 63 0 57 1 0 21 2 17 I 2 I 0 I 0 -------snip------ hoge.rb hoge.rbc 3行 158行
  20. 20. ここからが Rubiniusの真骨頂 JITコンパイルだー! と思うのですが...
  21. 21. 誤解しがちなこと
 (僕が誤解していたこと) 「なぜRubiniusはLLVMでコンパイルする言語なのに CやRustほど速くないの?」
  22. 22. "Rubinius doesn't compile Ruby down native code, instead it uses a JIT to compile certain blocks of code, but only whenever possible (or deemed necessary based on the call amounts)." "RubiniusはRubyを機械語にコンパイルせずに、代わり に、いくつかのブロックを可能なときだけ(あるいはそのブ ロックの呼び出し回数に応じた必要性を判断して)、JITコンパイ ルを行う" 誤解しがちなこと
 (僕が誤解していたこと) https://github.com/rubinius/rubinius/issues/3165
  23. 23. すべてのコードを JITコンパイルで 機械語にしているわけ じゃなかった
  24. 24. RubiniusのJITコンパイル 特徴: Method JIT > メソッドが何度も呼び出されるときに行なう最適化です。この方法だと, 一度コンパイルされたメソッドは再利用できますが,コンパイルには時間が かかり,インライン化によってメソッドのサイズが大きくなります。 http://gihyo.jp/news/report/01/rubykaigi2015/0003 命令1 命令1 命令2 命令2 命令1 命令1の
 定義 命令2の
 定義 インライン化 命令1の定義 命令1の定義 命令1の定義 命令2の定義 命令2の定義 LLVMが最適化しやすい 動的言語の性質を活かしたまま、静的な割当てが可能
  25. 25. おさらい Rubinius命令列 Rubyコード トークン列 AST LLVM命令列 機械語 C 必要に応じて JITコンパイル VM 実行 解釈 Ruby C++
  26. 26. カーネルがRubyで 書かれているということは ActiveSupportの メソッドの移植なんて こともできるのでは?
  27. 27. Rubyで 書かれているので さくっと 「try!」実装する なんてことも できました! class Object ----snip---- def try!(*a, &b) if a.empty? && block_given? if b.arity.zero? instance_eval(&b) else yield self end else public_send(*a, &b) end end end kernel/alpha.rb class NilClass ----snip---- def try!(*args) nil end end kernel/nil.rb % cat try_length.rb
 p 'hoge'.try!(:length) p nil.try!(:length) % ./bin/rbx try_length.rb
 4 nil 「kernel/」にRubyのメソッドの定義 が書かれているので、Objectクラスと nilクラスにtry!を定義してコンパイル
  28. 28. 本当はRubiniusに ぼっちオペレーター 実装しようとしたのですが parse.yが書けずに断念しました &.
  29. 29. Rubinius 思った以上に おもしろかったです!
  30. 30. "Rubinius はただの Ruby 処理系では ない。Rubinius は Ruby コ ミュニティ にとって価値ある学習リソースだ " 「Rubyのしくみ」p330
  31. 31. ありがとう ございました
  32. 32. 「お詫び」または
 「Thank you for your マサカリ」 Rubiniusのコードを完全に追えたわけではなく、書 籍やドキュメント等の情報を元にしながらポイント ごとに実装を見て、まとめました...。 おかしいなと思ったら是非ご指摘くださいm(_ _)m
  33. 33. 謝辞 社内でLTをやったあと、「Rubyのしくみ」 の原文や、Rubiniusのissueから、「すべて のコードを機械語にJITコンパイルするわけ ではない」ということを突き止めて説明して くれた、同僚@na_o_ys氏にとっても感謝し ています!!
  34. 34. Web https://github.com/rubinius/ http://rubinius.com/doc/ja/what-is-rubinius/
 - Rubinius.com 「Rubiniusとは」 https://blog.engineyard.com/2010/making-ruby-fast-the-rubinius-jit
 - ENGINE YARD BLOG 「Making Ruby Fast: The Rubinius JIT」 http://gihyo.jp/news/report/01/rubykaigi2015/0003
 - gihyo.jp 「RubyKaigi 2015レポート Evan Phoenixさん「Rubyを速く するのは今がその時」 ∼RubyKaigi 2015 基調講演 3日目」 図書 Rubyのしくみ -Ruby Under a Microscope-
 - Pat Shaughnessy (著), 島田 浩二 (翻訳), 角谷 信太郎 (翻訳) 参考
  • naitoh1

    Sep. 17, 2016
  • syokenz

    Feb. 8, 2016
  • KatsuyaTokuyama

    Feb. 5, 2016

表参道.rb #8でLTしたRubiniusについてのスライドです。

Vues

Nombre de vues

1 393

Sur Slideshare

0

À partir des intégrations

0

Nombre d'intégrations

111

Actions

Téléchargements

6

Partages

0

Commentaires

0

Mentions J'aime

3

×