# $Id: SProfiler.rb,v 1.1 2001/08/27 11:00:35 matju Exp $
#
#	MetaRuby's Statistical Time-Consumption Profiler
#	Copyright 2001 by Mathieu Bouchard
#	under the same license as Ruby itself.
#

# Statistical Time-Consumption Profiler
# An alternative to Ruby's profile.rb
#   does not use set_trace_func().
#   approximates the real thing by taking stack snapshots.
#   may be more accurate
#     (profile.rb widens the C/Ruby speed gap while measuring)

class CallStats
	CallStatsEntry = Struct.new(:method,:time,:time_nest)

	def initialize
		@table = {}
	end

	def eat_stack(stack)
		stack.each_with_index {|frame,i|
			next if i==0
			method = File.basename(frame[0..frame.index(?:)])
			pos = frame.rindex(?`)
			method << frame[pos+1..-2] if pos
			e = (@table[method] ||= CallStatsEntry.new(method,0,0))
			e.time      += 1 if i==1
			e.time_nest += 1
		}
	end

	def print_top_methods_to(stream)
		column = :time_nest
		#column = :time
		ks = @table.keys.sort {|a,b|
			@table[b].send(column) <=> @table[a].send(column)
		}
		i=0
		ks.each {|k|
			v = @table[k]
			stream.printf "%40s %7d %7d\n", v.method, v.time, v.time_nest
			i+=1
			break if i>=32
		}
	end
end

foo = CallStats.new
foo.eat_stack proc{caller}.call

parent = $$
m=0
trap(12) {
	if m<1; m+=1; foo.eat_stack caller; m-=1; end
}
fork {|pid|
	while true
		begin Process.kill(12,parent) rescue exit end
		sleep .01
	end
}
END {
	STDERR.puts; foo.print_top_methods_to(STDERR)
}
