require "erb"
module RubyProf
# Generates graph[link:files/examples/graph_html.html] profile reports as html.
# To use the grap html printer:
#
# result = RubyProf.profile do
# [code to profile]
# end
#
# printer = RubyProf::GraphHtmlPrinter.new(result, 5)
# printer.print(STDOUT, 0)
#
# The constructor takes two arguments. The first is
# a RubyProf::Result object generated from a profiling
# run. The second is the minimum %total (the methods
# total time divided by the overall total time) that
# a method must take for it to be printed out in
# the report. Use this parameter to eliminate methods
# that are not important to the overall profiling results.
class GraphHtmlPrinter
PERCENTAGE_WIDTH = 8
TIME_WIDTH = 10
CALL_WIDTH = 20
# Create a GraphPrinter. Result is a RubyProf::Result
# object generated from a profiling run.
def initialize(result)
@result = result
end
# Print a graph html report to the provided output.
#
# output - Any IO oject, including STDOUT or a file.
# The default value is STDOUT.
#
# min_percent - The minimum %total (the methods
# total time divided by the overall total time) that
# a method must take for it to be printed out in
# the report. Default value is 0.
def print(output = STDOUT, min_percent = 0)
@output = output
@min_percent = min_percent
_erbout = @output
erb = ERB.new(template, nil, nil)
@output << erb.result(binding)
end
# These methods should be private but then ERB doesn't
# work. Turn off RDOC though
#--
def total_time(thread_id)
toplevel = @result.toplevel(thread_id)
total_time = toplevel.total_time
total_time = 0.01 if total_time == 0
return total_time
end
def total_percent(method)
overall_time = self.total_time(method.thread_id)
(method.total_time/overall_time) * 100
end
def self_percent(method)
overall_time = self.total_time(method.thread_id)
(method.self_time/overall_time) * 100
end
# Creates a link to a method. Note that we do not create
# links to methods which are under the min_perecent
# specified by the user, since they will not be
# printed out.
def create_link(thread_id, name)
# Get method
method = @result.threads[thread_id][name]
if self.total_percent(method) < @min_percent
# Just return name
name
else
# Create link
"#{name}"
end
end
def link_name(thread_id, name)\
name.gsub(/[><#\.\?=:]/,"_") + "_" + thread_id.to_s
end
def template
'
<%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Total") %> |
<%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Self") %> |
<%= sprintf("%#{TIME_WIDTH}s", "Total") %> |
<%= sprintf("%#{TIME_WIDTH}s", "Self") %> |
<%= sprintf("%#{TIME_WIDTH+2}s", "Children") %> |
<%= sprintf("%#{CALL_WIDTH}s", "Calls") %> |
Name |
<% methods.sort.reverse.each do |pair| %>
<% name = pair[0] %>
<% method = pair[1] %>
<% method_total_percent = self.total_percent(method) %>
<% next if method_total_percent < @min_percent %>
<% method_self_percent = self.self_percent(method) %>
<% for name, call_info in method.parents %>
|
|
<%= sprintf("%#{TIME_WIDTH}.2f", call_info.total_time) %> |
<%= sprintf("%#{TIME_WIDTH}.2f", call_info.self_time) %> |
<%= sprintf("%#{TIME_WIDTH}.2f", call_info.children_time) %> |
<% called = "#{call_info.called}/#{method.called}" %>
<%= sprintf("%#{CALL_WIDTH}s", called) %> |
<%= create_link(thread_id, name) %> |
<% end %>
<%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", method_total_percent) %> |
<%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", method_self_percent) %> |
<%= sprintf("%#{TIME_WIDTH}.2f", method.total_time) %> |
<%= sprintf("%#{TIME_WIDTH}.2f", method.self_time) %> |
<%= sprintf("%#{TIME_WIDTH}.2f", method.children_time) %> |
<%= sprintf("%#{CALL_WIDTH}i", method.called) %> |
<%= method.name %> |
<% for name, call_info in method.children %>
<% methods = @result.threads[thread_id] %>
<% child = methods[name] %>
|
|
<%= sprintf("%#{TIME_WIDTH}.2f", call_info.total_time) %> |
<%= sprintf("%#{TIME_WIDTH}.2f", call_info.self_time) %> |
<%= sprintf("%#{TIME_WIDTH}.2f", call_info.children_time) %> |
<% called = "#{call_info.called}/#{child.called}" %>
<%= sprintf("%#{CALL_WIDTH}s", called) %> |
<%= create_link(thread_id, name) %> |
<% end %>
|
<% end %>
<% end %>
'
end
end
end