From: SASADA Koichi Date: 2009-06-11T08:05:56+09:00 Subject: [ruby-dev:38584] [Feature: trunk] ObjectSpace.count_nodes  ささだです.  ObjectSpace.count_objects という,オブジェクトの種類を数えるメソッドが ありますが,同じように ObjectSpace.count_nodes というものを加えるのはど うでしょうか.  いや,使うのは多分 Ruby 開発者だけのような気もするので,正直どうかなぁ とも思うんですが. # slot を全部巡る, st_each みたいなインターフェースがあれば, # 拡張ライブラリとして実装することも不可能じゃなくなる, # けど,コールバックベースだと遅いかもなあ. 利用例:  例えば benchmark/bm_pentomino.rb を実行すると,なんか node が沢山出来 ているのが分かるの (*1) で,なぜだろうかと解析することが出来ます (*2). *1: http://www.atdot.net/fp_store/f.89p1lk/file.g.png X軸が時間,左Y軸がオブジェクト数,右Y軸がGC回数 1秒ごとのサンプリング. node の数が GC 回数に影響していることがわかる *2: http://www.atdot.net/fp_store/f.eio1lk/file.g.png X軸が時間,Y軸が消費量・GC回数 1秒ごとのサンプリング. ほぼ,NODE_LITの生成回数にGC回数が依存していることがわかる. NODE_LIT は,実は break 時にテンポラリオブジェクトとして生成される んだけど,pentomino では break を沢山するので,こういうことになる, ということがわかった. # 余談: # じゃぁ,break の実装を変えれば性能が向上するかというと, # GC の実行時間は1秒中0.1秒くらいなので,1割の性能向上が見込める, # かもしれない. +static VALUE +count_nodes(int argc, VALUE *argv, VALUE os) +{ + rb_objspace_t *objspace = &rb_objspace; + size_t nodes[NODE_LAST]; + size_t i; + VALUE hash; + + if (rb_scan_args(argc, argv, "01", &hash) == 1) { + if (TYPE(hash) != T_HASH) + rb_raise(rb_eTypeError, "non-hash given"); + } + + for (i = 0; i <= NODE_LAST; i++) { + nodes[i] = 0; + } + + for (i = 0; i < heaps_used; i++) { + RVALUE *p, *pend; + + p = heaps[i].slot; pend = p + heaps[i].limit; + for (;p < pend; p++) { + if (p->as.basic.flags && BUILTIN_TYPE(p) == T_NODE) { + nodes[nd_type((NODE *)p)]++; + } + } + } + + if (hash == Qnil) { + hash = rb_hash_new(); + } + else if (!RHASH_EMPTY_P(hash)) { + st_foreach(RHASH_TBL(hash), set_zero, hash); + } + + for (i=0; i