This page contains automated test results for code from O'Reilly's Ruby Cookbook. If this code looks interesting or useful, you might want to buy the whole book.
| Who's Calling That Method? A Call Graph Analyzer | ||
|---|---|---|
| Code | Expected | Actual |
% cumulative self self total
time seconds seconds calls ms/call ms/call name
12.19 2.74 2.74 4930 0.56 0.77 Array#each
class CallTracker
# Initialize and start the trace.
def initialize(show_stack_depth=1)
@show_stack_depth = show_stack_depth
@to_trace = Hash.new { |h,k| h[k] = {} }
start
at_exit { stop }
end
# Register a class/method combination as being interesting. Subsequent calls
# to the method will be tallied by tally_calls.
def register(klass, method_symbol)
@to_trace[klass][method_symbol] = {}
end
# Tells the Ruby interpreter to call tally_calls whenever it's about to
# do anything interesting.
def start
set_trace_func method(:tally_calls).to_proc
end
# Stops the profiler, and prints a report of the interesting calls made
# while it was running.
def stop(out=$stderr)
set_trace_func nil
report(out)
end
# If the interpreter is about to call a method we find interesting,
# increment the count for that method.
def tally_calls(event, file, line, symbol, binding, klass)
if @to_trace[klass] and @to_trace[klass][symbol] and
(event == 'call' or event =='c-call')
stack = caller
stack = stack[1..(@show_stack_depth ? @show_stack_depth : stack.size)]
@to_trace[klass][symbol][stack] ||= 0
@to_trace[klass][symbol][stack] += 1
end
end
# Prints a report of the lines of code that called interesting
# methods, sorted so that the the most active lines of code show up
# first.
def report(out=$stderr)
first = true
@to_trace.each do |klass, symbols|
symbols.each do |symbol, calls|
total = calls.inject(0) { |sum, ct| sum + ct[1] }
padding = total.to_s.size
separator = (klass.is_a? Class) ? '#' : '.'
plural = (total == 1) ? '' : 's'
stack_join = "\n" + (' ' * (padding+2))
first ? first = false : out.puts
out.puts "#{total} call#{plural} to #{klass}#{separator}#{symbol}"
(calls.sort_by { |caller, times| -times }).each do |caller, times|
out.puts " %#{padding}.d #{caller.join(stack_join)}" % times
end
end
end
end
end
require 'rubygems'
require 'rubyful_soup'
tracker = CallTracker.new
tracker.register(Array, :each)
BeautifulSoup.new(open('test.html') { |f| f.read })
tracker.stop($stdout) |
4930 calls to Array#each 1671 ./rubyful_soup.rb:715:in `pop_to_tag' 1631 ./rubyful_soup.rb:567:in `unknown_starttag' 1627 ./rubyful_soup.rb:751:in `smart_pop' 1 ./rubyful_soup.rb:510:in `feed' |
SyntaxError: compile error
(irb):1: parse error, unexpected tIDENTIFIER, expecting $
% cumulative self self total
^
from (irb):1
SyntaxError: compile error
(irb):2: parse error, unexpected tIDENTIFIER, expecting kDO or '{' or '('
time seconds seconds calls ms/call ms/call name
^
(irb):2: parse error, unexpected tIDENTIFIER, expecting kDO or '{' or '('
time seconds seconds calls ms/call ms/call name
^
from (irb):2
SyntaxError: compile error
(irb):3: parse error, unexpected tFLOAT, expecting $
12.19 2.74 2.74 4930 0.56 0.77 Array#each
^
from (irb):3
9 calls to Array#each
4 /usr/lib/ruby/gems/1.8/gems/rubyful_soup-1.0.4/lib/rubyful_soup.rb:232:in `attrs'
4 /usr/lib/ruby/gems/1.8/gems/rubyful_soup-1.0.4/lib/rubyful_soup.rb:341:in `render_contents'
1 /usr/lib/ruby/gems/1.8/gems/rubyful_soup-1.0.4/lib/rubyful_soup.rb:536:in `feed' |