K.Sasada's Home Page

こめんとのついか

こめんとこめんと!

message

please set comment :).

_13(Thu)

Ruby VM アドベントカレンダーの 13 日目です.

昨日は TracePoint の利用例だけ紹介しました.コードを再掲します(といって行を稼ぐ).

def m
  p :hello
  p :world
end

set_trace_func(proc{|event, file, line, id, binding, klass|
  puts "#{file}:#{line} #{id}" if event == 'line'
})

m

#=>
t.rb:10 
t.rb:2 m
:hello
t.rb:3 m
:world

これを TracePoint で書き換えた版は次に.

def m
  p :hello
  p :world
end

trace = TracePoint.trace(:line){|tp|
  puts "#{tp.path}:#{tp.lineno} #{tp.method_id}"
}

m

#=>
t.rb:10 
t.rb:2 m
:hello
t.rb:3 m
:world

トレースを設定しているところは次の箇所ですね.

set_trace_func(proc{|event, file, line, id, binding, klass|
  puts "#{file}:#{line} #{id}" if event == 'line'
})

trace = TracePoint.trace(:line){|tp|
  puts "#{tp.path}:#{tp.lineno} #{tp.method_id}"
}

さて,違いをゆっくり見て行きましょう.

まず,登録のインターフェースに着目してみます.

今回の例ではこの返値である TracePoint オブジェクトは使っていませんが,trace.disable とすることで,このトレースだけ無効にすることができます.ちなみに,こんな感じです.

trace = TracePoint.trace{...}
...
trace.disable # 以降はトレースが無効になる
...

次に,トレースとして渡すブロックを見てみます.

というわけで,大きな違いというか特長は,次の 4 つになります.

さて,昨日言っていた set_trace_func の問題点は解決したでしょうか.チェックしてみましょう.

TracePoint.trace では,引数で :line のように,トレースしたいイベントの種類を指定できるので解決しています.

TracePoint.trace によって得られる TracePoint オブジェクトの TracePoint#disable メソッドによって,このトレースのみを無効に出来ます.

遅い理由はいくつかありました.Proc オブジェクトを呼び出すコストがかかる,というものですが,(1) で興味のないイベントでは Proc オブジェクト呼ばれないので,Proc の起動コストの問題は若干解決しています.また,Binding オブジェクトを必ず作成してしまう,という問題は,tp.binding というメソッドによって Binding オブジェクトの作成を指示するまで作成されないので,これも問題ありません.

実際にためしてみましょう.10万回のトレース付きのメソッド呼び出しです.

require 'benchmark'

def m
  a = 1
  b = a
  a = b
end

max = 100_000

Benchmark.bm{|x|
  x.report{
    set_trace_func(proc{|event, file, line, id, binding, klass|
      if event == 'line'
        # do something
      end
    })
    max.times{m}
    set_trace_func(nil)
  }
  x.report{
    trace = TracePoint.trace(:line){|tp|
      # do something
    }
    max.times{m}
    trace.disable
  }
}

実行結果です.

ruby 2.0.0dev (2012-12-21 trunk 38515) [i386-mswin32_100]
       user     system      total        real
   6.755000   0.016000   6.771000 (  7.176412)
   0.733000   0.000000   0.733000 (  0.775598)

10 倍ほど速くなっています.というか,set_trace_func が遅すぎただけ,という言い方が出来るかもしれません.

新規 API なので,イベントを増やしても怒られません.また,TracePoint.trace では,トレースしたいイベントを指定するようになっているので,意図しないイベントが来て困るようなトレースが書けないようになっています(ちなみに,無引数では全イベントを受け付けるようになっていますが,そこは自己責任で.今後,増える可能性があることを考慮して書いて下さい).こんな感じで,互換性の問題も解決しています.

というわけで,TracePoint では,set_trace_func に含まれていた 4 つの問題を解決していることがわかります.

さて,今日も長くなってしまったので,TracePoint の細かい紹介は明日に回すことにします.

では,今日はこの辺で.


好きにコメントを編集してください。ただし、あまり他の人のコメントを書き換えることは感心しません。



back

tton 記述が使えます。YukiWikiな記述してりゃ問題ありません。

「行頭に#code」 と、「行頭に#end」 で挟むと、その間の行は pre で囲まれます。プログラムのソースを書くときに使ってください。

例:

#code

(なんかプログラム書く)

#end

リンクは

[[なまえ|http://www.example.org]]

とか

[[http://www.example.org]]

で貼れます。

$Date: 2003/04/28 10:27:51 $