Running Multiple Analysis Tools at Once


You want to combine two analysis tools, like the Ruby profiler and the Ruby tracer. But when one tool calls set_trace_func, it overwrites the trace function left by the other.


Change set_trace_func so that it keeps an array of trace functions instead of just one. Heres a library called multitrace.rb that makes it possible:

	# multitrace.rb

	alias :set_single_trace_func :set_trace_func
	def set_trace_func(proc)
	 if (proc == nil)
	 $TRACE_FUNCS << proc

	trace_all = do |event, file, line, symbol, binding, klass|
	 $TRACE_FUNCS.each { |p|, file, line, symbol, binding, klass)}
	set_single_trace_func trace_all

	def unset_trace_func(proc)

Now you can run any number of analysis tools simultaneously. However, when one of the tools stops, they will all stop:

	#!/usr/bin/ruby -w
	# paranoia.rb
	require multitrace
	require profile
	require 	racer

	puts "I feel like Im being watched."

This programs nervousness is well-justified, since its every move is being tracked by the Ruby tracer and timed by the Ruby profiler:

	$ ruby paranoia.rb
	#0:./multitrace.rb:9:Array:<: $TRACE_FUNCS << proc
	#0:./multitrace.rb:11:Object:<: end
	#0:paranoia.rb:9::-: puts "I feel like Im being watched."
	#0:paranoia.rb:9:Kernel:>: puts "I feel like Im being watched."
	 % cumulative self self total
	 time seconds seconds calls ms/call ms/call name
	 0.00 0.00 0.00 1 0.00 0.00 Kernel.require
	 0.00 0.00 0.00 1 0.00 0.00 Fixnum#==
	 0.00 0.00 0.00 1 0.00 0.00 String#scan

Without the include multitrace at the beginning, only the profiler will run: its trace function will override the tracers.


This example illustrates yet again how you can benefit by replacing some built-in part of Ruby. The multitrace library creates a drop-in replacement for set_trace_func that lets you run multiple analyzers at once. You probably don really want to run the tracer and the analyzer simultaneously, since they e both monolithic tools. But if youve written some smaller, more modular analysis tools, you e more likely to want to run more than one during a single run of a program.

The standard way of stopping a tracer is to pass nil into set_trace_func. Our new set_trace_func will accept nil, but it has no way of knowing which trace function you want to stop.[4] It has no choice but to remove all of them. Of course, if you e writing your own trace functions, and you know multitrace will be in place, you don need to pass nil into set_trace_func. You can call unset_trace_func to remove one particular trace function, without stopping the rest.

[4] Well, you could do this by taking a snapshot of the call stack every time set_trace_func was called with a Proc object. When set_trace_func was called with nil, you could look at the call stack at that point (see Recipe 17.6), and only remove the Proc object(s) inserted by the same file. For instance, if a nil call comes in from profiler.rb, you could remove only the Proc object(s) inserted by calls coming from profiler.rb. This is probably not worth the trouble.

See Also

  • The tracer function created in Recipe 17.15, "Whos Calling That Method? A Call Graph Analyzer," is the kind of lightweight analysis tool Id like to see more of: one that it makes sense to run in conjunction with others



Date and Time



Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming


Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration

Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399 © 2008-2020.
If you may any questions please contact us: