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, 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.
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 58 58: def calculate_thread_times 59: # Cache thread times since this is an expensive 60: # operation with the required sorting 61: @result.threads.each do |thread_id, methods| 62: top = methods.sort.last 63: 64: thread_time = 0.01 65: thread_time = top.total_time if top.total_time > 0 66: 67: @thread_times[thread_id] = thread_time 68: end 69: 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 89 89: def create_link(thread_id, method) 90: if self.total_percent(thread_id, method) < min_percent 91: # Just return name 92: h method.full_name 93: else 94: href = '#' + method_href(thread_id, method) 95: "<a href=\"#{href}\">#{h method.full_name}</a>" 96: end 97: end
# File lib/ruby-prof/graph_html_printer.rb, line 99 99: def method_href(thread_id, method) 100: h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread_id.to_s) 101: 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: _erbout = @output 51: erb = ERB.new(template, nil, nil) 52: @output << erb.result(binding) 53: end
# File lib/ruby-prof/graph_html_printer.rb, line 80 80: def self_percent(method) 81: overall_time = self.thread_time(method.thread_id) 82: (method.self_time/overall_time) * 100 83: end
# File lib/ruby-prof/graph_html_printer.rb, line 103 103: def template 104: ' 105: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 106: <html> 107: <head> 108: <style media="all" type="text/css"> 109: table { 110: border-collapse: collapse; 111: border: 1px solid #CCC; 112: font-family: Verdana, Arial, Helvetica, sans-serif; 113: font-size: 9pt; 114: line-height: normal; 115: } 116: 117: th { 118: text-align: center; 119: border-top: 1px solid #FB7A31; 120: border-bottom: 1px solid #FB7A31; 121: background: #FFC; 122: padding: 0.3em; 123: border-left: 1px solid silver; 124: } 125: 126: tr.break td { 127: border: 0; 128: border-top: 1px solid #FB7A31; 129: padding: 0; 130: margin: 0; 131: } 132: 133: tr.method td { 134: font-weight: bold; 135: } 136: 137: td { 138: padding: 0.3em; 139: } 140: 141: td:first-child { 142: width: 190px; 143: } 144: 145: td { 146: border-left: 1px solid #CCC; 147: text-align: center; 148: } 149: </style> 150: </head> 151: <body> 152: <h1>Profile Report</h1> 153: <!-- Threads Table --> 154: <table> 155: <tr> 156: <th>Thread ID</th> 157: <th>Total Time</th> 158: </tr> 159: <% for thread_id, methods in @result.threads %> 160: <tr> 161: <td><a href="#<%= thread_id %>"><%= thread_id %></a></td> 162: <td><%= thread_time(thread_id) %></td> 163: </tr> 164: <% end %> 165: </table> 166: 167: <!-- Methods Tables --> 168: <% for thread_id, methods in @result.threads 169: total_time = thread_time(thread_id) %> 170: <h2><a name="<%= thread_id %>">Thread <%= thread_id %></a></h2> 171: 172: <table> 173: <tr> 174: <th><%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Total") %></th> 175: <th><%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Self") %></th> 176: <th><%= sprintf("%#{TIME_WIDTH}s", "Total") %></th> 177: <th><%= sprintf("%#{TIME_WIDTH}s", "Self") %></th> 178: <th><%= sprintf("%#{TIME_WIDTH}s", "Wait") %></th> 179: <th><%= sprintf("%#{TIME_WIDTH+2}s", "Child") %></th> 180: <th><%= sprintf("%#{CALL_WIDTH}s", "Calls") %></th> 181: <th>Name</th> 182: <th>Line</th> 183: </tr> 184: 185: <% methods.sort.reverse_each do |method| 186: total_percentage = (method.total_time/total_time) * 100 187: next if total_percentage < min_percent 188: self_percentage = (method.self_time/total_time) * 100 %> 189: 190: <!-- Parents --> 191: <% for caller in method.parents %> 192: <tr> 193: <td> </td> 194: <td> </td> 195: <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.total_time) %></td> 196: <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.self_time) %></td> 197: <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.wait_time) %></td> 198: <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.children_time) %></td> 199: <% called = "#{caller.called}/#{method.called}" %> 200: <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td> 201: <td><%= create_link(thread_id, caller.target) %></td> 202: <td><a href="file://<%= File.expand_path(caller.target.source_file) %>#line=<%= caller.line %>"><%= caller.line %></a></td> 203: </tr> 204: <% end %> 205: 206: <tr class="method"> 207: <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage) %></td> 208: <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", self_percentage) %></td> 209: <td><%= sprintf("%#{TIME_WIDTH}.2f", method.total_time) %></td> 210: <td><%= sprintf("%#{TIME_WIDTH}.2f", method.self_time) %></td> 211: <td><%= sprintf("%#{TIME_WIDTH}.2f", method.wait_time) %></td> 212: <td><%= sprintf("%#{TIME_WIDTH}.2f", method.children_time) %></td> 213: <td><%= sprintf("%#{CALL_WIDTH}i", method.called) %></td> 214: <td><a name="<%= method_href(thread_id, method) %>"><%= h method.full_name %></a></td> 215: <td><a href="file://<%= File.expand_path(method.source_file) %>#line=<%= method.line %>"><%= method.line %></a></td> 216: </tr> 217: 218: <!-- Children --> 219: <% for callee in method.children %> 220: <tr> 221: <td> </td> 222: <td> </td> 223: <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.total_time) %></td> 224: <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.self_time) %></td> 225: <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.wait_time) %></td> 226: <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.children_time) %></td> 227: <% called = "#{callee.called}/#{callee.target.called}" %> 228: <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td> 229: <td><%= create_link(thread_id, callee.target) %></td> 230: <td><a href="file://<%= File.expand_path(method.source_file) %>#line=<%= callee.line %>"><%= callee.line %></a></td> 231: </tr> 232: <% end %> 233: <!-- Create divider row --> 234: <tr class="break"><td colspan="8"></td></tr> 235: <% end %> 236: </table> 237: <% end %> 238: </body> 239: </html>' 240: end
# File lib/ruby-prof/graph_html_printer.rb, line 71 71: def thread_time(thread_id) 72: @thread_times[thread_id] 73: end