airbnb-ruby-prof 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. data/CHANGES +483 -0
  2. data/LICENSE +25 -0
  3. data/README.rdoc +426 -0
  4. data/Rakefile +51 -0
  5. data/bin/ruby-prof +279 -0
  6. data/bin/ruby-prof-check-trace +45 -0
  7. data/examples/flat.txt +50 -0
  8. data/examples/graph.dot +84 -0
  9. data/examples/graph.html +823 -0
  10. data/examples/graph.txt +139 -0
  11. data/examples/multi.flat.txt +23 -0
  12. data/examples/multi.graph.html +760 -0
  13. data/examples/multi.grind.dat +114 -0
  14. data/examples/multi.stack.html +547 -0
  15. data/examples/stack.html +547 -0
  16. data/ext/ruby_prof/extconf.rb +67 -0
  17. data/ext/ruby_prof/rp_call_info.c +374 -0
  18. data/ext/ruby_prof/rp_call_info.h +59 -0
  19. data/ext/ruby_prof/rp_fast_call_tree_printer.c +247 -0
  20. data/ext/ruby_prof/rp_fast_call_tree_printer.h +10 -0
  21. data/ext/ruby_prof/rp_measure.c +71 -0
  22. data/ext/ruby_prof/rp_measure.h +56 -0
  23. data/ext/ruby_prof/rp_measure_allocations.c +74 -0
  24. data/ext/ruby_prof/rp_measure_cpu_time.c +134 -0
  25. data/ext/ruby_prof/rp_measure_gc_runs.c +71 -0
  26. data/ext/ruby_prof/rp_measure_gc_time.c +58 -0
  27. data/ext/ruby_prof/rp_measure_memory.c +75 -0
  28. data/ext/ruby_prof/rp_measure_process_time.c +69 -0
  29. data/ext/ruby_prof/rp_measure_wall_time.c +43 -0
  30. data/ext/ruby_prof/rp_method.c +717 -0
  31. data/ext/ruby_prof/rp_method.h +79 -0
  32. data/ext/ruby_prof/rp_stack.c +221 -0
  33. data/ext/ruby_prof/rp_stack.h +81 -0
  34. data/ext/ruby_prof/rp_thread.c +312 -0
  35. data/ext/ruby_prof/rp_thread.h +36 -0
  36. data/ext/ruby_prof/ruby_prof.c +800 -0
  37. data/ext/ruby_prof/ruby_prof.h +64 -0
  38. data/ext/ruby_prof/vc/ruby_prof.sln +32 -0
  39. data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +108 -0
  40. data/ext/ruby_prof/vc/ruby_prof_19.vcxproj +110 -0
  41. data/ext/ruby_prof/vc/ruby_prof_20.vcxproj +110 -0
  42. data/lib/ruby-prof.rb +63 -0
  43. data/lib/ruby-prof/aggregate_call_info.rb +76 -0
  44. data/lib/ruby-prof/assets/call_stack_printer.css.html +117 -0
  45. data/lib/ruby-prof/assets/call_stack_printer.js.html +385 -0
  46. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  47. data/lib/ruby-prof/assets/flame_graph_printer.lib.css.html +149 -0
  48. data/lib/ruby-prof/assets/flame_graph_printer.lib.js.html +707 -0
  49. data/lib/ruby-prof/assets/flame_graph_printer.page.js.html +56 -0
  50. data/lib/ruby-prof/assets/flame_graph_printer.tmpl.html.erb +39 -0
  51. data/lib/ruby-prof/call_info.rb +111 -0
  52. data/lib/ruby-prof/call_info_visitor.rb +40 -0
  53. data/lib/ruby-prof/compatibility.rb +186 -0
  54. data/lib/ruby-prof/method_info.rb +109 -0
  55. data/lib/ruby-prof/printers/abstract_printer.rb +85 -0
  56. data/lib/ruby-prof/printers/call_info_printer.rb +41 -0
  57. data/lib/ruby-prof/printers/call_stack_printer.rb +260 -0
  58. data/lib/ruby-prof/printers/call_tree_printer.rb +130 -0
  59. data/lib/ruby-prof/printers/dot_printer.rb +132 -0
  60. data/lib/ruby-prof/printers/fast_call_tree_printer.rb +87 -0
  61. data/lib/ruby-prof/printers/flame_graph_html_printer.rb +59 -0
  62. data/lib/ruby-prof/printers/flame_graph_json_printer.rb +157 -0
  63. data/lib/ruby-prof/printers/flat_printer.rb +70 -0
  64. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +64 -0
  65. data/lib/ruby-prof/printers/graph_html_printer.rb +244 -0
  66. data/lib/ruby-prof/printers/graph_printer.rb +116 -0
  67. data/lib/ruby-prof/printers/multi_printer.rb +58 -0
  68. data/lib/ruby-prof/profile.rb +22 -0
  69. data/lib/ruby-prof/profile/exclude_common_methods.rb +201 -0
  70. data/lib/ruby-prof/rack.rb +95 -0
  71. data/lib/ruby-prof/task.rb +147 -0
  72. data/lib/ruby-prof/thread.rb +35 -0
  73. data/lib/ruby-prof/version.rb +4 -0
  74. data/lib/ruby-prof/walker.rb +95 -0
  75. data/lib/unprof.rb +10 -0
  76. data/ruby-prof.gemspec +56 -0
  77. data/test/aggregate_test.rb +136 -0
  78. data/test/basic_test.rb +128 -0
  79. data/test/block_test.rb +74 -0
  80. data/test/call_info_test.rb +78 -0
  81. data/test/call_info_visitor_test.rb +31 -0
  82. data/test/duplicate_names_test.rb +32 -0
  83. data/test/dynamic_method_test.rb +55 -0
  84. data/test/enumerable_test.rb +21 -0
  85. data/test/exceptions_test.rb +16 -0
  86. data/test/exclude_methods_test.rb +146 -0
  87. data/test/exclude_threads_test.rb +53 -0
  88. data/test/fiber_test.rb +79 -0
  89. data/test/issue137_test.rb +63 -0
  90. data/test/line_number_test.rb +71 -0
  91. data/test/measure_allocations_test.rb +26 -0
  92. data/test/measure_cpu_time_test.rb +213 -0
  93. data/test/measure_gc_runs_test.rb +32 -0
  94. data/test/measure_gc_time_test.rb +36 -0
  95. data/test/measure_memory_test.rb +33 -0
  96. data/test/measure_process_time_test.rb +63 -0
  97. data/test/measure_wall_time_test.rb +255 -0
  98. data/test/module_test.rb +45 -0
  99. data/test/multi_measure_test.rb +38 -0
  100. data/test/multi_printer_test.rb +83 -0
  101. data/test/no_method_class_test.rb +15 -0
  102. data/test/pause_resume_test.rb +166 -0
  103. data/test/prime.rb +54 -0
  104. data/test/printers_test.rb +255 -0
  105. data/test/printing_recursive_graph_test.rb +127 -0
  106. data/test/rack_test.rb +93 -0
  107. data/test/recursive_test.rb +212 -0
  108. data/test/singleton_test.rb +38 -0
  109. data/test/stack_printer_test.rb +65 -0
  110. data/test/stack_test.rb +138 -0
  111. data/test/start_stop_test.rb +112 -0
  112. data/test/test_helper.rb +264 -0
  113. data/test/thread_test.rb +187 -0
  114. data/test/unique_call_path_test.rb +202 -0
  115. data/test/yarv_test.rb +55 -0
  116. metadata +211 -0
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+
3
+ module RubyProf
4
+ # Generates flat[link:files/examples/flat_txt.html] profile reports as text.
5
+ # To use the flat printer with line numbers:
6
+ #
7
+ # result = RubyProf.profile do
8
+ # [code to profile]
9
+ # end
10
+ #
11
+ # printer = RubyProf::FlatPrinterWithLineNumbers.new(result)
12
+ # printer.print(STDOUT, {})
13
+ #
14
+ class FlatPrinterWithLineNumbers < FlatPrinter
15
+ def print_methods(thread)
16
+ total_time = thread.total_time
17
+
18
+ methods = thread.methods.sort_by(&sort_method).reverse
19
+ sum = 0
20
+ methods.each do |method|
21
+ self_percent = (method.self_time / total_time) * 100
22
+ next if self_percent < min_percent
23
+
24
+ sum += method.self_time
25
+ #self_time_called = method.called > 0 ? method.self_time/method.called : 0
26
+ #total_time_called = method.called > 0? method.total_time/method.called : 0
27
+
28
+ @output << "%6.2f %9.3f %9.3f %9.3f %9.3f %8d %s%s" % [
29
+ method.self_time / total_time * 100, # %self
30
+ method.total_time, # total
31
+ method.self_time, # self
32
+ method.wait_time, # wait
33
+ method.children_time, # children
34
+ method.called, # calls
35
+ method.recursive? ? "*" : " ", # cycle
36
+ method_name(method) # name
37
+ ]
38
+ if method.source_file == 'ruby_runtime'
39
+ @output << "\n"
40
+ else
41
+ @output << "\n defined at:\n"
42
+ @output << " %s:%s\n" % [File.expand_path(method.source_file), method.line]
43
+ end
44
+
45
+ callers = []
46
+ method.call_infos.each do |ci|
47
+ if ci.parent && ci.parent.target.source_file != 'ruby_runtime'
48
+ callers << [method_name(ci.parent.target), File.expand_path(ci.parent.target.source_file), ci.parent.target.line]
49
+ end
50
+ end
51
+ # make sure callers are unique
52
+ callers.uniq!
53
+
54
+ unless callers.empty?
55
+ @output << " called from:\n"
56
+ callers.each do |args|
57
+ @output << " %s (%s:%s)\n" % args
58
+ end
59
+ end
60
+ @output << "\n"
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,244 @@
1
+ # encoding: utf-8
2
+
3
+ require 'erb'
4
+
5
+ module RubyProf
6
+ # Generates graph[link:files/examples/graph_html.html] profile reports as html.
7
+ # To use the graph html printer:
8
+ #
9
+ # result = RubyProf.profile do
10
+ # [code to profile]
11
+ # end
12
+ #
13
+ # printer = RubyProf::GraphHtmlPrinter.new(result)
14
+ # printer.print(STDOUT, :min_percent=>0)
15
+ #
16
+ # The Graph printer takes the following options in its print methods:
17
+ # :filename - specify a file to use that contains the ERB
18
+ # template to use, instead of the built-in self.template
19
+ #
20
+ # :template - specify an ERB template to use, instead of the
21
+ # built-in self.template
22
+ #
23
+
24
+ class GraphHtmlPrinter < AbstractPrinter
25
+ include ERB::Util
26
+
27
+ def setup_options(options)
28
+ super(options)
29
+
30
+ filename = options[:filename]
31
+ template = filename ? File.read(filename).untaint : (options[:template] || self.template)
32
+ @erb = ERB.new(template)
33
+ @erb.filename = filename
34
+ end
35
+
36
+ def print(output = STDOUT, options = {})
37
+ @output = output
38
+ setup_options(options)
39
+ @output << @erb.result(binding).split("\n").map(&:rstrip).join("\n") << "\n"
40
+ end
41
+
42
+ # Creates a link to a method. Note that we do not create
43
+ # links to methods which are under the min_perecent
44
+ # specified by the user, since they will not be
45
+ # printed out.
46
+ def create_link(thread, overall_time, method)
47
+ total_percent = (method.total_time/overall_time) * 100
48
+ if total_percent < min_percent
49
+ # Just return name
50
+ h method.full_name
51
+ else
52
+ href = '#' + method_href(thread, method)
53
+ "<a href=\"#{href}\">#{h method.full_name}</a>"
54
+ end
55
+ end
56
+
57
+ def method_href(thread, method)
58
+ h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread.fiber_id.to_s)
59
+ end
60
+
61
+ def file_link(path, linenum)
62
+ srcfile = File.expand_path(path)
63
+ if srcfile =~ /\/ruby_runtime$/
64
+ ""
65
+ else
66
+ if RUBY_PLATFORM =~ /darwin/
67
+ "<a href=\"txmt://open?url=file://#{h srcfile}&line=#{linenum}\" title=\"#{h srcfile}:#{linenum}\">#{linenum}</a>"
68
+ else
69
+ "<a href=\"file://#{h srcfile}##{linenum}\" title=\"#{h srcfile}:#{linenum}\">#{linenum}</a>"
70
+ end
71
+ end
72
+ end
73
+
74
+ def template
75
+ '
76
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
77
+ <html>
78
+ <head>
79
+ <style media="all" type="text/css">
80
+ table {
81
+ border-collapse: collapse;
82
+ border: 1px solid #CCC;
83
+ font-family: Verdana, Arial, Helvetica, sans-serif;
84
+ font-size: 9pt;
85
+ line-height: normal;
86
+ width: 100%;
87
+ }
88
+
89
+ th {
90
+ text-align: center;
91
+ border-top: 1px solid #FB7A31;
92
+ border-bottom: 1px solid #FB7A31;
93
+ background: #FFC;
94
+ padding: 0.3em;
95
+ border-left: 1px solid silver;
96
+ }
97
+
98
+ tr.break td {
99
+ border: 0;
100
+ border-top: 1px solid #FB7A31;
101
+ padding: 0;
102
+ margin: 0;
103
+ }
104
+
105
+ tr.method td {
106
+ font-weight: bold;
107
+ }
108
+
109
+ td {
110
+ padding: 0.3em;
111
+ }
112
+
113
+ td:first-child {
114
+ width: 190px;
115
+ }
116
+
117
+ td {
118
+ border-left: 1px solid #CCC;
119
+ text-align: center;
120
+ }
121
+
122
+ .method_name {
123
+ text-align: left;
124
+ }
125
+
126
+ tfoot td {
127
+ text-align: left;
128
+ }
129
+ </style>
130
+ </head>
131
+ <body>
132
+ <h1>Profile Report: <%= RubyProf.measure_mode_string %></h1>
133
+ <!-- Threads Table -->
134
+ <table>
135
+ <tr>
136
+ <th>Thread ID</th>
137
+ <th>Fiber ID</th>
138
+ <th>Total Time</th>
139
+ </tr>
140
+ <% for thread in @result.threads %>
141
+ <tr>
142
+ <td><%= thread.id %></td>
143
+ <td><a href="#<%= thread.fiber_id %>"><%= thread.fiber_id %></a></td>
144
+ <td><%= thread.total_time %></td>
145
+ </tr>
146
+ <% end %>
147
+ </table>
148
+ <!-- Methods Tables -->
149
+ <%
150
+ for thread in @result.threads
151
+ methods = thread.methods
152
+ total_time = thread.total_time
153
+ %>
154
+ <h2><a name="<%= thread.fiber_id %>">Thread <%= thread.id %>, Fiber: <%= thread.fiber_id %></a></h2>
155
+ <table>
156
+ <thead>
157
+ <tr>
158
+ <th>%Total</th>
159
+ <th>%Self</th>
160
+ <th>Total</th>
161
+ <th>Self</th>
162
+ <th>Wait</th>
163
+ <th>Child</th>
164
+ <th>Calls</th>
165
+ <th class="method_name">Name</th>
166
+ <th>Line</th>
167
+ </tr>
168
+ </thead>
169
+ <tbody>
170
+ <%
171
+ min_time = @options[:min_time] || (@options[:nonzero] ? 0.005 : nil)
172
+ methods.sort_by(&sort_method).reverse_each do |method|
173
+ total_percentage = (method.total_time/total_time) * 100
174
+ next if total_percentage < min_percent
175
+ next if min_time && method.total_time < min_time
176
+ self_percentage = (method.self_time/total_time) * 100
177
+ %>
178
+ <!-- Parents -->
179
+ <%
180
+ for caller in method.aggregate_parents.sort_by(&:total_time)
181
+ next unless caller.parent
182
+ next if min_time && caller.total_time < min_time
183
+ %>
184
+ <tr>
185
+ <td>&nbsp;</td>
186
+ <td>&nbsp;</td>
187
+ <td><%= sprintf("%.2f", caller.total_time) %></td>
188
+ <td><%= sprintf("%.2f", caller.self_time) %></td>
189
+ <td><%= sprintf("%.2f", caller.wait_time) %></td>
190
+ <td><%= sprintf("%.2f", caller.children_time) %></td>
191
+ <td><%= "#{caller.called}/#{method.called}" %></td>
192
+ <td class="method_name"><%= create_link(thread, total_time, caller.parent.target) %></td>
193
+ <td><%= file_link(caller.parent.target.source_file, caller.line) %></td>
194
+ </tr>
195
+ <% end %>
196
+ <tr class="method">
197
+ <td><%= sprintf("%.2f\%", total_percentage) %></td>
198
+ <td><%= sprintf("%.2f\%", self_percentage) %></td>
199
+ <td><%= sprintf("%.2f", method.total_time) %></td>
200
+ <td><%= sprintf("%.2f", method.self_time) %></td>
201
+ <td><%= sprintf("%.2f", method.wait_time) %></td>
202
+ <td><%= sprintf("%.2f", method.children_time) %></td>
203
+ <td><%= sprintf("%i", method.called) %></td>
204
+ <td class="method_name">
205
+ <a name="<%= method_href(thread, method) %>">
206
+ <%= method.recursive? ? "*" : " "%><%= h method.full_name %>
207
+ </a>
208
+ </td>
209
+ <td><%= file_link(method.source_file, method.line) %></td>
210
+ </tr>
211
+ <!-- Children -->
212
+ <%
213
+ for callee in method.aggregate_children.sort_by(&:total_time).reverse
214
+ next if min_time && callee.total_time < min_time
215
+ %>
216
+ <tr>
217
+ <td>&nbsp;</td>
218
+ <td>&nbsp;</td>
219
+ <td><%= sprintf("%.2f", callee.total_time) %></td>
220
+ <td><%= sprintf("%.2f", callee.self_time) %></td>
221
+ <td><%= sprintf("%.2f", callee.wait_time) %></td>
222
+ <td><%= sprintf("%.2f", callee.children_time) %></td>
223
+ <td><%= "#{callee.called}/#{callee.target.called}" %></td>
224
+ <td class="method_name"><%= create_link(thread, total_time, callee.target) %></td>
225
+ <td><%= file_link(method.source_file, callee.line) %></td>
226
+ </tr>
227
+ <% end %>
228
+ <!-- Create divider row -->
229
+ <tr class="break"><td colspan="9"></td></tr>
230
+ <% end %>
231
+ </tbody>
232
+ <tfoot>
233
+ <tr>
234
+ <td colspan="9">* indicates recursively called methods</td>
235
+ </tr>
236
+ </tfoot>
237
+ </table>
238
+ <% end %>
239
+ </body>
240
+ </html>'
241
+ end
242
+ end
243
+ end
244
+
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ module RubyProf
4
+ # Generates graph[link:files/examples/graph_txt.html] profile reports as text.
5
+ # To use the graph printer:
6
+ #
7
+ # result = RubyProf.profile do
8
+ # [code to profile]
9
+ # end
10
+ #
11
+ # printer = RubyProf::GraphPrinter.new(result)
12
+ # printer.print(STDOUT, {})
13
+ #
14
+ # The constructor takes two arguments. See the README
15
+
16
+ class GraphPrinter < AbstractPrinter
17
+ PERCENTAGE_WIDTH = 8
18
+ TIME_WIDTH = 11
19
+ CALL_WIDTH = 17
20
+
21
+ private
22
+
23
+ def print_header(thread)
24
+ @output << "Measure Mode: %s\n" % RubyProf.measure_mode_string
25
+ @output << "Thread ID: #{thread.id}\n"
26
+ @output << "Fiber ID: #{thread.fiber_id}\n" unless thread.id == thread.fiber_id
27
+ @output << "Total Time: #{thread.total_time}\n"
28
+ @output << "Sort by: #{sort_method}\n"
29
+ @output << "\n"
30
+
31
+ # 1 is for % sign
32
+ @output << sprintf("%#{PERCENTAGE_WIDTH}s", "%total")
33
+ @output << sprintf("%#{PERCENTAGE_WIDTH}s", "%self")
34
+ @output << sprintf("%#{TIME_WIDTH}s", "total")
35
+ @output << sprintf("%#{TIME_WIDTH}s", "self")
36
+ @output << sprintf("%#{TIME_WIDTH}s", "wait")
37
+ @output << sprintf("%#{TIME_WIDTH}s", "child")
38
+ @output << sprintf("%#{CALL_WIDTH}s", "calls")
39
+ @output << " name"
40
+ @output << "\n"
41
+ end
42
+
43
+ def print_methods(thread)
44
+ total_time = thread.total_time
45
+ # Sort methods from longest to shortest total time
46
+ methods = thread.methods.sort_by(&sort_method)
47
+
48
+ # Print each method in total time order
49
+ methods.reverse_each do |method|
50
+ total_percentage = (method.total_time/total_time) * 100
51
+ next if total_percentage < min_percent
52
+
53
+ self_percentage = (method.self_time/total_time) * 100
54
+
55
+ @output << "-" * 80 << "\n"
56
+ print_parents(thread, method)
57
+
58
+ # 1 is for % sign
59
+ @output << sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage)
60
+ @output << sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", self_percentage)
61
+ @output << sprintf("%#{TIME_WIDTH}.3f", method.total_time)
62
+ @output << sprintf("%#{TIME_WIDTH}.3f", method.self_time)
63
+ @output << sprintf("%#{TIME_WIDTH}.3f", method.wait_time)
64
+ @output << sprintf("%#{TIME_WIDTH}.3f", method.children_time)
65
+ @output << sprintf("%#{CALL_WIDTH}i", method.called)
66
+ @output << sprintf(" %s", method.recursive? ? "*" : " ")
67
+ @output << sprintf("%s", method_name(method))
68
+ if print_file
69
+ @output << sprintf(" %s:%s", method.source_file, method.line)
70
+ end
71
+ @output << "\n"
72
+
73
+ print_children(method)
74
+ end
75
+ end
76
+
77
+ def print_parents(thread, method)
78
+ method.aggregate_parents.sort_by(&:total_time).each do |caller|
79
+ next unless caller.parent
80
+ @output << " " * 2 * PERCENTAGE_WIDTH
81
+ @output << sprintf("%#{TIME_WIDTH}.3f", caller.total_time)
82
+ @output << sprintf("%#{TIME_WIDTH}.3f", caller.self_time)
83
+ @output << sprintf("%#{TIME_WIDTH}.3f", caller.wait_time)
84
+ @output << sprintf("%#{TIME_WIDTH}.3f", caller.children_time)
85
+
86
+ call_called = "#{caller.called}/#{method.called}"
87
+ @output << sprintf("%#{CALL_WIDTH}s", call_called)
88
+ @output << sprintf(" %s", caller.parent.target.full_name)
89
+ @output << "\n"
90
+ end
91
+ end
92
+
93
+ def print_children(method)
94
+ method.aggregate_children.sort_by(&:total_time).reverse.each do |child|
95
+ # Get children method
96
+
97
+ @output << " " * 2 * PERCENTAGE_WIDTH
98
+
99
+ @output << sprintf("%#{TIME_WIDTH}.3f", child.total_time)
100
+ @output << sprintf("%#{TIME_WIDTH}.3f", child.self_time)
101
+ @output << sprintf("%#{TIME_WIDTH}.3f", child.wait_time)
102
+ @output << sprintf("%#{TIME_WIDTH}.3f", child.children_time)
103
+
104
+ call_called = "#{child.called}/#{child.target.called}"
105
+ @output << sprintf("%#{CALL_WIDTH}s", call_called)
106
+ @output << sprintf(" %s", child.target.full_name)
107
+ @output << "\n"
108
+ end
109
+ end
110
+
111
+ def print_footer(thread)
112
+ @output << "\n"
113
+ @output << "* indicates recursively called methods\n"
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+
3
+ module RubyProf
4
+ # Helper class to simplify printing profiles of several types from
5
+ # one profiling run. Currently prints a flat profile, a callgrind
6
+ # profile, a call stack profile and a graph profile.
7
+ class MultiPrinter
8
+ def initialize(result)
9
+ @stack_printer = CallStackPrinter.new(result)
10
+ @graph_printer = GraphHtmlPrinter.new(result)
11
+ @tree_printer = CallTreePrinter.new(result)
12
+ @flat_printer = FlatPrinter.new(result)
13
+ end
14
+
15
+ # create profile files under options[:path] or the current
16
+ # directory. options[:profile] is used as the base name for the
17
+ # pofile file, defaults to "profile".
18
+ def print(options)
19
+ @profile = options.delete(:profile) || "profile"
20
+ @directory = options.delete(:path) || File.expand_path(".")
21
+
22
+ File.open(stack_profile, "w") do |f|
23
+ @stack_printer.print(f, options.merge(:graph => "#{@profile}.graph.html"))
24
+ end
25
+
26
+ File.open(graph_profile, "w") do |f|
27
+ @graph_printer.print(f, options)
28
+ end
29
+
30
+ @tree_printer.print(options.merge(:path => @directory, :profile => @profile))
31
+
32
+ File.open(flat_profile, "w") do |f|
33
+ @flat_printer.print(f, options)
34
+ end
35
+ end
36
+
37
+ # the name of the call stack profile file
38
+ def stack_profile
39
+ "#{@directory}/#{@profile}.stack.html"
40
+ end
41
+
42
+ # the name of the graph profile file
43
+ def graph_profile
44
+ "#{@directory}/#{@profile}.graph.html"
45
+ end
46
+
47
+ # the name of the callgrind profile file
48
+ def tree_profile
49
+ "#{@directory}/#{@profile}.callgrind.out.#{$$}"
50
+ end
51
+
52
+ # the name of the flat profile file
53
+ def flat_profile
54
+ "#{@directory}/#{@profile}.flat.txt"
55
+ end
56
+
57
+ end
58
+ end