Project

General

Profile

Feature #6895

Updated by zzak (zzak _) almost 12 years ago

=begin 
 = Abstract 

 Let's introduce TracePoint API that can replace be replaced with set_trace_func(). 

 = Background 

 See discussions on [Feature #6649] <http://bugs.ruby-lang.org/issues/show/6649>. 

 Problems with of set_trace_func: 

 * Invoke trace funcs on all events (C level API can filter events) 
 * With this spec, we can't add new trace event (compatibility issue) 
 * Slow because it generates binding object each trace func 

 = Proposal Porposal 

 Introduce TracePoint API. 
  
   trace = TracePoint.trace(event1, event2, ...) do |tp| 
     # tp has methods like: 
     #     event: event name represented by Symbol like :line. 
     #            "c-call", "c-return" is :c_call, :c_return (sub('-', '_')) 
     #     file, line: return filename and line number 
     #     klass, id: return class or id (depends on a context. Same as set_trace_func) 
     #     binding: return (generated) binding object 
     #     self: new method.    same as tp.binding.eval('self') 
     ... # trace func 
     # tp is TracePoint object. 
     # In fact, tp is same object as `trace'. 
     # We don't need any object creation on trace func. 
   end 
   ... # Proc are called     1.600000     0.000000     1.600000 (    1.601750) 
    0.280000     0.000000     0.280000 (    0.287466) 
    0.750000     0.000000     0.750000 (    0.741344) 
    1.400000     0.020000     1.420000 (    1.420574) 
   trace.untrace # stop tracing 
   ... 
   trace.retrace # restart tracing 

 `eventN' parameter for TracePoint.trace() is set of symbols.    You can specify events what you want to trace.    If you don't specify any events on it, then all events are activate (similar to set_trace_func). 

 = Implementation 

 See <https://github.com/ko1/ruby/compare/tracepoint>. 

 Try <https://github.com/ko1/ruby/tracepoint>. 

 = Evaluation 

 TracePoint API doesn't make temporary object on default.    It is faster than current set_trace_func. 

   require 'benchmark' 
   MAX = 1_000_000 
   $c1 = $c2 = 0 

   
  
   Benchmark.bm{|x| 
     x.report{ 
       set_trace_func(lambda{|*args| $c1+=1}) 
       MAX.times{ 
         a = 1 
       } 
       set_trace_func(nil) 
     } 
     x.report{ 
       trace = TracePoint.trace(*%i{line call return c_call c_return}){|tp| $c2+=1} 
       MAX.times{ 
         a = 1 
       } 
       trace.disable trace.untrace 
     } 
     x.report{ 
       trace = TracePoint.trace(*%i{line call return c_call c_return}){|tp| $c2+=1; tp.event; tp.self; tp.method_id} tp.klass; tp.id} 
       MAX.times{ 
         a = 1 
       } 
       trace.disable trace.untrace 
     } 
     x.report{ 
       trace = TracePoint.trace(*%i{line call return c_call c_return}){|tp| $c2+=1; tp.event; tp.self; tp.method_id; tp.klass; tp.id; tp.binding} 
       MAX.times{ 
         a = 1 
       } 
       trace.disable trace.untrace 
     } 
   } 
   __END__ 
   #=> 
          user       system        total          real 
    1.140000 1.600000     0.000000     1.140000 1.600000 (    1.145847) 1.601750) 
    0.200000 0.280000     0.000000     0.200000 0.280000 (    0.194970) 0.287466) 
    0.380000 0.750000     0.000000     0.380000 0.750000 (    0.385857) 0.741344) 
    1.250000 1.400000     0.000000 0.020000     1.250000 1.420000 (    1.251083) 1.420574) 

 = Problems 

 * TracePoint.trace(...) is good interface? 
 * Now, noway to specify Thread specific hooks (like Thread#set_trace_func) 

 = Next Step 

 I also want to introduce block enter/leave events on TracePoint. 

 =end 

Back