読者です 読者をやめる 読者になる 読者になる

観察日記 2011-07-15

%ruby

Mac上でのベンチマーク結果速報

http://www.atdot.net/sp/readonly/nfbnnl_kosaki0
Mac上でのベンチマーク結果速報
これはえーと
一番下だけ見ればいいのか
はい
基本的には、若干悪化している、と。
稀に速くなってるのもあるな。
vm_thread_mutex3 はなんぞ
あと、vm3_clearmethodcache もなんぞ
cleanmethodcacheはささださんがメソッドキャッシュをごそっと変えた影響
vm_thread_mutex3は1000スレッドが1つのmutexを奪い合うベンチ
遅いっつってもじゅーぶん許せる範囲だと思いますです。
vm_thread_mutex3hは皆さんの努力の成果か。
ですす
ほとんどのベンチはシングルスレッドなので、そのへんだけが193の成果
...
短すぎて測定結果が無意味になってたベンチ全部ループ回数ふやしたった
これはヒドイ
{znz_v} biff: [ruby-changes:20308] kosaki:r32356 (trunk): * benchmark/bm_app_erb.rb: increase loop count. too short - http://mla.n-z.jp/?ruby-changes=20308

Linuxでの結果

app_answer はジョークベンチマークなので
消した方がいいかもしれません
スレッド2つの時に遅いのはlazy timer threadの影響があるかもしれないので、調べよう
app_answerは消したい。あれで性能負けると腹がたつけど、ベンチのソースコード読むと直し用がないという結論になって二重に腹がたつという
vm_thread_create_join が性能落ちてるのがあんまり身に覚えないんだけど、ささださん何か思いつきます?
Linuxでの結果もでたようだ
paste>
{ko1_ndk} http://www.atdot.net/sp/readonly/39pnnl_kosaki0
如実に悪化してるなぁ
困りますなぁ
うーん、thread_mutex2が遅いのは、lazy timer threadと gvl_yield が大変相性が悪いという結論になりつつある
観測事実としてはcontext switchがやたら増えているのと、ruby-192でCPU 99%使用がtrunkは150%
おおベンチマーク
なんか本当にすごい 1.9.3 遅いね
vm1_rescue* 0.111 -0.193
マイナス
この結果、もうちょっと見やすくならんもんかね
vm3_clearmethodcache 4.957 1.159
vm3_gc 2.176 5.464
それは whileloop1 の結果を引くという設計なので、値が小さくなりすぎると誤差で余裕にマイナスに突入する
この辺は興味深い
vm3_gcはnari3にみてってさっき@した
loop_whileloop がこんなに遅くなってるとか
column -tで
インデントもなんだけど、目で数値比較したくない
比率を自動計算ってできそうだよねえ
しかしこの速度低下は原因わからない限り blocker と呼びたいレベルだな
特にどれを問題にしています?
全体的にもっさりしてるの
目で数値比較した印象だから本当に全体的に遅くなっているのかはよくわからない
最初の方に遅くなってるのが多いだけ?
いや、全体的に遅い
原因を予想しよう
わたしもコミットするときは、自分の変更前後しか比較してなかったから気づいてなかった
1. GC
シングルスレッドでも遅いのはGVLやタイマースレッドは無罪っぽい
thread_mutex2のつづき。gvl_acquireからのrb_thread_wakeup_timer_thread() でタイマースレッドが起こされまくってるのは確定。timer_thread_functionはエライ数呼ばれてる。gvl_yieldがそれほど呼ばれてないのはmain threadが拾えないぐらいinterrupt_flag立てまくってるから。あかん、これはなおそう
速度劣化はこっちでも再現するっぽいなあ
まだぜんぜん途中だけど
vm_thread_mutex3 84.002 2.766
http://www.atdot.net/sp/readonly/kgtnnl
うちでの結果
やっぱり全般的に193が遅いな
strace したら write(4, "!", 1) とかでてるのはタイマースレッドかしら
シグナルうけたときと、GVL待ちスレッドが0から1に変化したときにwriteしてます
ですよねー
なにい再現しなくなった
ん? > 再現
全く何も変えていないけれど再現しなくなった
benchmark/bm_app_mandelbrot.rb を直接実行してみてるんだけど。
速度低下が? それともあたらしいバグ?
速度低下が。
そりゃ、不思議だ
benchmark/bm_app_mandelbrot.rb 以外では再現するやつもあるのかな
再 make benchmark 中
http://www.atdot.net/sp/readonly/5qunnl
そんなに顕著な差は見て取れなくなった、ような気もする
なんかx86_64のほうが差がでかい気がする
io_file_read は確実に遅くなっている気がする
あれじゃない。do_selectでrb_fdset_t対応されたなかったのを直したやつ。あれで毎回mallocするようになってしまったので・・・
最適化パッチつくるか
max = 200_000; len = 1000 を
max = 20_000; len = 10000 に変えると trunk の方がだいぶ速くなった
どういうことだろう
^^;;;;
maxを減らすと速いというのは、やっぱりreadそのものが遅いんだよな
lenはstring操作にからんでくる部分だから、だれかがstringを最適化した
io の前処理や後処理が遅くなって、読み込み部分が速くなった
blocking_region とか関係ないよね
ある
gvl_acquireがいままで、pthread_mutex_lockだったのが、mutex_lock, unlockの二手順になり、gvl_releaseも同じ
なので、gvl を取ったり離したりを繰り返すIO系ベンチはすこしは負けるのは予想できた
でも、readとwriteで落ち方が同じじゃないように見えるので
もうちょっと考える
write は別に影響なさ気ですね
いやいやいや、ちがう。おれはパッチ作ったときに直前のコミットと性能比較したんだった。ruby-dev:43465 の添付を見るとreadもwriteもちょっぴり落ちる程度の数値になってる

原因は rubygems

原因は rubygems のようです
$ time ./ruby --disable-gems benchmark/bm_io_file_read.rb
real 0m4.069s
$ time ./ruby benchmark/bm_io_file_read.rb
real 0m4.970s
rubygems が余計な (かどうかはしらんけど) Array をいっぱい作ってるようで
そのせいで GC が遅くなってる。
$ ./ruby --disable-gems -e 'GC.start; p ObjectSpace.count_objects[:T_ARRAY]'
18
$ ./ruby -e 'GC.start; p ObjectSpace.count_objects[:T_ARRAY]'
597
こういうときにオブジェクトの生成元知りたいな
知りたいっすねー
r27016
{unak_away} http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=27016
これのせいで attr ごとに配列ができるようになっちゃってる
これで 597 -> 527 になった
これを消したら
とりあえずこの ary は生でみえたらまずい予感がする
いろいろ変わってるけど vm_method.c の変更が重要
再測定してるけど、--disable-gemsつけたら192とtrunkはだいたい互角の性能っぽい
しかし、よく気づけましたね。そんけー
GC::Profiler さんのおかげ
1. GC と予言したとおりではあった
でも rubygems の人たちに配列やハッシュを保持すんなって言っても聞かないだろうな
ああ、1.9.2 のときは gem_prelude があったからか
preludeなくても性能に影響ないって言ったじゃん。あれ、いわなかったかも
Array が原因かはわからないけどオブジェクト数が倍増してるもんな
世代別 GC できてない以上、マイクロベンチマークにはクリティカルに影響しそうだ
マイクロベンチマーク以外に影響ないといいきれるような数字じゃないと思うんだが
1.9.2 でも rubygems 使ってる場合はこんなもんだった
ということになるんだと思う
ああ、どうせ本番ではgemつかうでしょ?って事
つまりぼくのような ProjectEuler する人とかが困るわけだ
こまるぞ!
声をあげるべきです
ProjectEuler 用のライブラリを gem にまとめようとしていたところで悲しい
gem を C で書き直すんだ
rubygems を C で書き直すんだ
戦う相手が Ryan になりそうだしなあ

そしてGC

GC 側でなんとかしろよ、というのが正しいとはぼくも思う
世代別 GC 導入しかないと思うが
そしてそれには全拡張ライブラリでの対応が必要
Ruby おわた
オワタ
拡張ライブラリがつらいよなぁ
やっぱり世代別 GC があれば解決できるんだ
世代別 GC 対応すれば並列マーキングも可能になるので
G1GCをぱくろう
Ruby の未来を考えると全拡張ライブラリを一旦捨てる選択肢もまじめに考えるべきなのかもしれない
互換性ぶっ壊すのはいいんだけど、
世代別と今みたいな拡張ライブラリって併存できるの?
メンテナンスされてない拡張ライブラリは切り捨てて良いと思いますよ
VALUE がインデックスなら、VALUE を特殊な使い方していなければ大丈夫なんじゃなかったっけ
あぁ、そうか
今みたいなって?
ポインタそのまま外に持ってける
世代別じゃなくてコピー/コンパクションだ
うーん
参照はできるかもしれんけど書き換えは多分ダメ
オブジェクトの mark 先が変わるような変更をした時に
具体的には RARRAY_PTR(ary)[idx] = elem; とか
変更したよーってことを GC に教えてあげるようにしないといけない
ああ、VALUE が途中で変わるかって心配か
いぇっさ
未対応の拡張ライブラリにオブジェクトを渡すと汚染されるフラグとか
未対応の拡張ライブラリに渡ったかどうか分かるのかな
未対応というか、まず対応してる拡張ライブラリはどう振る舞えばいいの
さっき言ったようにライトバリアを実装する
で、インデクスなら大丈夫ってはなしか
くらいで済まないかなあ。
汚染されたオブジェクトから参照されるオブジェクトも一気に汚染させることになる
あとグローバルに参照できるオブジェクトも
たぶんほとんど汚染
ポインタのママだと入れたVALUEの先が別の場所に行ったらダメに
VALUE をインデックスにしたら、全体的に遅くなると思うのだけど、どのくらい遅くなるのか気になる
インデックスにしなくてもいいと思うよ
移動させなければいい。性能向上の量は減るけど
でも RObject にポインタ 1 つか 2 つもたせないとダメだったかも
移動させる前提でどうしたらいいかって言う話だったので(わたしは)
移動させたいか
いや、わたしは関わりたくない
とかいってしまう
ぼくも関わりたくない
Ruby おわた
現実論で言えば移動しないのが妥当なのはまぁわかりきってて、
もとい nari さんのそうけんにかかっている
ぼくも移動させるもんだと思ってた
そうすると比較的夢のない泥臭い話になるので、ますます関わりたくない
がらっと変わるなら興味がないわけでもない、とかそういう感じ
slap で実験しよう
GC なんて元々泥臭いと思う
agree
遅いと文句は言われるが速いと褒められることは滅多に無い
関わる人の気がしれない (ぉ
作ったオブジェクトが例えばRARRY_PTR(hoge)[n]とかに入ったかどうかが分からないと、どうしても速くなるきがしない
だから hoge が変更されたことを知ったら
hoge を変更したことと GC に通知したら
preludeフェーズが終わったところで一度GCかけて、そこで生き残ったやつらはずっとmarkしっぱなしとかにするとか
GChoge の先をチェックしなおしてくれる
古い世代のオブジェクトから参照される新しい世代のオブジェクトは強制的に古い世代になったりする
ていうか、RubyのVALUEの先ってサイズ決まってるんだから、
コンパクションは必要ない (完
RVALUEといえ
いやいや
スロットが回収できるのとできないのの大きな違いはある
Ruby では heap というんだっけ
コンパクションするなら VALUE はインデックスになるね
何か手はないかねえ
たしかに
JNIだとどうしてんだっけ
でも、インデックスにするにしても、コンパクションのアルゴリズムは難しいだろうなぁ
コピー GC ならコピーするだけだから原理的には単純だよ
実際の実装がどのくらい難しいかはしらん
Javaのオブジェクトをそのまま見れるわけじゃない、まぁそうだな
コピーしてアドレスが変わったところ全部書き換えないと行けないんじゃない?
って前提読めてなかった
つめるだけ?いや、インデックス詰めないと行けないような
GC本読もう
インデクスとかどう実装するんだろう
hash みたいになるんかな
だとおもった
スーパー遅そうだな
僕のイメージでは、固定サイズスロット内のインデックスを持たせて、コンパクションするときは同じインデックスで空いている場所に移動する事を考えていた
それだとフラグメンテーション解決しなさそうだから
コピー GC する意味が減りそうだが
そう、フラグメンテーションの解決がとても難しそう
どのくらい減るかはしらない
実際に作って評価しまくるしかないね
いよいよやりたくない。
給料出るならやる
300 円払うから 3 日でたのむ
><
711のがたかい
時給1000円として、
3日で72時間か
1 時間でたのむ
この店で一番いいGCをたのむ
tweet いじってたらわけわからない @nari3 次第になった
複数またぐtweetはしたら負けだと思ってる
うん。負けた
http://www.fireproject.jp/feature/jni/class-object/reference.html
JVMはネイティブコードに渡した参照に関する情報をテーブルに保持する.これにより,JVMは「ネイティブコードでこの参照が使用されているからGCのときに注意しなければならない(削除や移動をしてはいけない)」ことがわかる」
めんどくせぇ
そういうことは可能なのだな
まあでも、コア部分だけでも十分
VALUE が変わりうるなんてのには耐えられないと思う
我々が。
でも変わるのってGCまたいだとこだけだから
どこだっけ
VALUE str=rb_str_new(); VALUE ary=rb_ary_new() /* ここでGC! */; rb_p(str) //=> SEGV
しねる
Java のコアはどうやって書かれてるんだ?
コアってJVM?らいぶらり?
JVM
C++っていってたような
上のような現象が発生するとしたらまともにプログラム書けなさそう
だから Java はほとんど Java でかいてる面もあるのかな
なのかなぁ
strはテーブル登録されてて動かせずにSEGVしないんじゃね?
いつテーブル登録解除されるんだろう
だとすると、ほぼ全てテーブル登録されてる気がする
外に抜けたら?
大変ですなあ
returnしたら解除されるが
RubyはOb(ry
return したら、とか C++ でできるだろうか
解除する関数を明示的に呼ぶんじゃなかろうか
そして解除漏れ
解除漏れしても死にはしないかな
事実上のメモリリークだよな
呼ぶ側が、テーブル作成、呼び出し、削除 をやっていると思われる。
外部ライブラリを呼ぶ部分はね
さっきの str はコア内部の話
内部でも同様にするのかな
vm_call_hogeあたりが
内部はどうするんだろなぁ?
ただ、スタックに乗ってるVALUEかどうかわかるきがするけど
まぁそうか
http://d.hatena.ne.jp/spider-man/20080309/p1
とりあえずString#equalsはJavaでかかれているようだ
http://blog.goo.ne.jp/muraokasemi/e/bdd3472b362941971ce13f6cd1eab3f7
ふむ
頭がふっと―してきた
Java は相当なところまで Java で書かれてるよね
安易に「C 化して高速化」なんて考えなくなるのでいい選択と言えるかもしれない
結論: やっぱり時代はJRuby
Java ってどうなるんだろう
一応ちゃんと投資するんじゃないですかねぇ、さすがに
まぁ、しかし、コピーGCやコンパクションは拡張ライブラリ以前に、
俺らが死ぬという知見を得た
結論: Ruby に未来はない
IronRubyがやってくれる・・・!
IronRubyJRuby 以上に終わってなかったっけ
一応開発続いてるよ
別に JRuby は終わってないが
少なくとも数日に1通ペースくらいでメールも流れているようだ

YARVの高速化

YARVバイトコードをもっとアグレッシブに最適化させたいなぁ
既に用意されている最適化オプションを動くようにメンテするとこから
なにが効いて何が効いてないんだろ
see vm_opts.h
末尾呼び出し最適化が0だ
まぁ、半分ジョークですしおすし
末尾 Proc#call も最適化したいですね
とりあえず、実行したいプログラムによって特化命令を変えて、
専用のYARVで動かすといいんじゃないですかね!
末尾最適化は set_trace_func とかあるからダメ
opt_helloからはじめよう
opt_eular_1から
それだ!
set_trace_funcがあるとなぜダメなのか
常にCとほぼ同速度でる
def foo; set_trace_func; end
としたときに foo の return を取れない
trace 呼び出しがはさまるから末尾にならない
あとバックトレースも読みにくくなるよ
Scheme のバックトレースはいつも読めない
まぁ、そこは、C で omit-frame-pointer するのと一緒ですし
そのときは-O0で
最適化部分にバグがあって泣く
それはよくあること
それなら Ruby 的にはデフォルト -O0 だろう
Rails なら容赦なく -O6 くらいで動かそうとして沢山バグレポート出してくれそうだ
そういえばlink time optimizationでぶっこわれてたな
-O6がどの辺りか分からないけど、動作保証しなければリリースには問題ないw
Rails って RubyVM::InstructionSequence.compile_option= とかいじってる?
さすがにそこは・・・どうだろう
さすがにやってないでしょうね
容赦ある
本当にやってないかしらんけど
そもそもいじって効果があるんかしらん
OPT_INSTRUCTIONS_UNIFICATION とかはやくなるようなうごかないような
Railsで作られるバイトコードで統計とって、
特か命令やoperands/insns unificationを整備すればだいぶ
Railsじゃなくてeularでやれと、そうですね