ruby-prof 0.11.0.rc1-x86-mingw32 → 0.11.0.rc2-x86-mingw32

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 (79) hide show
  1. data/CHANGES +20 -5
  2. data/README.rdoc +10 -3
  3. data/ext/ruby_prof/rp_call_info.c +108 -79
  4. data/ext/ruby_prof/rp_call_info.h +1 -0
  5. data/ext/ruby_prof/rp_measure_cpu_time.c +111 -111
  6. data/ext/ruby_prof/rp_measure_gc_runs.c +1 -1
  7. data/ext/ruby_prof/rp_measure_memory.c +1 -1
  8. data/ext/ruby_prof/rp_measure_process_time.c +71 -71
  9. data/ext/ruby_prof/rp_measure_wall_time.c +1 -1
  10. data/ext/ruby_prof/rp_method.c +143 -73
  11. data/ext/ruby_prof/rp_method.h +7 -4
  12. data/ext/ruby_prof/rp_stack.c +16 -1
  13. data/ext/ruby_prof/rp_stack.h +4 -1
  14. data/ext/ruby_prof/rp_thread.c +165 -35
  15. data/ext/ruby_prof/rp_thread.h +8 -2
  16. data/ext/ruby_prof/ruby_prof.c +164 -171
  17. data/ext/ruby_prof/ruby_prof.h +53 -54
  18. data/ext/ruby_prof/vc/ruby_prof.sln +26 -0
  19. data/ext/ruby_prof/vc/ruby_prof.vcxproj +109 -0
  20. data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +105 -0
  21. data/lib/1.8/ruby_prof.so +0 -0
  22. data/lib/1.9/ruby_prof.so +0 -0
  23. data/lib/ruby-prof/aggregate_call_info.rb +9 -7
  24. data/lib/ruby-prof/call_info.rb +2 -27
  25. data/lib/ruby-prof/call_info_visitor.rb +42 -0
  26. data/lib/ruby-prof/{empty.png → images/empty.png} +0 -0
  27. data/lib/ruby-prof/{minus.png → images/minus.png} +0 -0
  28. data/lib/ruby-prof/{plus.png → images/plus.png} +0 -0
  29. data/lib/ruby-prof/method_info.rb +13 -15
  30. data/lib/ruby-prof/{abstract_printer.rb → printers/abstract_printer.rb} +36 -2
  31. data/lib/ruby-prof/printers/call_info_printer.rb +40 -0
  32. data/lib/ruby-prof/{call_stack_printer.rb → printers/call_stack_printer.rb} +11 -16
  33. data/lib/ruby-prof/{call_tree_printer.rb → printers/call_tree_printer.rb} +4 -4
  34. data/lib/ruby-prof/{dot_printer.rb → printers/dot_printer.rb} +11 -31
  35. data/lib/ruby-prof/{flat_printer.rb → printers/flat_printer.rb} +26 -35
  36. data/lib/ruby-prof/{flat_printer_with_line_numbers.rb → printers/flat_printer_with_line_numbers.rb} +14 -25
  37. data/lib/ruby-prof/printers/graph_html_printer.rb +248 -0
  38. data/lib/ruby-prof/{graph_printer.rb → printers/graph_printer.rb} +31 -73
  39. data/lib/ruby-prof/{multi_printer.rb → printers/multi_printer.rb} +0 -0
  40. data/lib/ruby-prof/profile.rb +27 -22
  41. data/lib/ruby-prof/rack.rb +22 -12
  42. data/ruby-prof.gemspec +58 -0
  43. data/test/aggregate_test.rb +6 -6
  44. data/test/call_info_visitor_test.rb +31 -0
  45. data/test/duplicate_names_test.rb +1 -1
  46. data/test/dynamic_method_test.rb +1 -1
  47. data/test/enumerable_test.rb +1 -1
  48. data/test/exclude_threads_test.rb +2 -2
  49. data/test/gc_test.rb +35 -0
  50. data/test/line_number_test.rb +2 -2
  51. data/test/measure_cpu_time_test.rb +5 -5
  52. data/test/measure_process_time_test.rb +5 -5
  53. data/test/measure_wall_time_test.rb +5 -5
  54. data/test/method_elimination_test.rb +3 -3
  55. data/test/module_test.rb +1 -1
  56. data/test/no_method_class_test.rb +1 -1
  57. data/test/printers_test.rb +16 -8
  58. data/test/recursive_test.rb +115 -91
  59. data/test/stack_test.rb +1 -1
  60. data/test/start_stop_test.rb +13 -13
  61. data/test/summarize_test.rb +48 -0
  62. data/test/test_suite.rb +1 -0
  63. data/test/thread_test.rb +16 -12
  64. data/test/unique_call_path_test.rb +10 -10
  65. metadata +65 -85
  66. data/lib/1.9/ruby_prof.exp +0 -0
  67. data/lib/1.9/ruby_prof.ilk +0 -0
  68. data/lib/1.9/ruby_prof.lib +0 -0
  69. data/lib/1.9/ruby_prof.pdb +0 -0
  70. data/lib/ruby-prof.rb +0 -70
  71. data/lib/ruby-prof/graph_html_printer.rb +0 -286
  72. data/lib/ruby-prof/symbol_to_proc.rb +0 -10
  73. data/lib/ruby_prof.exp +0 -0
  74. data/lib/ruby_prof.ilk +0 -0
  75. data/lib/ruby_prof.lib +0 -0
  76. data/lib/ruby_prof.pdb +0 -0
  77. data/lib/ruby_prof.so +0 -0
  78. data/lib/unprof.rb +0 -10
  79. data/test/do_nothing.rb +0 -0
@@ -12,21 +12,10 @@ module RubyProf
12
12
  # printer.print(STDOUT, {})
13
13
  #
14
14
  class FlatPrinterWithLineNumbers < FlatPrinter
15
+ def print_methods(thread)
16
+ total_time = thread.top_method.total_time
15
17
 
16
- def print_methods(thread_id, methods)
17
- # Get total time
18
- toplevel = methods.max
19
- total_time = toplevel.total_time
20
- if total_time == 0
21
- total_time = 0.01
22
- end
23
-
24
- methods = methods.sort_by(&sort_method).reverse
25
-
26
- @output << "Thread ID: %d\n" % thread_id
27
- @output << "Total: %0.6f\n" % total_time
28
- @output << "\n"
29
- @output << " %self total self wait child calls name\n"
18
+ methods = thread.methods.sort_by(&sort_method).reverse
30
19
  sum = 0
31
20
  methods.each do |method|
32
21
  self_percent = (method.self_time / total_time) * 100
@@ -36,15 +25,16 @@ module RubyProf
36
25
  #self_time_called = method.called > 0 ? method.self_time/method.called : 0
37
26
  #total_time_called = method.called > 0? method.total_time/method.called : 0
38
27
 
39
- @output << "%6.2f %8.2f %8.2f %8.2f %8.2f %8d %s " % [
40
- method.self_time / total_time * 100, # %self
41
- method.total_time, # total
42
- method.self_time, # self
43
- method.wait_time, # wait
44
- method.children_time, # children
45
- method.called, # calls
46
- method_name(method), # name
47
- ]
28
+ @output << "%6.2f %8.2f %8.2f %8.2f %8.2f %8d %s%s \n" % [
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
+ ]
48
38
  if method.source_file != 'ruby_runtime'
49
39
  @output << " %s:%s" % [File.expand_path(method.source_file), method.line]
50
40
  end
@@ -64,5 +54,4 @@ module RubyProf
64
54
  end
65
55
  end
66
56
  end
67
- end
68
-
57
+ end
@@ -0,0 +1,248 @@
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
+ PERCENTAGE_WIDTH = 8
28
+ TIME_WIDTH = 10
29
+ CALL_WIDTH = 20
30
+
31
+ def setup_options(options)
32
+ super(options)
33
+
34
+ filename = options[:filename]
35
+ template = filename ? File.read(filename).untaint : (options[:template] || self.template)
36
+ @erb = ERB.new(template, nil, nil)
37
+ @erb.filename = filename
38
+ end
39
+
40
+ def print(output = STDOUT, options = {})
41
+ @output = output
42
+ setup_options(options)
43
+ _erbout = @output
44
+ @output << @erb.result(binding)
45
+ end
46
+
47
+ # Creates a link to a method. Note that we do not create
48
+ # links to methods which are under the min_perecent
49
+ # specified by the user, since they will not be
50
+ # printed out.
51
+ def create_link(thread, method)
52
+ overall_time = thread.top_method.total_time
53
+ total_percent = (method.total_time/overall_time) * 100
54
+ if total_percent < min_percent
55
+ # Just return name
56
+ h method.full_name
57
+ else
58
+ href = '#' + method_href(thread, method)
59
+ "<a href=\"#{href}\">#{h method.full_name}</a>"
60
+ end
61
+ end
62
+
63
+ def method_href(thread, method)
64
+ h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread.id.to_s)
65
+ end
66
+
67
+ def file_link(path, linenum)
68
+ srcfile = File.expand_path(path)
69
+ if srcfile =~ /\/ruby_runtime$/
70
+ ""
71
+ else
72
+ if RUBY_PLATFORM =~ /darwin/
73
+ "<a href=\"txmt://open?url=file://#{h srcfile}&line=#{linenum}\" title=\"#{h srcfile}:#{linenum}\">#{linenum}</a>"
74
+ else
75
+ "<a href=\"file://#{h srcfile}##{linenum}\" title=\"#{h srcfile}:#{linenum}\">#{linenum}</a>"
76
+ end
77
+ end
78
+ end
79
+
80
+ def template
81
+ '
82
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
83
+ <html>
84
+ <head>
85
+ <style media="all" type="text/css">
86
+ table {
87
+ border-collapse: collapse;
88
+ border: 1px solid #CCC;
89
+ font-family: Verdana, Arial, Helvetica, sans-serif;
90
+ font-size: 9pt;
91
+ line-height: normal;
92
+ width: 100%;
93
+ }
94
+
95
+ th {
96
+ text-align: center;
97
+ border-top: 1px solid #FB7A31;
98
+ border-bottom: 1px solid #FB7A31;
99
+ background: #FFC;
100
+ padding: 0.3em;
101
+ border-left: 1px solid silver;
102
+ }
103
+
104
+ tr.break td {
105
+ border: 0;
106
+ border-top: 1px solid #FB7A31;
107
+ padding: 0;
108
+ margin: 0;
109
+ }
110
+
111
+ tr.method td {
112
+ font-weight: bold;
113
+ }
114
+
115
+ td {
116
+ padding: 0.3em;
117
+ }
118
+
119
+ td:first-child {
120
+ width: 190px;
121
+ }
122
+
123
+ td {
124
+ border-left: 1px solid #CCC;
125
+ text-align: center;
126
+ }
127
+
128
+ .method_name {
129
+ text-align: left;
130
+ }
131
+
132
+ tfoot td {
133
+ text-align: left;
134
+ }
135
+ </style>
136
+ </head>
137
+ <body>
138
+ <h1>Profile Report</h1>
139
+ <!-- Threads Table -->
140
+ <table>
141
+ <tr>
142
+ <th>Thread ID</th>
143
+ <th>Total Time</th>
144
+ </tr>
145
+ <% for thread in @result.threads %>
146
+ <tr>
147
+ <td><a href="#<%= thread.id %>"><%= thread.id %></a></td>
148
+ <td><%= thread.top_method.total_time %></td>
149
+ </tr>
150
+ <% end %>
151
+ </table>
152
+
153
+ <!-- Methods Tables -->
154
+ <% for thread in @result.threads
155
+ methods = thread.methods
156
+ total_time = thread.top_method.total_time %>
157
+ <h2><a name="<%= thread.id %>">Thread <%= thread.id %></a></h2>
158
+
159
+ <table>
160
+ <thead>
161
+ <tr>
162
+ <th><%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Total") %></th>
163
+ <th><%= sprintf("%#{PERCENTAGE_WIDTH}s", "%Self") %></th>
164
+ <th><%= sprintf("%#{TIME_WIDTH}s", "Total") %></th>
165
+ <th><%= sprintf("%#{TIME_WIDTH}s", "Self") %></th>
166
+ <th><%= sprintf("%#{TIME_WIDTH}s", "Wait") %></th>
167
+ <th><%= sprintf("%#{TIME_WIDTH+2}s", "Child") %></th>
168
+ <th><%= sprintf("%#{CALL_WIDTH}s", "Calls") %></th>
169
+ <th class="method_name">Name</th>
170
+ <th>Line</th>
171
+ </tr>
172
+ </thead>
173
+
174
+ <tbody>
175
+ <% min_time = @options[:min_time] || (@options[:nonzero] ? 0.005 : nil)
176
+ methods.sort_by(&sort_method).reverse_each do |method|
177
+ total_percentage = (method.total_time/total_time) * 100
178
+ next if total_percentage < min_percent
179
+ next if min_time && method.total_time < min_time
180
+ self_percentage = (method.self_time/total_time) * 100 %>
181
+
182
+ <!-- Parents -->
183
+ <% for caller in method.aggregate_parents.sort_by(&:total_time)
184
+ next unless caller.parent
185
+ next if min_time && caller.total_time < min_time %>
186
+ <tr>
187
+ <td>&nbsp;</td>
188
+ <td>&nbsp;</td>
189
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.total_time) %></td>
190
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.self_time) %></td>
191
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.wait_time) %></td>
192
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", caller.children_time) %></td>
193
+ <% called = "#{caller.called}/#{method.called}" %>
194
+ <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td>
195
+ <td class="method_name"><%= create_link(thread, caller.parent.target) %></td>
196
+ <td><%= file_link(caller.parent.target.source_file, caller.line) %></td>
197
+ </tr>
198
+ <% end %>
199
+
200
+ <tr class="method">
201
+ <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage) %></td>
202
+ <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", self_percentage) %></td>
203
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.total_time) %></td>
204
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.self_time) %></td>
205
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.wait_time) %></td>
206
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.children_time) %></td>
207
+ <td><%= sprintf("%#{CALL_WIDTH}i", method.called) %></td>
208
+ <td class="method_name">
209
+ <a name="<%= method_href(thread, method) %>">
210
+ <%= method.recursive? ? "*" : " "%><%= h method.full_name %>
211
+ </a>
212
+ </td>
213
+ <td><%= file_link(method.source_file, method.line) %></td>
214
+ </tr>
215
+
216
+ <!-- Children -->
217
+ <% for callee in method.aggregate_children.sort_by(&:total_time).reverse %>
218
+ <% next if min_time && callee.total_time < min_time %>
219
+ <tr>
220
+ <td>&nbsp;</td>
221
+ <td>&nbsp;</td>
222
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.total_time) %></td>
223
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.self_time) %></td>
224
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.wait_time) %></td>
225
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", callee.children_time) %></td>
226
+ <% called = "#{callee.called}/#{callee.target.called}" %>
227
+ <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td>
228
+ <td class="method_name"><%= create_link(thread, callee.target) %></td>
229
+ <td><%= file_link(method.source_file, callee.line) %></td>
230
+ </tr>
231
+ <% end %>
232
+ <!-- Create divider row -->
233
+ <tr class="break"><td colspan="9"></td></tr>
234
+ <% end %>
235
+ </tbody>
236
+ <tfoot>
237
+ <tr>
238
+ <td colspan="9">* in front of method name means it is recursively called</td>
239
+ </tr>
240
+ </tfoot>
241
+ </table>
242
+ <% end %>
243
+ </body>
244
+ </html>'
245
+ end
246
+ end
247
+ end
248
+
@@ -18,60 +18,30 @@ module RubyProf
18
18
  TIME_WIDTH = 10
19
19
  CALL_WIDTH = 17
20
20
 
21
- # Create a GraphPrinter. Result is a RubyProf::Result
22
- # object generated from a profiling run.
23
- def initialize(result)
24
- super(result)
25
- @thread_times = Hash.new
26
- calculate_thread_times
27
- end
28
-
29
- def calculate_thread_times
30
- # Cache thread times since this is an expensive
31
- # operation with the required sorting
32
- @result.threads.each do |thread_id, methods|
33
- top = methods.max
34
-
35
- thread_time = [top.total_time, 0.01].max
36
-
37
- @thread_times[thread_id] = thread_time
38
- end
39
- end
21
+ private
40
22
 
41
- # Print a graph report to the provided output.
42
- #
43
- # output - Any IO oject, including STDOUT or a file.
44
- # The default value is STDOUT.
45
- #
46
- # options - Hash of print options. See #setup_options
47
- # for more information.
48
- #
49
- def print(output = STDOUT, options = {})
50
- @output = output
51
- setup_options(options)
52
- print_threads
53
- end
23
+ def print_header(thread)
24
+ @output << "Thread ID: #{thread.id}\n"
25
+ @output << "Total Time: #{thread.top_method.total_time}\n"
26
+ @output << "Sort by: #{sort_method}\n"
27
+ @output << "\n"
54
28
 
55
- private
56
- def print_threads
57
- # sort assumes that spawned threads have higher object_ids
58
- @result.threads.sort.each do |thread_id, methods|
59
- print_methods(thread_id, methods)
60
- @output << "\n" * 2
61
- end
29
+ # 1 is for % sign
30
+ @output << sprintf("%#{PERCENTAGE_WIDTH}s", "%total")
31
+ @output << sprintf("%#{PERCENTAGE_WIDTH}s", "%self")
32
+ @output << sprintf("%#{TIME_WIDTH}s", "total")
33
+ @output << sprintf("%#{TIME_WIDTH}s", "self")
34
+ @output << sprintf("%#{TIME_WIDTH}s", "wait")
35
+ @output << sprintf("%#{TIME_WIDTH}s", "child")
36
+ @output << sprintf("%#{CALL_WIDTH}s", "calls")
37
+ @output << " Name"
38
+ @output << "\n"
62
39
  end
63
40
 
64
- def print_methods(thread_id, methods)
41
+ def print_methods(thread)
42
+ total_time = thread.top_method.total_time
65
43
  # Sort methods from longest to shortest total time
66
- methods = methods.sort_by(&sort_method)
67
-
68
- toplevel = methods.last
69
- total_time = toplevel.total_time
70
- if total_time == 0
71
- total_time = 0.01
72
- end
73
-
74
- print_heading(thread_id)
44
+ methods = thread.methods.sort_by(&sort_method)
75
45
 
76
46
  # Print each method in total time order
77
47
  methods.reverse_each do |method|
@@ -82,7 +52,7 @@ module RubyProf
82
52
 
83
53
  @output << "-" * 80 << "\n"
84
54
 
85
- print_parents(thread_id, method)
55
+ print_parents(thread, method)
86
56
 
87
57
  # 1 is for % sign
88
58
  @output << sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage)
@@ -92,7 +62,8 @@ module RubyProf
92
62
  @output << sprintf("%#{TIME_WIDTH}.2f", method.wait_time)
93
63
  @output << sprintf("%#{TIME_WIDTH}.2f", method.children_time)
94
64
  @output << sprintf("%#{CALL_WIDTH}i", method.called)
95
- @output << sprintf(" %s", method_name(method))
65
+ @output << sprintf(" %s", method.recursive? ? "*" : " ")
66
+ @output << sprintf("%s", method_name(method))
96
67
  if print_file
97
68
  @output << sprintf(" %s:%s", method.source_file, method.line)
98
69
  end
@@ -102,24 +73,7 @@ module RubyProf
102
73
  end
103
74
  end
104
75
 
105
- def print_heading(thread_id)
106
- @output << "Thread ID: #{thread_id}\n"
107
- @output << "Total Time: #{@thread_times[thread_id]}\n"
108
- @output << "\n"
109
-
110
- # 1 is for % sign
111
- @output << sprintf("%#{PERCENTAGE_WIDTH}s", "%total")
112
- @output << sprintf("%#{PERCENTAGE_WIDTH}s", "%self")
113
- @output << sprintf("%#{TIME_WIDTH}s", "total")
114
- @output << sprintf("%#{TIME_WIDTH}s", "self")
115
- @output << sprintf("%#{TIME_WIDTH}s", "wait")
116
- @output << sprintf("%#{TIME_WIDTH}s", "child")
117
- @output << sprintf("%#{CALL_WIDTH}s", "calls")
118
- @output << " Name"
119
- @output << "\n"
120
- end
121
-
122
- def print_parents(thread_id, method)
76
+ def print_parents(thread, method)
123
77
  method.aggregate_parents.sort_by(&:total_time).each do |caller|
124
78
  next unless caller.parent
125
79
  @output << " " * 2 * PERCENTAGE_WIDTH
@@ -130,7 +84,7 @@ module RubyProf
130
84
 
131
85
  call_called = "#{caller.called}/#{method.called}"
132
86
  @output << sprintf("%#{CALL_WIDTH}s", call_called)
133
- @output << sprintf(" %s", caller.parent.target.full_name)
87
+ @output << sprintf(" %s", caller.parent.target.full_name)
134
88
  @output << "\n"
135
89
  end
136
90
  end
@@ -148,10 +102,14 @@ module RubyProf
148
102
 
149
103
  call_called = "#{child.called}/#{child.target.called}"
150
104
  @output << sprintf("%#{CALL_WIDTH}s", call_called)
151
- @output << sprintf(" %s", child.target.full_name)
105
+ @output << sprintf(" %s", child.target.full_name)
152
106
  @output << "\n"
153
107
  end
154
108
  end
155
- end
156
- end
157
109
 
110
+ def print_footer(thread)
111
+ @output << "\n"
112
+ @output << "* in front of method name means it is recursively called\n"
113
+ end
114
+ end
115
+ end