rdp-ruby-prof 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/CHANGES +202 -0
  2. data/LICENSE +23 -0
  3. data/README +445 -0
  4. data/Rakefile +123 -0
  5. data/bin/ruby-prof +207 -0
  6. data/examples/flat.txt +55 -0
  7. data/examples/graph.html +823 -0
  8. data/examples/graph.txt +170 -0
  9. data/ext/#ruby_prof.c# +1679 -0
  10. data/ext/Makefile +180 -0
  11. data/ext/extconf.rb +40 -0
  12. data/ext/measure_allocations.h +58 -0
  13. data/ext/measure_cpu_time.h +152 -0
  14. data/ext/measure_gc_runs.h +76 -0
  15. data/ext/measure_gc_time.h +57 -0
  16. data/ext/measure_memory.h +101 -0
  17. data/ext/measure_process_time.h +52 -0
  18. data/ext/measure_wall_time.h +53 -0
  19. data/ext/mingw/Rakefile +23 -0
  20. data/ext/mingw/build.rake +38 -0
  21. data/ext/ruby_prof.c +1707 -0
  22. data/ext/ruby_prof.e +19984 -0
  23. data/ext/ruby_prof.h +188 -0
  24. data/ext/vc/ruby_prof.sln +20 -0
  25. data/ext/vc/ruby_prof.vcproj +241 -0
  26. data/ext/version.h +4 -0
  27. data/lib/ruby-prof.rb +48 -0
  28. data/lib/ruby-prof/abstract_printer.rb +41 -0
  29. data/lib/ruby-prof/aggregate_call_info.rb +62 -0
  30. data/lib/ruby-prof/call_info.rb +47 -0
  31. data/lib/ruby-prof/call_tree_printer.rb +84 -0
  32. data/lib/ruby-prof/flat_printer.rb +79 -0
  33. data/lib/ruby-prof/graph_html_printer.rb +256 -0
  34. data/lib/ruby-prof/graph_html_printer.rb.orig +256 -0
  35. data/lib/ruby-prof/graph_html_printer.rb.rej +34 -0
  36. data/lib/ruby-prof/graph_printer.rb +164 -0
  37. data/lib/ruby-prof/graph_printer.rb.orig +164 -0
  38. data/lib/ruby-prof/method_info.rb +111 -0
  39. data/lib/ruby-prof/task.rb +146 -0
  40. data/lib/ruby-prof/test.rb +148 -0
  41. data/lib/unprof.rb +8 -0
  42. data/rails/environment/profile.rb +24 -0
  43. data/rails/example/example_test.rb +9 -0
  44. data/rails/profile_test_helper.rb +21 -0
  45. data/test/aggregate_test.rb +121 -0
  46. data/test/basic_test.rb +283 -0
  47. data/test/duplicate_names_test.rb +32 -0
  48. data/test/exceptions_test.rb +15 -0
  49. data/test/exclude_threads_test.rb +54 -0
  50. data/test/line_number_test.rb +73 -0
  51. data/test/measurement_test.rb +121 -0
  52. data/test/module_test.rb +54 -0
  53. data/test/no_method_class_test.rb +13 -0
  54. data/test/prime.rb +58 -0
  55. data/test/prime_test.rb +13 -0
  56. data/test/printers_test.rb +71 -0
  57. data/test/recursive_test.rb +254 -0
  58. data/test/singleton_test.rb +37 -0
  59. data/test/stack_test.rb +138 -0
  60. data/test/start_stop_test.rb +95 -0
  61. data/test/test_suite.rb +23 -0
  62. data/test/thread_test.rb +159 -0
  63. data/test/unique_call_path_test.rb +206 -0
  64. metadata +124 -0
@@ -0,0 +1,256 @@
1
+ require 'ruby-prof/abstract_printer'
2
+ require 'erb'
3
+
4
+ module RubyProf
5
+ # Generates graph[link:files/examples/graph_html.html] profile reports as html.
6
+ # To use the grap html printer:
7
+ #
8
+ # result = RubyProf.profile do
9
+ # [code to profile]
10
+ # end
11
+ #
12
+ # printer = RubyProf::GraphHtmlPrinter.new(result)
13
+ # printer.print(STDOUT, :min_percent=>0)
14
+ #
15
+ # The constructor takes two arguments. The first is
16
+ # a RubyProf::Result object generated from a profiling
17
+ # run. The second is the minimum %total (the methods
18
+ # total time divided by the overall total time) that
19
+ # a method must take for it to be printed out in
20
+ # the report. Use this parameter to eliminate methods
21
+ # that are not important to the overall profiling results.
22
+
23
+ class GraphHtmlPrinter < AbstractPrinter
24
+ include ERB::Util
25
+
26
+ PERCENTAGE_WIDTH = 8
27
+ TIME_WIDTH = 10
28
+ CALL_WIDTH = 20
29
+
30
+ # Create a GraphPrinter. Result is a RubyProf::Result
31
+ # object generated from a profiling run.
32
+ def initialize(result)
33
+ super(result)
34
+ @thread_times = Hash.new
35
+ calculate_thread_times
36
+ end
37
+
38
+ # Print a graph html report to the provided output.
39
+ #
40
+ # output - Any IO oject, including STDOUT or a file.
41
+ # The default value is STDOUT.
42
+ #
43
+ # options - Hash of print options. See #setup_options
44
+ # for more information.
45
+ #
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
57
+
58
+ # These methods should be private but then ERB doesn't
59
+ # work. Turn off RDOC though
60
+ #--
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
73
+
74
+ def thread_time(thread_id)
75
+ @thread_times[thread_id]
76
+ end
77
+
78
+ def total_percent(thread_id, method)
79
+ overall_time = self.thread_time(thread_id)
80
+ (method.total_time/overall_time) * 100
81
+ end
82
+
83
+ def self_percent(method)
84
+ overall_time = self.thread_time(method.thread_id)
85
+ (method.self_time/overall_time) * 100
86
+ end
87
+
88
+ # Creates a link to a method. Note that we do not create
89
+ # links to methods which are under the min_perecent
90
+ # specified by the user, since they will not be
91
+ # printed out.
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
101
+
102
+ def method_href(thread_id, method)
103
+ h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread_id.to_s)
104
+ end
105
+
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
+ width: 100%;
119
+ }
120
+
121
+ th {
122
+ text-align: center;
123
+ border-top: 1px solid #FB7A31;
124
+ border-bottom: 1px solid #FB7A31;
125
+ background: #FFC;
126
+ padding: 0.3em;
127
+ border-left: 1px solid silver;
128
+ }
129
+
130
+ tr.break td {
131
+ border: 0;
132
+ border-top: 1px solid #FB7A31;
133
+ padding: 0;
134
+ margin: 0;
135
+ }
136
+
137
+ tr.method td {
138
+ font-weight: bold;
139
+ }
140
+
141
+ td {
142
+ padding: 0.3em;
143
+ }
144
+
145
+ td:first-child {
146
+ width: 190px;
147
+ }
148
+
149
+ td {
150
+ border-left: 1px solid #CCC;
151
+ text-align: center;
152
+ }
153
+
154
+ .method_name {
155
+ text-align: left;
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.aggregate_parents
202
+ next unless caller.parent
203
+ next if min_time && caller.total_time < min_time %>
204
+ <tr>
205
+ <td>&nbsp;</td>
206
+ <td>&nbsp;</td>
207
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.total_time) %></td>
208
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.self_time) %></td>
209
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.wait_time) %></td>
210
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.children_time) %></td>
211
+ <% called = "#{caller.called}/#{method.called}" %>
212
+ <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td>
213
+ <td class="method_name"><%= create_link(thread_id, caller.parent.target) %></td>
214
+ <td><a href="file://<%=h srcfile=File.expand_path(caller.parent.target.source_file) %>#line=<%= linenum=caller.line %>" title="<%=h srcfile %>:<%= linenum %>"><%= caller.line %></a></td>
215
+ </tr>
216
+ <% end %>
217
+
218
+ <tr class="method">
219
+ <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage) %></td>
220
+ <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", self_percentage) %></td>
221
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.total_time) %></td>
222
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.self_time) %></td>
223
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.wait_time) %></td>
224
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.children_time) %></td>
225
+ <td><%= sprintf("%#{CALL_WIDTH}i", method.called) %></td>
226
+ <td class="method_name"><a name="<%= method_href(thread_id, method) %>"><%= h method.full_name %></a></td>
227
+ <td><a href="file://<%=h srcfile=File.expand_path(method.source_file) %>#line=<%= linenum=method.line %>" title="<%=h srcfile %>:<%= linenum %>"><%= method.line %></a></td>
228
+ </tr>
229
+
230
+ <!-- Children -->
231
+ <% for callee in method.aggregate_children %>
232
+ <% next if min_time && callee.total_time < min_time %>
233
+ <tr>
234
+ <td>&nbsp;</td>
235
+ <td>&nbsp;</td>
236
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.total_time) %></td>
237
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.self_time) %></td>
238
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.wait_time) %></td>
239
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.children_time) %></td>
240
+ <% called = "#{callee.called}/#{callee.target.called}" %>
241
+ <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td>
242
+ <td class="method_name"><%= create_link(thread_id, callee.target) %></td>
243
+ <td><a href="file://<%=h srcfile=File.expand_path(method.source_file) %>#line=<%= linenum=callee.line %>" title="<%=h srcfile %>:<%= linenum %>"><%= callee.line %></a></td>
244
+ </tr>
245
+ <% end %>
246
+ <!-- Create divider row -->
247
+ <tr class="break"><td colspan="9"></td></tr>
248
+ <% end %>
249
+ </table>
250
+ <% end %>
251
+ </body>
252
+ </html>'
253
+ end
254
+ end
255
+ end
256
+
@@ -0,0 +1,34 @@
1
+ ***************
2
+ *** 198,204 ****
3
+ self_percentage = (method.self_time/total_time) * 100 %>
4
+
5
+ <!-- Parents -->
6
+ - <% for caller in method.aggregate_parents.sort_by(&:total_time)
7
+ next unless caller.parent
8
+ next if min_time && caller.total_time < min_time %>
9
+ <tr>
10
+ --- 198,204 ----
11
+ self_percentage = (method.self_time/total_time) * 100 %>
12
+
13
+ <!-- Parents -->
14
+ + <% for caller in method.aggregate_parents
15
+ next unless caller.parent
16
+ next if min_time && caller.total_time < min_time %>
17
+ <tr>
18
+ ***************
19
+ *** 228,234 ****
20
+ </tr>
21
+
22
+ <!-- Children -->
23
+ - <% for callee in method.aggregate_children.sort_by(&:total_time).reverse %>
24
+ <% next if min_time && callee.total_time < min_time %>
25
+ <tr>
26
+ <td>&nbsp;</td>
27
+ --- 228,234 ----
28
+ </tr>
29
+
30
+ <!-- Children -->
31
+ + <% for callee in method.aggregate_children %>
32
+ <% next if min_time && callee.total_time < min_time %>
33
+ <tr>
34
+ <td>&nbsp;</td>
@@ -0,0 +1,164 @@
1
+ require 'ruby-prof/abstract_printer'
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, 5)
12
+ # printer.print(STDOUT, 0)
13
+ #
14
+ # The constructor takes two arguments. The first is
15
+ # a RubyProf::Result object generated from a profiling
16
+ # run. The second is the minimum %total (the methods
17
+ # total time divided by the overall total time) that
18
+ # a method must take for it to be printed out in
19
+ # the report. Use this parameter to eliminate methods
20
+ # that are not important to the overall profiling results.
21
+
22
+ class GraphPrinter < AbstractPrinter
23
+ PERCENTAGE_WIDTH = 8
24
+ TIME_WIDTH = 10
25
+ CALL_WIDTH = 17
26
+
27
+ # Create a GraphPrinter. Result is a RubyProf::Result
28
+ # object generated from a profiling run.
29
+ def initialize(result)
30
+ super(result)
31
+ @thread_times = Hash.new
32
+ calculate_thread_times
33
+ end
34
+
35
+ def calculate_thread_times
36
+ # Cache thread times since this is an expensive
37
+ # operation with the required sorting
38
+ @result.threads.each do |thread_id, methods|
39
+ top = methods.sort.last
40
+
41
+ thread_time = 0.01
42
+ thread_time = top.total_time if top.total_time > 0
43
+
44
+ @thread_times[thread_id] = thread_time
45
+ end
46
+ end
47
+
48
+ # Print a graph report to the provided output.
49
+ #
50
+ # output - Any IO oject, including STDOUT or a file.
51
+ # The default value is STDOUT.
52
+ #
53
+ # options - Hash of print options. See #setup_options
54
+ # for more information.
55
+ #
56
+ def print(output = STDOUT, options = {})
57
+ @output = output
58
+ setup_options(options)
59
+ print_threads
60
+ end
61
+
62
+ private
63
+ def print_threads
64
+ # sort assumes that spawned threads have higher object_ids
65
+ @result.threads.sort.each do |thread_id, methods|
66
+ print_methods(thread_id, methods)
67
+ @output << "\n" * 2
68
+ end
69
+ end
70
+
71
+ def print_methods(thread_id, methods)
72
+ # Sort methods from longest to shortest total time
73
+ methods = methods.sort
74
+
75
+ toplevel = methods.last
76
+ total_time = toplevel.total_time
77
+ if total_time == 0
78
+ total_time = 0.01
79
+ end
80
+
81
+ print_heading(thread_id)
82
+
83
+ # Print each method in total time order
84
+ methods.reverse_each do |method|
85
+ total_percentage = (method.total_time/total_time) * 100
86
+ self_percentage = (method.self_time/total_time) * 100
87
+
88
+ next if total_percentage < min_percent
89
+
90
+ @output << "-" * 80 << "\n"
91
+
92
+ print_parents(thread_id, method)
93
+
94
+ # 1 is for % sign
95
+ @output << sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage)
96
+ @output << sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", self_percentage)
97
+ @output << sprintf("%#{TIME_WIDTH}.2f", method.total_time)
98
+ @output << sprintf("%#{TIME_WIDTH}.2f", method.self_time)
99
+ @output << sprintf("%#{TIME_WIDTH}.2f", method.wait_time)
100
+ @output << sprintf("%#{TIME_WIDTH}.2f", method.children_time)
101
+ @output << sprintf("%#{CALL_WIDTH}i", method.called)
102
+ @output << sprintf(" %s", method_name(method))
103
+ if print_file
104
+ @output << sprintf(" %s:%s", method.source_file, method.line)
105
+ end
106
+ @output << "\n"
107
+
108
+ print_children(method)
109
+ end
110
+ end
111
+
112
+ def print_heading(thread_id)
113
+ @output << "Thread ID: #{thread_id}\n"
114
+ @output << "Total Time: #{@thread_times[thread_id]}\n"
115
+ @output << "\n"
116
+
117
+ # 1 is for % sign
118
+ @output << sprintf("%#{PERCENTAGE_WIDTH}s", "%total")
119
+ @output << sprintf("%#{PERCENTAGE_WIDTH}s", "%self")
120
+ @output << sprintf("%#{TIME_WIDTH}s", "total")
121
+ @output << sprintf("%#{TIME_WIDTH}s", "self")
122
+ @output << sprintf("%#{TIME_WIDTH}s", "wait")
123
+ @output << sprintf("%#{TIME_WIDTH}s", "child")
124
+ @output << sprintf("%#{CALL_WIDTH}s", "calls")
125
+ @output << " Name"
126
+ @output << "\n"
127
+ end
128
+
129
+ def print_parents(thread_id, method)
130
+ method.aggregate_parents.sort_by(&:total_time).each do |caller|
131
+ next unless caller.parent
132
+ @output << " " * 2 * PERCENTAGE_WIDTH
133
+ @output << sprintf("%#{TIME_WIDTH}.2f", caller.total_time)
134
+ @output << sprintf("%#{TIME_WIDTH}.2f", caller.self_time)
135
+ @output << sprintf("%#{TIME_WIDTH}.2f", caller.wait_time)
136
+ @output << sprintf("%#{TIME_WIDTH}.2f", caller.children_time)
137
+
138
+ call_called = "#{caller.called}/#{method.called}"
139
+ @output << sprintf("%#{CALL_WIDTH}s", call_called)
140
+ @output << sprintf(" %s", caller.parent.target.full_name)
141
+ @output << "\n"
142
+ end
143
+ end
144
+
145
+ def print_children(method)
146
+ method.aggregate_children.sort_by(&:total_time).reverse.each do |child|
147
+ # Get children method
148
+
149
+ @output << " " * 2 * PERCENTAGE_WIDTH
150
+
151
+ @output << sprintf("%#{TIME_WIDTH}.2f", child.total_time)
152
+ @output << sprintf("%#{TIME_WIDTH}.2f", child.self_time)
153
+ @output << sprintf("%#{TIME_WIDTH}.2f", child.wait_time)
154
+ @output << sprintf("%#{TIME_WIDTH}.2f", child.children_time)
155
+
156
+ call_called = "#{child.called}/#{child.target.called}"
157
+ @output << sprintf("%#{CALL_WIDTH}s", call_called)
158
+ @output << sprintf(" %s", child.target.full_name)
159
+ @output << "\n"
160
+ end
161
+ end
162
+ end
163
+ end
164
+