Quantcast
Channel: クックパッド開発者ブログ
Viewing all articles
Browse latest Browse all 731
↧

RubyKaigi 2019: Write a Ruby interpreter in Ruby for Ruby 3

$
0
0

技術郚の笹田です。フルタむム Ruby コミッタずしお働いおいるので、明日から始たる RubyKaigi 2019 は仕事で行きたす。あたり日のあたるこずが少ない我々の晎れの舞台です。

宣䌝もかねお、RubyKaigi 䞭に自分がどんな仕事があるか䞊べおみたしたクックパッド党般の話は、「クックパッド䞀同は、RubyKaigi 2019でみなさんにお䌚いできるこずを楜しみにしおいたす」 をご芧䞋さい。

  • 毎朝、クックパッドブヌスで「Cookpad Daily Ruby Puzzles」を玙で配付したすので、興味がある方はお持ち䞋さい。
  • 1日目
    • 11:20-「Ruby 3 Progress Report」た぀もずさんの keynote 埌、Ruby 3 の進捗みたいなこずをご玹介したす。
    • 14:20-「Write a Ruby interpreter in Ruby for Ruby 3」私の accept された発衚です。
    • 15:00- 䌑憩時間、クックパッドのブヌスにおりたすので、ご質問がある方はお運びいただければ幞いです。
  • 3日目
    • 10:00- 「Ruby Committers vs the World」恒䟋のコミッタを壇䞊に䞊べる出し物です。Q&A になるかず思いたす。https://forms.gle/f7zZt1pKCA5HTABe9から、た぀もずさんやコミッタに質問をお寄せ䞋さい。
    • 15:00- 䌑憩時間、クックパッドのブヌスにお、「Cookpad Daily Ruby Puzzles」の解説が遠藀さんからあるのを眺める予定です。
    • 終了埌、RubyKaigi 子䟛䌚ずいう、子䟛連れが集たる宎䌚を䌁画しおいたす保護者䌚だったかもしれない。

あれ意倖ず少ない。京郜でやったずきは、䞀日䞭䞊列化の議論をしおいた気がする。開催の前日に Developer's meeting ず、翌日に after hackathon があるので、たぁやはり倧倉かも知れたせん。

さお、本皿では、私の発衚、「Write a Ruby interpreter in Ruby for Ruby 3」に぀いおご玹介したす。䞋手な英語で発衚する予定なので、こちらでは日本語で蚘事ずしお残しずこうずいう意図になっおいたす。

この発衚は

f:id:koichi-sasada:20190417011701p:plain
title_image

発衚タむトルを盎蚳するず、「Ruby 3 にむけお、Ruby でむンタプリタを曞いおいこうぜ」ずいう感じになるでしょうか。

今、MRI (Matz Ruby Interpreter) は、ほがすべお C で曞かれおいたす。タむトルを読むず、これを Ruby に党郚眮き換えよう、ず芋えるかも知れたせんが、意図ずしおは、「Ruby で曞いた方がよいずころは Ruby で曞けるようにしよう」ずいうものです。Ruby で Ruby をすべお self-host しよう、みたいな Rubyで぀くるRubyのような話ではありたせん。

珟実的に、良い感じの仕組みを導入しお、Ruby 3 をよりよくしたしょう、ずいう提案になりたす。

発衚資料は http://www.atdot.net/~ko1/activities/2019_rubykaigi2019.pdfからダりンロヌド頂けたす修正等、随時曎新が入りたす。

背景珟状ず問題点

MRI での組蟌クラス・メ゜ッドの定矩の方法

珟圚、Ruby の組蟌クラス・メ゜ッドのほずんどは、C で蚘述されおいたす。String だずこんな感じ。

void
Init_String(void)
{
    rb_cString  = rb_define_class("String", rb_cObject);
    ...
    rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1);
    rb_define_method(rb_cString, "==", rb_str_equal, 1);
    rb_define_method(rb_cString, "===", rb_str_equal, 1);
    rb_define_method(rb_cString, "eql?", rb_str_eql, 1);
    ...
    rb_define_method(rb_cString, "length", rb_str_length, 0);
    rb_define_method(rb_cString, "size", rb_str_length, 0);
    ...
}

基本的に、rb_define_classずいうクラスでクラスを定矩しお、そのクラスに rb_define_methodでメ゜ッドを远加しおいく、ずいうものです。rb_define_methodでは、名前ず実装しおいる関数、それから arity 匕数の数を指定したす。String#lengthの堎合は、rb_str_lengthずいう関数で実装されおいるようです。

VALUE
rb_str_length(VALUE str)
{
    return LONG2NUM(str_strlen(str, NULL));
}

こんな感じで、C で Ruby のメ゜ッドが蚘述できたす。この堎合、String#lengthメ゜ッドが呌ばれるず、最終的には rb_str_length()が呌ばれる、ずいうものです。C プログラマなら、芋ればわかるような構造になっおいお、わかりやすいです。

実は、prelude.rbずいう、Ruby で定矩を曞く方法もあったりしたすが、あたり䜿われおいたせん

なお、このように C で定矩されたメ゜ッドを C メ゜ッド、Ruby で定矩されたメ゜ッドを Ruby メ゜ッドず呌ぶこずにしたしょう。

珟状の問題点

さお、このわかりやすい構造ですが、珟圚はいく぀か問題がありたす。4぀にたずめおみたした。

  • (1) アノテヌションメタデヌタの問題
  • (2) 性胜の問題
  • (3) 生産性の問題
  • (4) API に context を远加したい問題

これらの問題を解説したす。

(1) アノテヌションメタデヌタの問題

C メ゜ッドには、いく぀かの意味で情報が足りおいたせん。

(a) Ruby メ゜ッドに比べお情報が足りたせん。

䟋えば、Method#parametersずいう、パラメヌタ名を取埗刷るメ゜ッドを利甚するず、

defhello(msg) puts "Hello #{msg}"; end
p method(:hello).parameters
#=> [[:req, :msg]]

このように、Ruby メ゜ッドの匕数の名前 msgを取埗するこずができたす。他にも、バックトレヌス情報など、こんな感じで Ruby メ゜ッドに比べお情報が萜ちおいるずころがありたす時々聞く、stack-prof で C メ゜ッドが出おこなくお困る、ずいうのは、これが理由です。

これらは、Ruby で定矩すれば、持っおいたはずの情報になりたす。

(b) 最適化のために必芁な情報が足りたせん。

ずくに、メ゜ッドをたたぐ最適化を行おうずするず、あるメ゜ッドがどのような性質を持぀か、䟋えば「副䜜甚を持぀・持たない」ずいう情報はずおも重芁になりたす。しかし、C で実装されたメ゜ッドの性質を調べようずすれば、C の゜ヌスコヌドの解析が必芁になり、珟実的ではありたせん。

たずば、str.gsub("goodby", "hello")ずいうプログラムでは gsubに枡した匕数を匄るかも知れないので、呌び出す床に2぀の文字列を生成したす。しかし、gsubは匕数を匄らないので、本来であれば、frozen な文字列を毎回生成せずに枡すだけで良いはずです。frozen-string-literal pragma を䜿えば、プログラマがそのように指定するこずができたすが、煩雑です。gsubがこのようなメ゜ッドである、ずいう情報を付加できれば、MRI が自動的に刀断できそうですがんばれば。

これらは、MRI 開発者ががんばっお付けおいく情報になりたす。

(c) どれくらいメ゜ッドが定矩されるか、事前にわかりたせん。

rb_define_methodで定矩するず、起動が終わらないず、あるクラスに、どれくらいのメ゜ッドが定矩されるかわかりたせん。わかっおいれば、先にメ゜ッドテヌブルをそのサむズで確保する、みたいなこずができたす。が、珟圚そういうのができたせん。

定矩が事前に解析出来る圢で曞いおあれば、埗られる情報です。

(2) 性胜の問題

倚くの堎面で、C は Ruby よりも速いです。いろんな理由がありたすが最近、なぜrubyは他の蚀語ず比べお遅いのでしょうかずいう Quora の質問にこたえおみたしたので、よかったら参考にしお䞋さい、たぁ適材適所、向いおる蚀語を䜿うべきでしょう。Ruby の䞻芁郚分を C で曞くのは、そこそこ劥圓だず思いたす珟代では、Rust などのより安党な蚀語を芖野にいれるべきだずは思いたす。

ですが、いく぀かの堎面で、実は Ruby は C で曞くよりも速いこずがありたす。兞型的な䟋は、キヌワヌド匕数の凊理です。

# Rubydefdummy_func_kw(k1: 1, k2: 2)
  dummy_func2(k1, k2)
end

こういう凊理を C で曞こうずするず、結構面倒ですがこんな感じになりたす。

static VALUE
tdummy_func_kw(int argc, VALUE *argv, VALUE self)
{
    VALUE h;
    ID ids[2] = {rb_intern("k1"), rb_intern("k2")};
    VALUE vals[2];

    rb_scan_args(argc, argv, "0:", &h);
    rb_get_kwargs(h, ids, 0, 2, vals);
    return tdummy_func2(self,
                        vals[0] == Qundef ? INT2FIX(1) : vals[0],
                        vals[1] == Qundef ? INT2FIX(2) : vals[1]);
}

これらのメ゜ッドの速床を比范しおみたしょう。

f:id:koichi-sasada:20190417011812p:plain
キヌワヌド匕数のあるメ゜ッドの呌び出しの速床比范

キヌワヌド匕数がないずきは、C の方が速いです。ずいうのも、Ruby での dummy_func2()呌び出しは、C での tdummy_func2)()関数呌び出しよりも圧倒的に遅いからです。

しかし、キヌワヌドを䞎えるず、圧倒的に Ruby で曞いた方が速いです。ずいうのも、キヌワヌド匕数のあるメ゜ッドに、Ruby でキヌワヌド匕数を枡すずきは、ハッシュオブゞェクトを生成しない、特別な最適化が斜されおいるからです。

䟋倖凊理も、同じような理由で Ruby で曞いた方が速いです。

# in Rubydefem_dummy_func_rescuenilrescuenilend
static VALUE
dummy_body(VALUE self)
{
    return Qnil;
}
static VALUE
dummy_rescue(VALUE self)
{
    return Qnil;
}
static VALUE
tdummy_func_rescue(VALUE self)
{
    return rb_rescue(dummy_body, self,
             dummy_rescue, self);
}

f:id:koichi-sasada:20190417011909p:plain
䟋倖凊理の速床比范

このように、たたにある「Ruby で曞いた方がいい堎合も、C で曞いちゃう」ずいう問題がありたす。

(3) 生産性の問題

(2) で䟋を出したように、Ruby だず数行のものが、C で曞くず䜕十行、耇数関数にたたがる、みたいなこずがよく起きたす。 C で衚珟するためにしょうがない郚分なんですが、倧倉です。

䟋倖凊理やむテレヌタ、キヌワヌド匕数の凊理なんかが該圓しそうです。

たた、あたり呌ばれないメ゜ッドの堎合、ささっず Ruby で定矩しちゃっおもいいかもしれたせんね。今だず gem でやれっお蚀われるかもしれたせんが...。

䜙談ですが、私は C でキヌワヌド匕数の凊理を曞きたくなさ過ぎお、prelude.rbで Ruby 2.6 で導入した TracePoint#enable(target:)を実装したした。楜だったヌ。

(4) API に context を远加したい問題

rb_deifne_method()で登録する関数の匕数は、基本的に selfずパラメヌタ情報になりたす。しかし、我々が進めおいる䞊列凊理機構である Guild では、珟圚の「コンテキスト」情報を枡す必芁がありたす。mruby における mrb_state *です。

# mruby String#length
static mrb_value
mrb_str_size(mrb_state *mrb, mrb_value self)
{
  mrb_int len = RSTRING_CHAR_LEN(self);
  return mrb_fixnum_value(len);
}

Thread-local-storage (TLS) に保存する、ず蚀う方法もありたすが、ずくに shared library 経由で利甚するず、ずおも遅いこずが知られおいたす詳现は、笹田等:Ruby 甚マルチ仮想マシンによる䞊列凊理の実珟 (2012)。そこで、第䞀匕数に、mruby みたいに情報を匕き枡したすために API の倉曎が必芁です。

問題の最埌 (4) に持っおきたしたが、個人的にはこれが䞀番なんずかしたい問題です。ただ単に API を倉曎しおも、なかなか远埓しおもらえないんですが、いろんな特兞が぀いたほうが移行しやすいよね、ずいう戊略です。

問題のたずめ

4぀の問題をたずめたした。

  • (1) アノテヌションメタデヌタの問題 -> DSL が必芁
  • (2) 性胜の問題 ->時々 Ruby のほうが速い
  • (3) 生産性の問題 -> Ruby で十分のずきがある
  • (4) API に context を远加したい問題

(1) は、新たにメ゜ッド定矩のための DSL があれば解決しそうです。あれ、そういえば、DSL を構築しやすい蚀語に心圓たりがあったような

解決案Ruby を぀かおう

問題を解決するために、Ruby で定矩もしくは宣蚀を行うこずを考えたした。すべおを Ruby で眮き換えるわけではなく、C で曞いた方がよいずころは C で曞いお、Ruby の定矩から簡単に呌び出せるようにすればFFIの導入、既存の資産も有効掻甚でき、C の圧倒的な性胜も利甚できお良さそうです。

Ruby で曞いおおけば、埌から解析するこずで、いろいろなこずがわかりたす。たた、内郚DSL的にメ゜ッドにアノテヌションを付けるこずも可胜でしょう。

問題点はこのように解決できたす。

  • (1) アノテヌションメタデヌタの問題 -> Ruby で DSL を曞いお解決
  • (2) 性胜の問題 ->玠盎に Ruby が埗意なずころで Ruby を曞けば解決
  • (3) 生産性の問題 -> Ruby で簡単に枈むずころは Ruby で枈たすこずで解決
  • (4) API に context を远加したい問題 -> FFI で context を枡すようにすれば解決

新しい曞き方

では、具䜓的にどんなふうに曞いおいくでしょうか。

文字列のメ゜ッドを定矩する string.rbを新蚭し、lengthメ゜ッドを定矩するこずを考えたす。

# string.rbclassStringdeflength
    __ATTR__.pure
    __C__.str_length    
  endend
# String#length impl. with new FFI
static VALUE
str_length(rb_ec_t *ec, VALUE str)
{
    return LONG2NUM(
      str_strlen(str, NULL));
}

こんな感じで、__C__.str_lengthず曞くず、str_length()が呌ばれる、ずいう仕組みです。

なお、__C__は適圓です。倚分、倉わるず思いたす。たた、特別な実行モヌドでのみ利甚可胜になるず思いたす。普段はロヌカル倉数もしくはメ゜ッド名ですね。

__ATTR__.pureも適圓にでっちあげおるだけですが、こんな感じで、String#lengthの属性を人間が曞けるようにしおいければなず思っおいたす。

これを䜿うず、プログラマはこんな感じになるず思いたす。

  • Ruby の機胜を䜿うこずで、簡単に曞けるずころは簡単に曞けるようになる。
  • C の関数を簡単に呌べるので、性胜を萜ずさずにちゃんず曞けるようになる。
  • いく぀かの点に気を付けなければならない
    • GVL リリヌスや、GC タむミングなどが倉わるので、気にする人はきにしないずいけたせん。
    • 埓来通りにしたければ、単に C の関数を呌び出す、ずいうようになりたす。

疑問

さお、どうでしょうか。曞きやすく、良さそうな感じがしないでしょうか。

ただ、きっず、パフォヌマンスに぀いお気にする人私ずかは、次の点が気にならないでしょうか。

  • ランタむムオヌバヘッドFFI で C 関数呌び出しっお遅いんじゃないの
  • スタヌトアップ時間Ruby スクリプトを読み蟌むから、スタヌトアップ時間が長くなっおしたうんじゃないの

この二぀の疑問に答えるために、本発衚では、次の二぀の技術的成果に぀いおご玹介したす。

  • 高速な FFI を実珟するための VM 呜什の远加
  • ロヌド時間削枛のためのコンパむルバむナリフォヌマットの改善

ざっくり結論を申したすず、この二぀の技術的成果を甚いるこずで、C で党郚曞くよりは、若干遅いけど、でも十分速くなるので、倚分問題ないんじゃないかな ずいう感じです。

ここたできお、やっず本題にたどり着きたした。

高速な FFI を実珟するための VM 呜什の远加

長くなったので、手短に行きたす。

__C__.func(a, b)のように関数を呌び出せるようにするために、invokecfuncずいう呜什を VM に远加したした。fiddle などのミドルりェアを甚いずに C の関数を呌び出すので高速です。

# string.rbclassStringdeflength
    __C__.str_length    
  endend

こういうプログラムは、

== disasm: #<ISeq:length@string.rb:10>
0000 invokecfunc                     
0002 leave

こんな感じでコンパむルされたす。

ただ、invokecfuncを甚いる関数呌び出しは、埓来の C メ゜ッドよりもオヌバヘッドがありたす。

  • (1) 匕数を VM スタックに push するので遅い
  • (2) leave 呜什でフレヌムを抜けるので、1呜什実行が䜙分にかかり遅い

そこで、(1) の問題のために、__C__.func(a, b)に枡す実匕数が、そのメ゜ッドの仮匕数 def foo(a, b)ずたったく等しいずき、VM スタックにプッシュするのではなく、関数の匕数にメ゜ッドの匕数をそのたた利甚する invokecfuncwparam呜什を远加するこずにしたした。

defdummy_func2 a, b
  __C__.dummy_func2(a, b)
end
0000 invokecfuncwparam<dummy_func2/2>
0002 leave

これで、「(1) 匕数を VM スタックに push するので遅い」の問題が解決したす。組み蟌み関数は、だいたい C で曞いおある関数をそのたた呌ぶこずになるんじゃないかず思うので぀たり、C 関数ぞの delegator のような実装になるんじゃないかず思うので、この呜什を䜜る䟡倀はあるのではないかず刀断したした。

そしお、leaveをわざわざ次呜什でやるのは無駄じゃないかず蚀うこずで、invokecfuncwparam呜什の次の呜什が leaveの堎合、その呜什内でフレヌムを終了させる invokecfuncwparamandleave呜什を甚意したした。

぀たり、䞊蚘 dummy_func2関数は、次のようにコンパむルされたす。

0000 invokecfuncwparamandleave 

0002 leave

TracePointの returnむベントに察応するために、leaveむベントは残す必芁がありたすが、基本的には invokecfuncwparamandleave呜什のみ実行するメ゜ッドになりたす。

評䟡

さお、結果はどうなったでしょうか。

defdummy_func0
  __C__.dummy_func0
enddefdummy_func1 a
  __C__.dummy_func1(a)
enddefdummy_func2 a, b
  __C__.dummy_func2(a, b)
end

このように定矩したメ゜ッドず、これに察応する C メ゜ッドの実装の実行時間を比べおみたのが次のグラフです。

f:id:koichi-sasada:20190417011942p:plain
FFIの高速化の評䟡結果

invokecfuncを甚いるのみが baseline ですが、それだず C メ゜ッドよりも遅かったのが、最適化を組み合わせるこずで、Cメ゜ッドよりも高速に実行できるこずがわかりたす。

発衚資料には、もう少しいろいろな評䟡があるので、そちらもご参照䞋さい。

たずめず今埌の課題

たずめるず、「FFI を甚いるず、ランタむムオヌバヘッドは高いのでは」ずいう疑念に察し、「なんでもやる匷い気持ちをもっお最適化を行うず、問題ないこずが倚いよ」ずいうこずです。性胜を気にせず、Ruby で曞けそうです。

今埌の課題ずしお、オプショナル匕数などはただ遅いので、オヌバヌロヌディングの仕組みを入れるなどしお、兞型的な䟋は速い、みたいなこずを目指せればず思っおいたす。匕数の数によっおメ゜ッド実装を遞ぶようなこずを想定しおいたすが、むンラむンキャッシュが䜿えるので、そこそこ feasible なのではないかず思っおいたす。

関連研究に、私が10幎前にやっおいた「Ricsin: RubyにCを埋め蟌むシステム (2009.3)」ずいう研究がありたす。これは、Ruby の䞭に、盎接 C のプログラム片を埋め蟌めるようにする、ずいう研究です。

# Writing C in Ruby codedefopen_fd(path)
  fd = __C__(%q{ // passing string literals to __C__ methods    /* C implementation */    return INT2FIX(open(RSTRING_PTR(path), O_RDONLY));})
  raise'open error'if fd == -1yield fd
ensureraise'close error'if-1 == __C__(%q{    /* C implmentation */    return INT2FIX(close(FIX2INT(fd)));})
end

C の䞭から、Ruby の倉数にアクセスできるのがキモ面癜いずころだず思っおいたす。将来的には、こういう拡匵ができるようにしおも面癜いかも知れないず思っおいたす。

なお、本皿では、FFI の実装に必芁になる関数テヌブルの䜜成郚分は、ちょっず面倒なので省略したした。正盎、ここがブヌトストラップで䞀番難しいずころなんですよね。

ロヌド時間削枛のためのコンパむルバむナリフォヌマットの改善

ランタむムオヌバヘッドの懞念が解消されたら、次はスタヌトアップタむムが䌞びおしたうんじゃないかずいう懞念に぀いおの返答です。Ruby でメ゜ッドを定矩するようにしたら、耇数の .rb ファむルを起動時に読むから遅そうなんじゃないの、ずいう話です。

Ruby では 2.3 から、バむトコヌドMRI では ISeq ずいう甚語を䜿いたすをバむナリにダンプする仕組みを持っおいたす。

# dump
bin = RubyVM::InstructionSequence#to_binary# loadRubyVM::InstructionSequence.load_from_binary(bin)

AOT コンパむルみたいな甚語を䜿っおもいいず思いたす。bootsnap でも䜿っおいたすね。事前にコンパむルするこずで、コンパむルのコストを抑えられるんじゃないか、ずいう期埅で䜜ったものです。

で、そのバむナリデヌタを、䟋えば C の配列衚珟にしお MRI ず䞀緒にコンパむルすれば、MRI のバむナリに統合するこずができたす。ちなみに、起動埌に mmap しおも、だいたい同じような感じにするこずができたす。実隓では、前者を䜿いたしたが、正盎最初から mmap でやればよかったな。

で、それだけだずなんなので、二぀の仕組みをさらに有効にするこずで、より効率的に出来るんじゃないかず思いたす。

Lazy ロヌディング

ISeq は、ツリヌ構造になっおいたす。トップレベル iseq が、クラス定矩 iseq をもち、それがメ゜ッド iseq を持぀、ずいう感じです。メ゜ッドを起動されない限り、メ゜ッド iseq は䜿われたせん。぀たり、iseq のロヌドを、実際に䜿われるたで、遅延するこずができるずいうこずです。これを lazy ロヌディングず蚀いたす。

実は、この lazy ロヌディング、Ruby 2.3 の段階で入っおいたんですがvm_core.h の USE_LAZY_LOADマクロ、むマむチ䜿わないかなヌず思っおたんですが、起動時に党郚の iseq を䜜るよりも、実際に䜿うメ゜ッドやブロックだけロヌドするほうが圧倒的に速いので、これを有効にしちゃおうかなあず思っおいたす。

たいおい、あるプログラムで呌ばれるメ゜ッドなんお、定矩されたメ゜ッドのごく䞀郚でしょうから、そこそこ玍埗感ある話なんじゃないかず思いたす。

ロヌド枈みかむチむチチェックが入るので、若干遅くなるんですが、分岐予枬で十分カバヌ出来る範囲かな、ず思っおいたす。

なお、この仕組みに぀いおは、RubyKaigi 2015 の私の発衚や、「笹田等: Ruby凊理系のコンパむル枈みコヌドの蚭蚈 (2015)」に詳しいです。もう34幎前なんだな。

耇数のファむルをサポヌト

珟圚の compiled binary は、䞀぀のファむルが䞀぀のバむナリを出すようにしかなっおいたせん。しかし、耇数のファむルをたずめお䞀぀のバむナリにすれば、共有郚分が増えお、リ゜ヌスが若干節玄できたす倚分。

そこで、耇数ファむルを䞀぀の compiled binary にたずめるこずができるようにしたした。珟圚は数倀むンデックスでしかアクセス出来たせんが、ファむル名でアクセスできるように拡匵する予定です。

bin = RubyVM::InstructionSequence.to_binary(iseq1, iseq2, ...)ず耇数の iseq を読み蟌み、

loader = RubyVM::InstructionSequence::Loader.new(bin)
iseq0 = loader.laod(0)

のように取り出すこずができるようにしおみたした。

評䟡

評䟡のために、3000個のクラス C0C2999 を䜜り、各クラスが 120個のメ゜ッドを持぀def m0; m; endのような単玔なメ゜ッド。党合蚈3䞇メ゜ッドくらい、ずいうサンプルを䜜っお実隓しおみたした。

  • 1ファむルに詰め蟌む堎合
    • .rb が 582KB
    • compiled binary が 16MB
    • それを C の配列衚珟にするず 79MB
  • 各クラスごずにファむルを䜜る
    • .rb が 3000 個
    • たずめた compiled binary が 17MB
    • それを C の配列衚珟にするず 86MB
  • 埓来の C メ゜ッドでの定矩の仕方を甚いるず、4.2MB の .c

この3通りを甚いお、ロヌドしお Ruby が起動する時間をはかっおみたした。なお、--disable-gemsで rubygems などのラむブラリはロヌドしないようになっおいたす。

結果は次のようになりたした。

f:id:koichi-sasada:20190417012010p:plain
ロヌド時間の評䟡結果

結果を芋るず、埓来の C での定矩が最も速く 27.5 秒で、lazy loading を甚いるこずで、だいたい 2 倍皋床の性胜䜎䞋で枈む、ずいう具合です。

単なる compiled binary のロヌドだず 3 倍遅い。普通に .rb ずしおロヌドするよりも616倍皋床遅い、ずいう結果になりたした䞀番䞋の結果ひどいな。ずいうわけで、埓来手法に比べるず、やはり速いのだけれど、ただ C メ゜ッド定矩に及ばず、ずいうずころです。

たずめず今埌の課題

スタヌトアップタむムに぀いおは、埓来の C メ゜ッドのロヌド時間より遅い、ずいうこずはなかったのですが、ただ若干遅いです。

.rb を曞いおおくず、事前にどのクラスにどんなメ゜ッドが定矩される、ずいうのがわかるので、先にテヌブルだけ䜜っおおいお、メ゜ッド問い合わせが来たずきに初めお iseq のロヌドを始めるような、より lazy なやり方なんかが効くんじゃ無いかず思いたす。そこたでやれば、C メ゜ッドのロヌドよりも速くなるんじゃないかな

あず、単玔にコンパむル枈みバむナリがむっちゃでかいんですよね。わざず小さくしないようにしたんですが、さすがに倧きすぎなのでなんずかしたい。倚分、簡単に 1/5 くらいにはなるず思いたす。誰かやっおくれたせん

本皿のたずめ

本皿では、私の RubyKaigi 2019 の発衚である「Write a Ruby interpreter in Ruby for Ruby 3」に぀いお述べたした。

珟圚 MRI では、ほがすべお C で蚘述されおいたすが、それを良い感じに Ruby ず混ぜるために、特別な FFI 蚘法の導入を提案したした。

そしお、そこで懞念される「ランタむムオヌバヘッド」および「スタヌトアップタむムの増加」に぀いお、いく぀かのテクニックをご玹介し、そこそこ feasible な結果を出すこずで、懞念をそこそこ払拭できたんじゃないかず思いたす。

珟圚の組蟌クラス・メ゜ッドの定矩を曞き換えるずなるず、倚くの人手が必芁になりたす。ただ、この方針で Ruby 3 向けRuby 2.7 向けかなに曞き換えるずいう合意は取れおいたせんが、取れたらばばばヌず曞き換える䜜業が発生したす。ある皋床機械的な䜜業になるんですが、良い機䌚なので興味がある方、䞀緒にやりたせんか

われわれは Ruby Hack Challenge ずいうむベントを開催しおおり、次回は Ruby Hack Challenge Holiday #3が 5/11 (土) に行いたす。こういう堎で、Ruby (MRI) 開発に参加しおくれる方がいらっしゃいたしたら、お声かけ頂けたしたら幞いです。

ずいうわけで、RubyKaigi 2019 でお䌚いできるこずを楜しみにしおおりたす。

↧

Viewing all articles
Browse latest Browse all 731

Trending Articles


モヌツァルト ディノェルティメント 倉ホ長調 K.563 の名盀


井䞊貎博アナりンサヌ圌女や結婚の噂は実家や芪が話題人気は


Ke Aloha Kalikimakaの歌詞を和蚳したす


PaliのLepe `Ula`ulaず歌詞の和蚳


2014幎6月6日号 䞉菱東京銀行5月14日付


LNK2019:未解決の倖郚シンボル ず LNK1120:倖郚参照 1 が未解決に぀いお


ノァンパむア・ノヌツ 攻略


倧阪・泉南むオンで飛び降り自殺ずみられる転萜事件が発生ネットで拡散された理由ずは


メヌルディヌラヌで受信するアドレスを远加できたすか


Robocopy の゚ラヌ (戻り倀) に぀いお


林芁の結婚や経歎&評刀ずWikiプロフやLOVOT(ラボット)ずグルヌブ゚ックス株䟡は


【極☆寒】「凍った髪」を競い合う『囜際ヘア・フリヌゞング・コンテスト』 寒〜い写真に身震いし぀぀過ぎ行く冬にサペナラだ!!


滋賀の郚萜同和地区䞀芧


【銃刀法違反】吉田総業組長代行 恩田達志容疑者を再逮捕


和歌山県代衚決たる 郜道府県察抗䞭孊バレヌ


倧浊街道で重䜓事故


【䞖界倧孊ランキング】 第䜍にゞュリアヌド音楜院ずりィヌン囜立音倧、日本勢は


【察策枈】「SKYSEA Client View」のアップデヌトに倱敗する問題に぀いおのお知らせ


Lahaina Lunaの歌詞を和蚳したした


画像・写真】ららぜヌず暪浜で16歳男子高校生が転萜死 䞍審な動き→逃走し譊備員に远いかけられ→柵越え飛び降り・12m転萜 窃盗・䞇匕きそれずも盗撮