[#45910] [ruby-trunk - Bug #6694][Open] Thread.new without block. — "ko1 (Koichi Sasada)" <redmine@...>

24 messages 2012/07/04

[#45913] [ruby-trunk - Bug #6698][Open] MacOSXではDir.globが返すファイル名の内容はUTF8-MACですがencodingがUTF-8になっている — "imkira (Mario Freitas)" <imkira@...>

10 messages 2012/07/04

[#45933] [ruby-trunk - Bug #6716][Open] FileUtils.mv でリンク先がないシンボリックリンクファイルを指定すると ENOENT エラーになる — "tommy (Masahiro Tomita)" <tommy@...>

8 messages 2012/07/10

[#45976] [ruby-trunk - Bug #6756][Open] FileUtils.rm_rf がアクセス権のない空ディレクトリを削除しない — "fumiyas (Fumiyasu SATOH)" <fumiyas@...>

9 messages 2012/07/20

[#46012] [ruby-trunk - Feature #6812][Open] Refactor gc.c — "authorNari (Narihiro Nakamura)" <authorNari@...>

13 messages 2012/07/30

[ruby-dev:45912] Plan of set_trace_func

From: SASADA Koichi <ko1@...>
Date: 2012-07-04 08:43:24 UTC
List: ruby-dev #45912
 ささだです.

 最近,[ruby-core:45949] (*1) 関連で trace_func 回りの実装を見ているの
ですが,色々と性能的にいけていない気がするので,メモを書いておきます.

*1: [ruby-core:45949] Re: [ruby-trunk - Feature #6649] Add new
set_trace_func events "b-call", "b-return"

ベンチマーク:
max = 10_000_000
require 'benchmark'
Benchmark.bm{|x|
  x.report{
    max.times{
      a = 1
      b = 2
    }
  }
  set_null_profiler
  x.report{
    max.times{
      a = 1
      b = 2
    }
  }
}

# C code
rb_define_global_function("set_null_profiler", set_null_profiler, 0);

static void
null_func(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE
klass)
{

}

static VALUE
set_null_profiler(VALUE self)
{
    rb_add_event_hook(null_func, RUBY_EVENT_LINE, 0);
    return Qnil;
}

結果:

       user     system      total        real
   4.640000   0.140000   4.780000 (  4.788095)  #0) 何も無し
  10.720000   0.020000  10.740000 ( 10.740693)  #1) null trace あり
   6.810000   0.000000   6.810000 (  6.816267)  #2) n/trace w/o setjmp
   6.260000   0.010000   6.270000 (  6.265966)  #3) w/o exec_event_hooks
   5.430000   0.000000   5.430000 (  5.426709)  #4) w/o thread_exec_e...

※Virtual box 上のてきとーな測定です.


 現在,trace が走るとき,

rb_threadptr_exec_event_hooks()
-> (a) thread_suppress_tracing()
-> (b) thread_exec_event_hooks()
-> (c) hooks の数だけ exec_event_hooks() を繰り返し

の順で実行されます.

 (a) では,trace 中に trace が走らないように,th->tracing フラグを設定
しています.そのために,PUSH_TAG() で実行しています(例外が発生した
ら,th->tracing フラグを元に戻して例外を上に伝搬).

 (b) では,なんかてきとーにフラグをセットして,必要な hook 関数を全部呼
び出しています.これが (c) です.

 例えば,プロファイラでやりそうな「イベントに応じたカウンタを増減する」
という処理をする場合は,再入りなどはしそうにないので,(a) での処理は不要
です.また,(b) の,なんかいろんなフラグの処理も,多分不要です.で,その
辺を全部削って,だいたいこんなふうになるだろうな,と計算したのが (4) に
なります.(4) の場合,そもそも hook 関数を呼んでいないのでフェアじゃない
んですが,まぁ,余計な処理をはぶいたら,だいたいこんなもんじゃないかなぁ
と思っています.何もしない時 (0) よりは,それなりに遅いですが,現状の時
間 (1) は 2 倍以上時間がかかっていますので,それよりはマシになるんじゃな
いかと.

 また,id やら klass やらを,このフローで持ち回っているんですが,実は
cfp を渡してあげて,必要になったらそこから計算する,というようにしたほう
がトータルのコストは低いんじゃないかな,と思っています.

 というわけで,総合しますと,

(1) 再入りしないようにする処理などを省いたワイルドな hook が登録できるよ
うにする
(2) id, klass などは渡さず,cfp を渡して,そこから計算するようにする
(3) 再入りなどをするような過保護な hook を登録できるようにする
    これは,(1) の上に互換性のために作る.
    互換性のため,引数なども従来通り渡される.

てなように,手直ししようと思います.2.0 までに.

 意識の高いプロファイラ・デバッガなどは (1) を使えるようにできるように
しようと思います.

-- 
// SASADA Koichi at atdot dot net


In This Thread

Prev Next