以前書いた(というかまだ書いている)キャッシュについてあまりにも何も知らなすぎたのでゼロから調べ直す を下敷きにして、実際に動作を見てキャッシュがどう使われていてどうパフォーマンスに影響しているのかを調べ、たのですが、結局まったくわからなかった、という話です。
「MJIT の invokesuper 遅い問題」と私が勝手に呼んでいる問題があります。 (というかありました。詳しくは後述)
以前書いた(というかまだ書いている)キャッシュについてあまりにも何も知らなすぎたのでゼロから調べ直す を下敷きにして、実際に動作を見てキャッシュがどう使われていてどうパフォーマンスに影響しているのかを調べ、たのですが、結局まったくわからなかった、という話です。
「MJIT の invokesuper 遅い問題」と私が勝手に呼んでいる問題があります。 (というかありました。詳しくは後述)
題名の通り、私がコンピュータの「キャッシュ」というものについてあまりにも知識不足なため、 ここらで基礎の基礎から調べ直してみて、その結果をまとめるつもりのものです。 たぶんこのテーマだと終わりはないような気がするので、気が向いたときに追加修正していくことになると思います。
https://en.oxforddictionaries.com/definition/cache から引用:
- NOUN
| $ cg_annotate cachegrind.diff | |
| -------------------------------------------------------------------------------- | |
| Files compared: cachegrind.out.foo; cachegrind.out.bar | |
| Command: ./miniruby --jit --jit-save-temps --jit-verbose=1 -e lv = 20; class A0; def foo; end; def bar; end; end; i = 0; while i < lv; j = i + 1; eval "class A#{j} < A#{i}; def foo; super; end; def bar; super; end; end"; i += 1; end; a = eval("A#{lv}").new; eval "a.foo; " * 5; RubyVM::MJIT.enabled? && RubyVM::MJIT.pause; n = 20_000; i = n; t0 = Time.now; while i > 0; i -= 1; end; i = n; t1 = Time.now; while i > 0; i -= 1; a.foo; end; t2 = Time.now; sec = (t2 - t1 - (t1 - t0)); p n / sec, sec; ./miniruby --jit --jit-save-temps --jit-verbose=1 -e lv = 20; class A0; def foo; end; def bar; end; end; i = 0; while i < lv; j = i + 1; eval "class A#{j} < A#{i}; def foo; super; end; def bar; super; end; end"; i += 1; end; a = eval("A#{lv}").new; eval "a.foo; " * 5; RubyVM::MJIT.enabled? && RubyVM::MJIT.pause; n = 20_000; i = n; t0 = Time.now; w |
| max = ARGV[0].to_i | |
| if ARGV[1] | |
| require "rbconfig" | |
| step = ARGV[1].to_i | |
| puts "%4s %13s %13s %13s" % ["n", "jit", "nojit", "rate"] | |
| ruby = RbConfig.ruby | |
| IO.popen("#{ruby} --disable-gems #{__FILE__} #{max}", mode: "r+") do |nojit| | |
| IO.popen("#{ruby} --disable-gems --jit --jit-verbose=1 #{__FILE__} #{max}", mode: "r+") do |jit| |
https://gist.github.com/wanabe/66642ae87c52f9bebf3d06a4f8c55b43 の続きで、題名の通りの作業記録です。 だいぶしつこいですがまたやります。 例によって例のごとくまったく未完成で書きながら作業しているので、いつ終わるのか何か成果が出るのかわかりません。
CRuby の MJIT は日々進歩しています。 特に、最近 r64094 で追加された "JIT compaction" は MJIT 有効時の Rails の速度改善にかなり効果が高いようです。
2018/07/13 の ruby r63959 現在、MJIT からローカルスタックがなくなっているので、これを復活させたかったのだけどうまく行かなかった、という作業の記録です。 今回は珍しく作業は終えていてあとは文章にまとめるだけになっています。
書き始め当初は、時系列に作業記録を書こうと思っていたのですが、作業当時にメモをつけておらず、作業を再現するだけならできるだろうと思っていたのですが全然できなかったので、「作業記録」というより「作業内容」=「やったこと一覧」になっています。すみませんすみません。
やっぱり作業時にはリアルタイムにメモをとらんといかんと思います。
| diff --git a/mjit.c b/mjit.c | |
| index e166a066bf..75dc984ab1 100644 | |
| --- a/mjit.c | |
| +++ b/mjit.c | |
| @@ -1290,9 +1290,16 @@ init_header_filename(void) | |
| const size_t libpathflag_len = sizeof(libpathflag) - 1; | |
| #endif | |
| - basedir_val = ruby_prefix_path; | |
| - basedir = StringValuePtr(basedir_val); |
| $ RBENV=""; for C in `seq 1 1 5`; do RBENV="$RBENV trunk:C=$C" && for BRANCH in trunk+mjit-same-so trunk+mjit-same-so+mjit-iseq-arg; do RBENV="$RBENV $BRANCH,--jit,--jit-min-calls=5000:C=$C:TRAINING_NUM=5000:WAIT_SEC=1"; done; done; RAILS_ENV=production ruby -W0 -S bundle exec rake bench RBENV="$RBENV" DURATION=10|tee bench.log | |
| Booting: production | |
| Endpoint: "/" | |
| Warming up -------------------------------------- | |
| bench 998.910 i/s | |
| Calculating ------------------------------------- | |
| trunk:C=1 trunk+mjit-same-so,--jit,--jit-min-calls=5000:C=1:TRAINING_NUM=5000:WAIT_SEC=1 trunk+mjit-same-so+mjit-iseq-arg,--jit,--jit-min-calls=5000:C=1:TRAINING_NUM=5000:WAIT_SEC=1 trunk:C=2 trunk+mjit-same-so,--jit,--jit-min-calls=5000:C=2:TRAINING_NUM=5000:WAIT_SEC=1 trunk+mjit-same-so+mjit-iseq-arg,--jit,--jit-min-calls=5000:C=2:TRAINING_NUM=5000:WAIT_SEC=1 trunk:C=3 trunk+mjit-same-so,--jit,--jit-min-calls=5000:C=3:TRAINING_NUM=5000:WAIT_SEC=1 trunk+mjit-same-so+mjit-iseq-arg,--jit, |
| $ RBENV=""; for C in `ruby -e '10.times {|i| p 2**i}'`; do RBENV="$RBENV trunk+mjit-same-so-mod,--jit,--jit-min-calls=6000,--jit-batch-size=$C:TRAINING_NUM=6000:WAIT_SEC=100:V=1"; done && RAILS_ENV=production ruby -W0 -S bundle exec rake bench RBENV="$RBENV" DURATION=30 | |
| Booting: production | |
| Endpoint: "/" | |
| Warming up -------------------------------------- | |
| 0 bench 5900 | |
| 0 | |
| 506.385 i/s | |
| Calculating ------------------------------------- | |
| trunk+mjit-same-so-mod,--jit,--jit-min-calls=6000,--jit-batch-size=1,TRAINING_NUM=6000,WAIT_SEC=100,V=1 trunk+mjit-same-so-mod,--jit,--jit-min-calls=6000,--jit-batch-size=2,TRAINING_NUM=6000,WAIT_SEC=100,V=1 trunk+mjit-same-so-mod,--jit,--jit-min-calls=6000,--jit-batch-size=4,TRAINING_NUM=6000,WAIT_SEC=100,V=1 trunk+mjit-same-so-mod,--jit,--jit-min-calls=6000,--jit-batch-size=8,TRAINING_NUM=6000,WAIT_SEC=100,V=1 trunk+mjit-same-so-mod,--jit,--jit-mi |
| $ RAILS_ENV=production ruby -W0 -S bundle exec rake bench RBENV="trunk trunk,--jit,--jit-min-calls=3000:TRAINING_NUM=3000:WAIT_SEC=100 trunk+mjit-same-so,--jit,--jit-min-calls=3000:TRAINING_NUM=3000:WAIT_SEC=100" DURATION=10 | |
| Booting: production | |
| Endpoint: "/" | |
| Warming up -------------------------------------- | |
| bench 1.066k i/s | |
| Calculating ------------------------------------- | |
| trunk trunk,--jit,--jit-min-calls=3000,TRAINING_NUM=3000,WAIT_SEC=100 trunk+mjit-same-so,--jit,--jit-min-calls=3000,TRAINING_NUM=3000,WAIT_SEC=100 | |
| bench 1.031k 594.824 795.382 i/s - 10.663k times in 10.343410s 17.926304s 13.406132s | |
| Comparison: |