ruby-prof 0.4.0-mswin32

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 (57) hide show
  1. data/CHANGES +17 -0
  2. data/LICENSE +23 -0
  3. data/README +220 -0
  4. data/Rakefile +141 -0
  5. data/bin/ruby-prof +154 -0
  6. data/doc/classes/RubyProf.html +563 -0
  7. data/doc/classes/RubyProf/CallInfo.html +274 -0
  8. data/doc/classes/RubyProf/FlatPrinter.html +207 -0
  9. data/doc/classes/RubyProf/GraphHtmlPrinter.html +538 -0
  10. data/doc/classes/RubyProf/GraphPrinter.html +240 -0
  11. data/doc/classes/RubyProf/MethodInfo.html +556 -0
  12. data/doc/classes/RubyProf/ProfileTask.html +395 -0
  13. data/doc/classes/RubyProf/Result.html +234 -0
  14. data/doc/created.rid +1 -0
  15. data/doc/files/LICENSE.html +142 -0
  16. data/doc/files/README.html +376 -0
  17. data/doc/files/bin/ruby-prof.html +143 -0
  18. data/doc/files/examples/flat_txt.html +187 -0
  19. data/doc/files/examples/graph_html.html +948 -0
  20. data/doc/files/examples/graph_txt.html +305 -0
  21. data/doc/files/ext/ruby_prof_c.html +101 -0
  22. data/doc/files/lib/ruby-prof/flat_printer_rb.html +101 -0
  23. data/doc/files/lib/ruby-prof/graph_html_printer_rb.html +108 -0
  24. data/doc/files/lib/ruby-prof/graph_printer_rb.html +101 -0
  25. data/doc/files/lib/ruby-prof/profiletask_rb.html +109 -0
  26. data/doc/files/lib/ruby-prof_rb.html +111 -0
  27. data/doc/files/lib/unprof_rb.html +108 -0
  28. data/doc/fr_class_index.html +34 -0
  29. data/doc/fr_file_index.html +39 -0
  30. data/doc/fr_method_index.html +67 -0
  31. data/doc/index.html +24 -0
  32. data/doc/rdoc-style.css +208 -0
  33. data/examples/flat.txt +57 -0
  34. data/examples/graph.html +827 -0
  35. data/examples/graph.txt +171 -0
  36. data/ext/extconf.rb +19 -0
  37. data/ext/ruby_prof.c +1433 -0
  38. data/lib/ruby-prof.rb +38 -0
  39. data/lib/ruby-prof/flat_printer.rb +76 -0
  40. data/lib/ruby-prof/graph_html_printer.rb +227 -0
  41. data/lib/ruby-prof/graph_printer.rb +142 -0
  42. data/lib/ruby-prof/profiletask.rb +150 -0
  43. data/lib/ruby_prof.so +0 -0
  44. data/lib/unprof.rb +8 -0
  45. data/test/basic_test.rb +141 -0
  46. data/test/clock_mode_test.rb +73 -0
  47. data/test/module_test.rb +45 -0
  48. data/test/prime.rb +58 -0
  49. data/test/prime_test.rb +24 -0
  50. data/test/printers_test.rb +28 -0
  51. data/test/recursive_test.rb +55 -0
  52. data/test/test.rb +3 -0
  53. data/test/test_helper.rb +45 -0
  54. data/test/test_suite.rb +9 -0
  55. data/test/thread_test.rb +32 -0
  56. data/test/timing_test.rb +90 -0
  57. metadata +122 -0
data/lib/ruby-prof.rb ADDED
@@ -0,0 +1,38 @@
1
+ require "ruby_prof.so"
2
+
3
+ require "ruby-prof/flat_printer"
4
+ require "ruby-prof/graph_printer"
5
+ require "ruby-prof/graph_html_printer"
6
+
7
+ module RubyProf
8
+ # See if the user specified the clock mode via
9
+ # the RUBY_PROF_CLOCK_MODE environment variable
10
+ def self.figure_clock_mode
11
+ case ENV["RUBY_PROF_CLOCK_MODE"]
12
+ when "wall" || "wall_time"
13
+ RubyProf.clock_mode = RubyProf::WALL_TIME
14
+ when "cpu" || "cpu_time"
15
+ if ENV.key?("RUBY_PROF_CPU_FREQUENCY")
16
+ RubyProf.cpu_frequency = ENV["RUBY_PROF_CPU_FREQUENCY"].to_f
17
+ else
18
+ begin
19
+ open("/proc/cpuinfo") do |f|
20
+ f.each_line do |line|
21
+ s = line.slice(/cpu MHz\s*:\s*(.*)/, 1)
22
+ if s
23
+ RubyProf.cpu_frequency = s.to_f * 1000000
24
+ break
25
+ end
26
+ end
27
+ end
28
+ rescue Errno::ENOENT
29
+ end
30
+ end
31
+ RubyProf.clock_mode = RubyProf::CPU_TIME
32
+ else
33
+ RubyProf.clock_mode = RubyProf::PROCESS_TIME
34
+ end
35
+ end
36
+ end
37
+
38
+ RubyProf::figure_clock_mode
@@ -0,0 +1,76 @@
1
+ module RubyProf
2
+ # Generates flat[link:files/examples/flat_txt.html] profile reports as text.
3
+ # To use the flat printer:
4
+ #
5
+ # result = RubyProf.profile do
6
+ # [code to profile]
7
+ # end
8
+ #
9
+ # printer = RubyProf::FlatPrinter.new(result)
10
+ # printer.print(STDOUT, 0)
11
+ #
12
+ class FlatPrinter
13
+ # Create a FlatPrinter. Result is a RubyProf::Result
14
+ # object generated from a profiling run.
15
+ def initialize(result)
16
+ @result = result
17
+ end
18
+
19
+ # Print a flat profile report to the provided output.
20
+ #
21
+ # output - Any IO oject, including STDOUT or a file.
22
+ # The default value is STDOUT.
23
+ #
24
+ # min_percent - The minimum %self (the methods
25
+ # self time divided by the overall total time) that
26
+ # a method must take for it to be printed out in
27
+ # the report. Default value is 0.
28
+ def print(output = STDOUT, min_percent = 0)
29
+ @min_percent = min_percent
30
+ @output = output
31
+ print_threads
32
+ end
33
+
34
+ private
35
+
36
+ def print_threads
37
+ # sort assumes that spawned threads have higher object_ids
38
+ @result.threads.sort.each do |thread_id, methods|
39
+ print_methods(thread_id, methods)
40
+ @output << "\n" * 2
41
+ end
42
+ end
43
+
44
+ def print_methods(thread_id, methods)
45
+ toplevel = @result.toplevel(thread_id)
46
+ total_time = toplevel.total_time
47
+
48
+ methods = methods.values.sort do |method1, method2|
49
+ method1.self_time <=> method2.self_time
50
+ end
51
+ methods.reverse!
52
+
53
+ sum = 0
54
+ @output << "Thread ID: " << thread_id << "\n"
55
+ @output << " %self cumulative total self children calls self/call total/call name\n"
56
+
57
+ for method in methods
58
+ self_percent = (method.self_time / total_time) * 100
59
+ next if self_percent < @min_percent
60
+
61
+ sum += method.self_time
62
+ @output.printf("%6.2f %8.2f %8.2f %8.2f %8.2f %8d %8.2f %8.2f %s\n",
63
+ method.self_time / total_time * 100, # %self
64
+ sum, # cumulative
65
+ method.total_time, # total
66
+ method.self_time, # self
67
+ method.children_time, # children
68
+ method.called, # calls
69
+ method.self_time / method.called, # self/call
70
+ method.total_time / method.called, # total/call
71
+ method.name) # name
72
+ end
73
+ end
74
+ end
75
+ end
76
+
@@ -0,0 +1,227 @@
1
+ require "erb"
2
+
3
+ module RubyProf
4
+ # Generates graph[link:files/examples/graph_html.html] profile reports as html.
5
+ # To use the grap html printer:
6
+ #
7
+ # result = RubyProf.profile do
8
+ # [code to profile]
9
+ # end
10
+ #
11
+ # printer = RubyProf::GraphHtmlPrinter.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 GraphHtmlPrinter
23
+ PERCENTAGE_WIDTH = 8
24
+ TIME_WIDTH = 10
25
+ CALL_WIDTH = 20
26
+
27
+ # Create a GraphPrinter. Result is a RubyProf::Result
28
+ # object generated from a profiling run.
29
+ def initialize(result)
30
+ @result = result
31
+ end
32
+
33
+ # Print a graph html report to the provided output.
34
+ #
35
+ # output - Any IO oject, including STDOUT or a file.
36
+ # The default value is STDOUT.
37
+ #
38
+ # min_percent - The minimum %total (the methods
39
+ # total time divided by the overall total time) that
40
+ # a method must take for it to be printed out in
41
+ # the report. Default value is 0.
42
+ def print(output = STDOUT, min_percent = 0)
43
+ @output = output
44
+ @min_percent = min_percent
45
+
46
+ _erbout = @output
47
+ erb = ERB.new(template, nil, nil)
48
+ @output << erb.result(binding)
49
+ end
50
+
51
+ # These methods should be private but then ERB doesn't
52
+ # work. Turn off RDOC though
53
+ #--
54
+ def total_time(thread_id)
55
+ toplevel = @result.toplevel(thread_id)
56
+ total_time = toplevel.total_time
57
+ total_time = 0.01 if total_time == 0
58
+ return total_time
59
+ end
60
+
61
+ def total_percent(method)
62
+ overall_time = self.total_time(method.thread_id)
63
+ (method.total_time/overall_time) * 100
64
+ end
65
+
66
+ def self_percent(method)
67
+ overall_time = self.total_time(method.thread_id)
68
+ (method.self_time/overall_time) * 100
69
+ end
70
+
71
+ # Creates a link to a method. Note that we do not create
72
+ # links to methods which are under the min_perecent
73
+ # specified by the user, since they will not be
74
+ # printed out.
75
+ def create_link(thread_id, name)
76
+ # Get method
77
+ method = @result.threads[thread_id][name]
78
+
79
+ if self.total_percent(method) < @min_percent
80
+ # Just return name
81
+ name
82
+ else
83
+ # Create link
84
+ "<a href=\"##{link_name(thread_id, name)}\">#{name}</a>"
85
+ end
86
+ end
87
+
88
+ def link_name(thread_id, name)\
89
+ name.gsub(/[><#\.\?=:]/,"_") + "_" + thread_id.to_s
90
+ end
91
+
92
+ def template
93
+ '
94
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
95
+ <html>
96
+ <head>
97
+ <style media="all" type="text/css">
98
+ table {
99
+ border-collapse: collapse;
100
+ border: 1px solid #CCC;
101
+ font-family: Verdana, Arial, Helvetica, sans-serif;
102
+ font-size: 9pt;
103
+ line-height: normal;
104
+ }
105
+
106
+ th {
107
+ text-align: center;
108
+ border-top: 1px solid #FB7A31;
109
+ border-bottom: 1px solid #FB7A31;
110
+ background: #FFC;
111
+ padding: 0.3em;
112
+ border-left: 1px solid silver;
113
+ }
114
+
115
+ tr.break td {
116
+ border: 0;
117
+ border-top: 1px solid #FB7A31;
118
+ padding: 0;
119
+ margin: 0;
120
+ }
121
+
122
+ tr.method td {
123
+ font-weight: bold;
124
+ }
125
+
126
+ td {
127
+ padding: 0.3em;
128
+ }
129
+
130
+ td:first-child {
131
+ width: 190px;
132
+ }
133
+
134
+ td {
135
+ border-left: 1px solid #CCC;
136
+ text-align: center;
137
+ }
138
+ </style>
139
+ </head>
140
+ <body>
141
+ <h1>Profile Report</h1>
142
+ <!-- Threads Table -->
143
+ <table>
144
+ <tr>
145
+ <th>Thread ID</th>
146
+ <th>Total Time</th>
147
+ </tr>
148
+ <% for thread_id, methods in @result.threads %>
149
+ <tr>
150
+ <td><a href="#<%= thread_id %>"><%= thread_id %></a></td>
151
+ <td><%= @result.toplevel(thread_id).total_time %></td>
152
+ </tr>
153
+ <% end %>
154
+ </table>
155
+
156
+ <!-- Methods Tables -->
157
+ <% for thread_id, methods in @result.threads %>
158
+ <h2><a name="<%= thread_id %>">Thread <%= thread_id %></a></h2>
159
+
160
+ <table>
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+2}s", "Children") %></th>
167
+ <th><%= sprintf("%#{CALL_WIDTH}s", "Calls") %></th>
168
+ <th>Name</th>
169
+ </tr>
170
+
171
+ <% methods = methods.values.sort.reverse %>
172
+ <% for method in methods %>
173
+ <% method_total_percent = self.total_percent(method) %>
174
+ <% next if method_total_percent < @min_percent %>
175
+ <% method_self_percent = self.self_percent(method) %>
176
+
177
+ <!-- Parents -->
178
+ <% for name, call_info in method.parents %>
179
+ <tr>
180
+ <td>&nbsp;</td>
181
+ <td>&nbsp;</td>
182
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", call_info.total_time) %></td>
183
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", call_info.self_time) %></td>
184
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", call_info.children_time) %></td>
185
+ <% called = "#{call_info.called}/#{method.called}" %>
186
+ <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td>
187
+ <td><%= create_link(thread_id, name) %></td>
188
+ </tr>
189
+ <% end %>
190
+
191
+ <tr class="method">
192
+ <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", method_total_percent) %></td>
193
+ <td><%= sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", method_self_percent) %></td>
194
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.total_time) %></td>
195
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.self_time) %></td>
196
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", method.children_time) %></td>
197
+ <td><%= sprintf("%#{CALL_WIDTH}i", method.called) %></td>
198
+ <td><a name="<%= link_name(thread_id, method.name) %>"><%= method.name %></a></td>
199
+ </tr>
200
+
201
+ <!-- Children -->
202
+ <% for name, call_info in method.children %>
203
+ <% methods = @result.threads[thread_id] %>
204
+ <% child = methods[name] %>
205
+
206
+ <tr>
207
+ <td>&nbsp;</td>
208
+ <td>&nbsp;</td>
209
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", call_info.total_time) %></td>
210
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", call_info.self_time) %></td>
211
+ <td><%= sprintf("%#{TIME_WIDTH}.2f", call_info.children_time) %></td>
212
+ <% called = "#{call_info.called}/#{child.called}" %>
213
+ <td><%= sprintf("%#{CALL_WIDTH}s", called) %></td>
214
+ <td><%= create_link(thread_id, name) %></td>
215
+ </tr>
216
+ <% end %>
217
+ <!-- Create divider row -->
218
+ <tr class="break"><td colspan="7"></td></tr>
219
+ <% end %>
220
+ </table>
221
+ <% end %>
222
+ </body>
223
+ </html>'
224
+ end
225
+ end
226
+ end
227
+
@@ -0,0 +1,142 @@
1
+ module RubyProf
2
+ # Generates graph[link:files/examples/graph_txt.html] profile reports as text.
3
+ # To use the graph printer:
4
+ #
5
+ # result = RubyProf.profile do
6
+ # [code to profile]
7
+ # end
8
+ #
9
+ # printer = RubyProf::GraphPrinter.new(result, 5)
10
+ # printer.print(STDOUT, 0)
11
+ #
12
+ # The constructor takes two arguments. The first is
13
+ # a RubyProf::Result object generated from a profiling
14
+ # run. The second is the minimum %total (the methods
15
+ # total time divided by the overall total time) that
16
+ # a method must take for it to be printed out in
17
+ # the report. Use this parameter to eliminate methods
18
+ # that are not important to the overall profiling results.
19
+
20
+ class GraphPrinter
21
+ PERCENTAGE_WIDTH = 8
22
+ TIME_WIDTH = 10
23
+ CALL_WIDTH = 20
24
+
25
+ # Create a GraphPrinter. Result is a RubyProf::Result
26
+ # object generated from a profiling run.
27
+ def initialize(result, min_percent = 0)
28
+ @result = result
29
+ @min_percent = min_percent
30
+ end
31
+
32
+ # Print a graph report to the provided output.
33
+ #
34
+ # output - Any IO oject, including STDOUT or a file.
35
+ # The default value is STDOUT.
36
+ #
37
+ # min_percent - The minimum %total (the methods
38
+ # total time divided by the overall total time) that
39
+ # a method must take for it to be printed out in
40
+ # the report. Default value is 0.
41
+ def print(output = STDOUT, min_percent = 0)
42
+ @output = output
43
+ @min_percent = min_percent
44
+
45
+ print_threads
46
+ end
47
+
48
+ private
49
+ def print_threads
50
+ # sort assumes that spawned threads have higher object_ids
51
+ @result.threads.sort.each do |thread_id, methods|
52
+ print_methods(thread_id, methods)
53
+ @output << "\n" * 2
54
+ end
55
+ end
56
+
57
+ def print_methods(thread_id, methods)
58
+ toplevel = @result.toplevel(thread_id)
59
+ total_time = toplevel.total_time
60
+ if total_time == 0
61
+ total_time = 0.01
62
+ end
63
+
64
+ print_heading(thread_id)
65
+
66
+ # Get methods and sort by time
67
+ methods = methods.values.sort.reverse
68
+
69
+ # Print each method
70
+ methods.each do |method|
71
+ total_percentage = (method.total_time/total_time) * 100
72
+ self_percentage = (method.self_time/total_time) * 100
73
+
74
+ next if total_percentage < @min_percent
75
+
76
+ @output << "-" * 80 << "\n"
77
+
78
+ print_parents(thread_id, method)
79
+
80
+ # 1 is for % sign
81
+ @output << sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", total_percentage)
82
+ @output << sprintf("%#{PERCENTAGE_WIDTH-1}.2f\%", self_percentage)
83
+ @output << sprintf("%#{TIME_WIDTH}.2f", method.total_time)
84
+ @output << sprintf("%#{TIME_WIDTH}.2f", method.self_time)
85
+ @output << sprintf("%#{TIME_WIDTH}.2f", method.children_time)
86
+ @output << sprintf("%#{CALL_WIDTH}i", method.called)
87
+ @output << sprintf(" %s", method.name)
88
+ @output << "\n"
89
+
90
+ print_children(thread_id, method)
91
+ end
92
+ end
93
+
94
+ def print_heading(thread_id)
95
+ @output << "Thread ID: #{thread_id}\n"
96
+ # 1 is for % sign
97
+ @output << sprintf("%#{PERCENTAGE_WIDTH}s", "%total")
98
+ @output << sprintf("%#{PERCENTAGE_WIDTH}s", "%self")
99
+ @output << sprintf("%#{TIME_WIDTH}s", "total")
100
+ @output << sprintf("%#{TIME_WIDTH}s", "self")
101
+ @output << sprintf("%#{TIME_WIDTH+2}s", "children")
102
+ @output << sprintf("%#{CALL_WIDTH-2}s", "calls")
103
+ @output << " Name"
104
+ @output << "\n"
105
+ end
106
+
107
+ def print_parents(thread_id, method)
108
+ method.parents.each do |name, call_info|
109
+ @output << " " * 2 * PERCENTAGE_WIDTH
110
+ @output << sprintf("%#{TIME_WIDTH}.2f", call_info.total_time)
111
+ @output << sprintf("%#{TIME_WIDTH}.2f", call_info.self_time)
112
+ @output << sprintf("%#{TIME_WIDTH}.2f", call_info.children_time)
113
+
114
+ call_called = "#{call_info.called}/#{method.called}"
115
+ @output << sprintf("%#{CALL_WIDTH}s", call_called)
116
+ @output << sprintf(" %s", name)
117
+ @output << "\n"
118
+ end
119
+ end
120
+
121
+ def print_children(thread_id, method)
122
+ a = method.children
123
+ method.children.each do |name, call_info|
124
+ # Get children method
125
+ methods = @result.threads[thread_id]
126
+ children = methods[name]
127
+
128
+ @output << " " * 2 * PERCENTAGE_WIDTH
129
+
130
+ @output << sprintf("%#{TIME_WIDTH}.2f", call_info.total_time)
131
+ @output << sprintf("%#{TIME_WIDTH}.2f", call_info.self_time)
132
+ @output << sprintf("%#{TIME_WIDTH}.2f", call_info.children_time)
133
+
134
+ call_called = "#{call_info.called}/#{children.called}"
135
+ @output << sprintf("%#{CALL_WIDTH}s", call_called)
136
+ @output << sprintf(" %s", name)
137
+ @output << "\n"
138
+ end
139
+ end
140
+ end
141
+ end
142
+