# encoding: utf-8 require 'erb' module RubyProf # Generates graph[link:files/examples/graph_html.html] profile reports as html. # To use the graph html printer: # # result = RubyProf.profile do # [code to profile] # end # # printer = RubyProf::GraphHtmlPrinter.new(result) # printer.print(STDOUT, :min_percent=>0) # # The Graph printer takes the following options in its print methods: # :filename - specify a file to use that contains the ERB # template to use, instead of the built-in self.template # # :template - specify an ERB template to use, instead of the # built-in self.template # class GraphHtmlPrinter < AbstractPrinter include ERB::Util PERCENTAGE_WIDTH = 8 TIME_WIDTH = 10 CALL_WIDTH = 20 def setup_options(options) super(options) filename = options[:filename] template = filename ? File.read(filename).untaint : (options[:template] || self.template) @erb = ERB.new(template, nil, nil) @erb.filename = filename end def print(output = STDOUT, options = {}) @output = output setup_options(options) @output << @erb.result(binding) 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, method) overall_time = thread.total_time total_percent = (method.total_time/overall_time) * 100 if total_percent < min_percent # Just return name h method.full_name else href = '#' + method_href(thread, method) "#{h method.full_name}" end end def method_href(thread, method) h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread.fiber_id.to_s) end def file_link(path, linenum) srcfile = File.expand_path(path) if srcfile =~ /\/ruby_runtime$/ "" else if RUBY_PLATFORM =~ /darwin/ "#{linenum}" else "#{linenum}" end end end def template '

Profile Report

<% if RUBY_VERSION >= "1.9" %> <% end %> <% for thread in @result.threads %> <% if RUBY_VERSION >= "1.9" %> <% end %> <% end %>
Thread IDFiber IDTotal Time
<%= thread.id %><%= thread.fiber_id %> <%= thread.total_time %>
<% for thread in @result.threads methods = thread.methods total_time = thread.total_time %> <% if RUBY_VERSION >= "1.9" %>

Thread <%= thread.id %>, Fiber: <%= thread.fiber_id %>

<% else %>

Thread <%= thread.fiber_id %>

<% end %> <% min_time = @options[:min_time] || (@options[:nonzero] ? 0.005 : nil) methods.sort_by(&sort_method).reverse_each do |method| total_percentage = (method.total_time/total_time) * 100 next if total_percentage < min_percent next if min_time && method.total_time < min_time self_percentage = (method.self_time/total_time) * 100 %> <% for caller in method.aggregate_parents.sort_by(&:total_time) next unless caller.parent next if min_time && caller.total_time < min_time %> <% called = "#{caller.called}/#{method.called}" %> <% end %> <% for callee in method.aggregate_children.sort_by(&:total_time).reverse %> <% next if min_time && callee.total_time < min_time %> <% called = "#{callee.called}/#{callee.target.called}" %> <% end %> <% end %>
<%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Total") %> <%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Self") %> <%= sprintf("%#{TIME_WIDTH}s", "Total") %> <%= sprintf("%#{TIME_WIDTH}s", "Self") %> <%= sprintf("%#{TIME_WIDTH}s", "Wait") %> <%= sprintf("%#{TIME_WIDTH+2}s", "Child") %> <%= sprintf("%#{CALL_WIDTH}s", "Calls") %> Name Line
    <%= sprintf("%#{TIME_WIDTH}.2f", caller.total_time) %> <%= sprintf("%#{TIME_WIDTH}.2f", caller.self_time) %> <%= sprintf("%#{TIME_WIDTH}.2f", caller.wait_time) %> <%= sprintf("%#{TIME_WIDTH}.2f", caller.children_time) %><%= sprintf("%#{CALL_WIDTH}s", called) %> <%= create_link(thread, caller.parent.target) %> <%= file_link(caller.parent.target.source_file, caller.line) %>
<%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage) %> <%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", self_percentage) %> <%= sprintf("%#{TIME_WIDTH}.2f", method.total_time) %> <%= sprintf("%#{TIME_WIDTH}.2f", method.self_time) %> <%= sprintf("%#{TIME_WIDTH}.2f", method.wait_time) %> <%= sprintf("%#{TIME_WIDTH}.2f", method.children_time) %> <%= sprintf("%#{CALL_WIDTH}i", method.called) %> <%= method.recursive? ? "*" : " "%><%= h method.full_name %> <%= file_link(method.source_file, method.line) %>
    <%= sprintf("%#{TIME_WIDTH}.2f", callee.total_time) %> <%= sprintf("%#{TIME_WIDTH}.2f", callee.self_time) %> <%= sprintf("%#{TIME_WIDTH}.2f", callee.wait_time) %> <%= sprintf("%#{TIME_WIDTH}.2f", callee.children_time) %><%= sprintf("%#{CALL_WIDTH}s", called) %> <%= create_link(thread, callee.target) %> <%= file_link(method.source_file, callee.line) %>
* indicates recursively called methods
<% end %> ' end end end