Class | RubyProf::GraphHtmlPrinter |
In: |
lib/ruby-prof/graph_html_printer.rb
|
Parent: | AbstractPrinter |
Generates graph profile reports as html. To use the grap html printer:
result = RubyProf.profile do [code to profile] end printer = RubyProf::GraphHtmlPrinter.new(result) printer.print(STDOUT, :min_percent=>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.
PERCENTAGE_WIDTH | = | 8 |
TIME_WIDTH | = | 10 |
CALL_WIDTH | = | 20 |
Create a GraphPrinter. Result is a RubyProf::Result object generated from a profiling run.
# File lib/ruby-prof/graph_html_printer.rb, line 32 32: def initialize(result) 33: super(result) 34: @thread_times = Hash.new 35: calculate_thread_times 36: end
These methods should be private but then ERB doesn‘t work. Turn off RDOC though
# File lib/ruby-prof/graph_html_printer.rb, line 61 61: def calculate_thread_times 62: # Cache thread times since this is an expensive 63: # operation with the required sorting 64: @result.threads.each do |thread_id, methods| 65: top = methods.sort.last 66: 67: thread_time = 0.01 68: thread_time = top.total_time if top.total_time > 0 69: 70: @thread_times[thread_id] = thread_time 71: end 72: 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.
# File lib/ruby-prof/graph_html_printer.rb, line 92 92: def create_link(thread_id, method) 93: if self.total_percent(thread_id, method) < min_percent 94: # Just return name 95: h method.full_name 96: else 97: href = '#' + method_href(thread_id, method) 98: "<a href=\"#{href}\">#{h method.full_name}</a>" 99: end 100: end
# File lib/ruby-prof/graph_html_printer.rb, line 102 102: def method_href(thread_id, method) 103: h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread_id.to_s) 104: end
Print a graph html report to the provided output.
output - Any IO oject, including STDOUT or a file. The default value is STDOUT.
options - Hash of print options. See setup_options
for more information.
# File lib/ruby-prof/graph_html_printer.rb, line 46 46: def print(output = STDOUT, options = {}) 47: @output = output 48: setup_options(options) 49: 50: filename = options[:filename] 51: template = filename ? File.read(filename).untaint : (options[:template] || self.template) 52: _erbout = @output 53: erb = ERB.new(template, nil, nil) 54: erb.filename = filename 55: @output << erb.result(binding) 56: end
# File lib/ruby-prof/graph_html_printer.rb, line 83 83: def self_percent(method) 84: overall_time = self.thread_time(method.thread_id) 85: (method.self_time/overall_time) * 100 86: end
# File lib/ruby-prof/graph_html_printer.rb, line 106 106: def template 107: ' 108: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 109: <html> 110: <head> 111: <style media="all" type="text/css"> 112: table { 113: border-collapse: collapse; 114: border: 1px solid #CCC; 115: font-family: Verdana, Arial, Helvetica, sans-serif; 116: font-size: 9pt; 117: line-height: normal; 118: } 119: 120: th { 121: text-align: center; 122: border-top: 1px solid #FB7A31; 123: border-bottom: 1px solid #FB7A31; 124: background: #FFC; 125: padding: 0.3em; 126: border-left: 1px solid silver; 127: } 128: 129: tr.break td { 130: border: 0; 131: border-top: 1px solid #FB7A31; 132: padding: 0; 133: margin: 0; 134: } 135: 136: tr.method td { 137: font-weight: bold; 138: } 139: 140: td { 141: padding: 0.3em; 142: } 143: 144: td:first-child { 145: width: 190px; 146: } 147: 148: td { 149: border-left: 1px solid #CCC; 150: text-align: center; 151: } 152: 153: .method_name { 154: text-align: left; 155: max-width: 25em; 156: } 157: </style> 158: </head> 159: <body> 160: <h1>Profile Report</h1> 161: <!-- Threads Table --> 162: <table> 163: <tr> 164: <th>Thread ID</th> 165: <th>Total Time</th> 166: </tr> 167: <% for thread_id, methods in @result.threads %> 168: <tr> 169: <td><a href="#<%= thread_id %>"><%= thread_id %></a></td> 170: <td><%= thread_time(thread_id) %></td> 171: </tr> 172: <% end %> 173: </table> 174: 175: <!-- Methods Tables --> 176: <% for thread_id, methods in @result.threads 177: total_time = thread_time(thread_id) %> 178: <h2><a name="<%= thread_id %>">Thread <%= thread_id %></a></h2> 179: 180: <table> 181: <tr> 182: <th><%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Total") %></th> 183: <th><%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Self") %></th> 184: <th><%= sprintf("%#{TIME_WIDTH}s", "Total") %></th> 185: <th><%= sprintf("%#{TIME_WIDTH}s", "Self") %></th> 186: <th><%= sprintf("%#{TIME_WIDTH}s", "Wait") %></th> 187: <th><%= sprintf("%#{TIME_WIDTH+2}s", "Child") %></th> 188: <th><%= sprintf("%#{CALL_WIDTH}s", "Calls") %></th> 189: <th class="method_name">Name</th> 190: <th>Line</th> 191: </tr> 192: 193: <% min_time = @options[:min_time] || (@options[:nonzero] ? 0.005 : nil) 194: methods.sort.reverse_each do |method| 195: total_percentage = (method.total_time/total_time) * 100 196: next if total_percentage < min_percent 197: next if min_time && method.total_time < min_time 198: self_percentage = (method.self_time/total_time) * 100 %> 199: 200: <!-- Parents --> 201: <% for caller in method.parents %> 202: <% next if min_time && caller.total_time < min_time %> 203: <tr> 204: <td> </td> 205: <td> </td> 206: <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.total_time) %></td> 207: <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.self_time) %></td> 208: <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.wait_time) %></td> 209: <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.children_time) %></td> 210: <% called = "#{caller.called}/#{method.called}" %> 211: <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td> 212: <td class="method_name"><%= create_link(thread_id, caller.target) %></td> 213: <td><a href="file://<%=h srcfile=File.expand_path(caller.target.source_file) %>#line=<%= linenum=caller.line %>" title="<%=h srcfile %>:<%= linenum %>"><%= caller.line %></a></td> 214: </tr> 215: <% end %> 216: 217: <tr class="method"> 218: <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage) %></td> 219: <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", self_percentage) %></td> 220: <td><%= sprintf("%#{TIME_WIDTH}.2f", method.total_time) %></td> 221: <td><%= sprintf("%#{TIME_WIDTH}.2f", method.self_time) %></td> 222: <td><%= sprintf("%#{TIME_WIDTH}.2f", method.wait_time) %></td> 223: <td><%= sprintf("%#{TIME_WIDTH}.2f", method.children_time) %></td> 224: <td><%= sprintf("%#{CALL_WIDTH}i", method.called) %></td> 225: <td class="method_name"><a name="<%= method_href(thread_id, method) %>"><%= h method.full_name %></a></td> 226: <td><a href="file://<%=h srcfile=File.expand_path(method.source_file) %>#line=<%= linenum=method.line %>" title="<%=h srcfile %>:<%= linenum %>"><%= method.line %></a></td> 227: </tr> 228: 229: <!-- Children --> 230: <% for callee in method.children %> 231: <% next if min_time && callee.total_time < min_time %> 232: <tr> 233: <td> </td> 234: <td> </td> 235: <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.total_time) %></td> 236: <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.self_time) %></td> 237: <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.wait_time) %></td> 238: <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.children_time) %></td> 239: <% called = "#{callee.called}/#{callee.target.called}" %> 240: <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td> 241: <td class="method_name"><%= create_link(thread_id, callee.target) %></td> 242: <td><a href="file://<%=h srcfile=File.expand_path(method.source_file) %>#line=<%= linenum=callee.line %>" title="<%=h srcfile %>:<%= linenum %>"><%= callee.line %></a></td> 243: </tr> 244: <% end %> 245: <!-- Create divider row --> 246: <tr class="break"><td colspan="9"></td></tr> 247: <% end %> 248: </table> 249: <% end %> 250: </body> 251: </html>' 252: end
# File lib/ruby-prof/graph_html_printer.rb, line 74 74: def thread_time(thread_id) 75: @thread_times[thread_id] 76: end