# class RubyProf::GraphHtmlPrinter

Generates graph 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

### Constants

CALL_WIDTH
PERCENTAGE_WIDTH
TIME_WIDTH

### Public Instance Methods

create_link(thread, overall_time, method) click to toggle source

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.

    # File lib/ruby-prof/printers/graph_html_printer.rb, line 49
    def create_link(thread, overall_time, method)
      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)
        "<a href=\"#{href}\">#{h method.full_name}</a>"
      end
    end

file_link(path, linenum) click to toggle source

    # File lib/ruby-prof/printers/graph_html_printer.rb, line 64
    def file_link(path, linenum)
      srcfile = File.expand_path(path)
      if srcfile =~ /\/ruby_runtime$/
        ""
      else
        if RUBY_PLATFORM =~ /darwin/
          "<a href=\"txmt://open?url=file://#{h srcfile}&line=#{linenum}\" title=\"#{h srcfile}:#{linenum}\">#{linenum}</a>"
        else
          "<a href=\"file://#{h srcfile}##{linenum}\" title=\"#{h srcfile}:#{linenum}\">#{linenum}</a>"
        end
      end
    end

method_href(thread, method) click to toggle source

    # File lib/ruby-prof/printers/graph_html_printer.rb, line 60
    def method_href(thread, method)
      h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread.fiber_id.to_s)
    end

print(output = STDOUT, options = {}) click to toggle source

    # File lib/ruby-prof/printers/graph_html_printer.rb, line 39
    def print(output = STDOUT, options = {})
      @output = output
      setup_options(options)
      @output << @erb.result(binding)
    end

setup_options(options) click to toggle source
Calls superclass method RubyProf::AbstractPrinter#setup_options

    # File lib/ruby-prof/printers/graph_html_printer.rb, line 30
    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

template() click to toggle source

    # File lib/ruby-prof/printers/graph_html_printer.rb, line 77
        def template
    '
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
      <style media="all" type="text/css">
        table {
          border-collapse: collapse;
          border: 1px solid #CCC;
          font-family: Verdana, Arial, Helvetica, sans-serif;
          font-size: 9pt;
          line-height: normal;
          width: 100%;
        }

        th {
          text-align: center;
          border-top: 1px solid #FB7A31;
          border-bottom: 1px solid #FB7A31;
          background: #FFC;
          padding: 0.3em;
          border-left: 1px solid silver;
        }

        tr.break td {
          border: 0;
          border-top: 1px solid #FB7A31;
          padding: 0;
          margin: 0;
        }

        tr.method td {
          font-weight: bold;
        }

        td {
          padding: 0.3em;
        }

        td:first-child {
          width: 190px;
          }

        td {
          border-left: 1px solid #CCC;
          text-align: center;
        }

        .method_name {
          text-align: left;
        }

        tfoot td {
          text-align: left;
        }
      </style>
      </head>
      <body>
        <h1>Profile Report</h1>
        <!-- Threads Table -->
        <table>
          <tr>
            <th>Thread ID</th>
            <th>Fiber ID</th>
            <th>Total Time</th>
          </tr>
          <% for thread in @result.threads %>
          <tr>
            <td><%= thread.id %></td>
            <td><a href="#<%= thread.fiber_id %>"><%= thread.fiber_id %></a></td>
            <td><%= thread.total_time %></td>
          </tr>
          <% end %>
        </table>

        <!-- Methods Tables -->
        <% for thread in @result.threads
             methods = thread.methods
             total_time = thread.total_time %>
          <h2><a name="<%= thread.fiber_id %>">Thread <%= thread.id %>, Fiber: <%= thread.fiber_id %></a></h2>
          <table>
            <thead>
              <tr>
                <th><%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Total") %></th>
                <th><%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Self") %></th>
                <th><%= sprintf("%#{TIME_WIDTH}s", "Total") %></th>
                <th><%= sprintf("%#{TIME_WIDTH}s", "Self") %></th>
                <th><%= sprintf("%#{TIME_WIDTH}s", "Wait") %></th>
                <th><%= sprintf("%#{TIME_WIDTH+2}s", "Child") %></th>
                <th><%= sprintf("%#{CALL_WIDTH}s", "Calls") %></th>
                <th class="method_name">Name</th>
                <th>Line</th>
              </tr>
            </thead>

            <tbody>
              <% 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 %>

                  <!-- Parents -->
                  <% for caller in method.aggregate_parents.sort_by(&:total_time)
                       next unless caller.parent
                       next if min_time && caller.total_time < min_time  %>
                    <tr>
                      <td>&nbsp;</td>
                      <td>&nbsp;</td>
                      <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.total_time) %></td>
                      <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.self_time) %></td>
                      <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.wait_time) %></td>
                      <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.children_time) %></td>
                      <% called = "#{caller.called}/#{method.called}" %>
                      <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td>
                      <td class="method_name"><%= create_link(thread, total_time, caller.parent.target) %></td>
                      <td><%= file_link(caller.parent.target.source_file, caller.line) %></td>
                    </tr>
                  <% end %>

                  <tr class="method">
                    <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage) %></td>
                    <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", self_percentage) %></td>
                    <td><%= sprintf("%#{TIME_WIDTH}.2f", method.total_time) %></td>
                    <td><%= sprintf("%#{TIME_WIDTH}.2f", method.self_time) %></td>
                    <td><%= sprintf("%#{TIME_WIDTH}.2f", method.wait_time) %></td>
                    <td><%= sprintf("%#{TIME_WIDTH}.2f", method.children_time) %></td>
                    <td><%= sprintf("%#{CALL_WIDTH}i", method.called) %></td>
                    <td class="method_name">
                      <a name="<%= method_href(thread, method) %>">
                        <%= method.recursive? ? "*" : " "%><%= h method.full_name %>
                      </a>
                    </td>
                    <td><%= file_link(method.source_file, method.line) %></td>
                  </tr>

                  <!-- Children -->
                  <% for callee in method.aggregate_children.sort_by(&:total_time).reverse %>
                  <%   next if min_time && callee.total_time < min_time  %>
                    <tr>
                      <td>&nbsp;</td>
                      <td>&nbsp;</td>
                      <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.total_time) %></td>
                      <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.self_time) %></td>
                      <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.wait_time) %></td>
                      <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.children_time) %></td>
                      <% called = "#{callee.called}/#{callee.target.called}" %>
                      <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td>
                      <td class="method_name"><%= create_link(thread, total_time, callee.target) %></td>
                      <td><%= file_link(method.source_file, callee.line) %></td>
                    </tr>
                  <% end %>
                  <!-- Create divider row -->
                  <tr class="break"><td colspan="9"></td></tr>
              <% end %>
            </tbody>
            <tfoot>
              <tr>
                <td colspan="9">* indicates recursively called methods</td>
              </tr>
            </tfoot>
          </table>
        <% end %>
      </body>
    </html>'
        end