ruby-prof 0.17.0 → 0.18.0

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 (185) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +500 -482
  3. data/LICENSE +24 -24
  4. data/README.rdoc +487 -485
  5. data/Rakefile +113 -113
  6. data/bin/ruby-prof +345 -345
  7. data/bin/ruby-prof-check-trace +45 -45
  8. data/examples/flat.txt +50 -50
  9. data/examples/graph.dot +84 -84
  10. data/examples/graph.html +823 -823
  11. data/examples/graph.txt +139 -139
  12. data/examples/multi.flat.txt +23 -23
  13. data/examples/multi.graph.html +760 -760
  14. data/examples/multi.grind.dat +114 -114
  15. data/examples/multi.stack.html +547 -547
  16. data/examples/stack.html +547 -547
  17. data/ext/ruby_prof/extconf.rb +68 -68
  18. data/ext/ruby_prof/rp_call_info.c +425 -425
  19. data/ext/ruby_prof/rp_call_info.h +53 -53
  20. data/ext/ruby_prof/rp_measure.c +40 -40
  21. data/ext/ruby_prof/rp_measure.h +45 -45
  22. data/ext/ruby_prof/rp_measure_allocations.c +76 -76
  23. data/ext/ruby_prof/rp_measure_cpu_time.c +136 -136
  24. data/ext/ruby_prof/rp_measure_gc_runs.c +73 -73
  25. data/ext/ruby_prof/rp_measure_gc_time.c +60 -60
  26. data/ext/ruby_prof/rp_measure_memory.c +77 -77
  27. data/ext/ruby_prof/rp_measure_process_time.c +71 -71
  28. data/ext/ruby_prof/rp_measure_wall_time.c +45 -45
  29. data/ext/ruby_prof/rp_method.c +630 -636
  30. data/ext/ruby_prof/rp_method.h +75 -75
  31. data/ext/ruby_prof/rp_stack.c +173 -173
  32. data/ext/ruby_prof/rp_stack.h +63 -63
  33. data/ext/ruby_prof/rp_thread.c +277 -276
  34. data/ext/ruby_prof/rp_thread.h +27 -27
  35. data/ext/ruby_prof/ruby_prof.c +794 -774
  36. data/ext/ruby_prof/ruby_prof.h +60 -59
  37. data/ext/ruby_prof/vc/ruby_prof.sln +20 -21
  38. data/ext/ruby_prof/vc/{ruby_prof_20.vcxproj → ruby_prof.vcxproj} +31 -0
  39. data/lib/ruby-prof.rb +68 -68
  40. data/lib/ruby-prof/aggregate_call_info.rb +76 -76
  41. data/lib/ruby-prof/assets/call_stack_printer.css.html +116 -116
  42. data/lib/ruby-prof/assets/call_stack_printer.js.html +384 -384
  43. data/lib/ruby-prof/call_info.rb +115 -115
  44. data/lib/ruby-prof/call_info_visitor.rb +40 -40
  45. data/lib/ruby-prof/compatibility.rb +179 -178
  46. data/lib/ruby-prof/method_info.rb +121 -121
  47. data/lib/ruby-prof/printers/abstract_printer.rb +104 -103
  48. data/lib/ruby-prof/printers/call_info_printer.rb +41 -41
  49. data/lib/ruby-prof/printers/call_stack_printer.rb +265 -265
  50. data/lib/ruby-prof/printers/call_tree_printer.rb +143 -143
  51. data/lib/ruby-prof/printers/dot_printer.rb +132 -132
  52. data/lib/ruby-prof/printers/flat_printer.rb +70 -70
  53. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +83 -83
  54. data/lib/ruby-prof/printers/graph_html_printer.rb +249 -249
  55. data/lib/ruby-prof/printers/graph_printer.rb +116 -116
  56. data/lib/ruby-prof/printers/multi_printer.rb +84 -84
  57. data/lib/ruby-prof/profile.rb +26 -26
  58. data/lib/ruby-prof/profile/exclude_common_methods.rb +207 -201
  59. data/lib/ruby-prof/profile/legacy_method_elimination.rb +50 -49
  60. data/lib/ruby-prof/rack.rb +174 -174
  61. data/lib/ruby-prof/task.rb +147 -147
  62. data/lib/ruby-prof/thread.rb +35 -35
  63. data/lib/ruby-prof/version.rb +3 -3
  64. data/lib/unprof.rb +10 -10
  65. data/ruby-prof.gemspec +58 -58
  66. data/test/abstract_printer_test.rb +53 -0
  67. data/test/aggregate_test.rb +136 -136
  68. data/test/basic_test.rb +128 -128
  69. data/test/block_test.rb +74 -74
  70. data/test/call_info_test.rb +78 -78
  71. data/test/call_info_visitor_test.rb +31 -31
  72. data/test/duplicate_names_test.rb +32 -32
  73. data/test/dynamic_method_test.rb +55 -55
  74. data/test/enumerable_test.rb +21 -21
  75. data/test/exceptions_test.rb +24 -16
  76. data/test/exclude_methods_test.rb +146 -146
  77. data/test/exclude_threads_test.rb +53 -53
  78. data/test/fiber_test.rb +79 -79
  79. data/test/issue137_test.rb +63 -63
  80. data/test/line_number_test.rb +80 -80
  81. data/test/measure_allocations_test.rb +26 -26
  82. data/test/measure_cpu_time_test.rb +212 -213
  83. data/test/measure_gc_runs_test.rb +32 -32
  84. data/test/measure_gc_time_test.rb +36 -36
  85. data/test/measure_memory_test.rb +33 -33
  86. data/test/measure_process_time_test.rb +61 -63
  87. data/test/measure_wall_time_test.rb +255 -255
  88. data/test/method_elimination_test.rb +84 -84
  89. data/test/module_test.rb +45 -45
  90. data/test/multi_printer_test.rb +104 -104
  91. data/test/no_method_class_test.rb +15 -15
  92. data/test/pause_resume_test.rb +166 -166
  93. data/test/prime.rb +54 -54
  94. data/test/printers_test.rb +275 -275
  95. data/test/printing_recursive_graph_test.rb +127 -127
  96. data/test/rack_test.rb +157 -157
  97. data/test/recursive_test.rb +215 -215
  98. data/test/singleton_test.rb +38 -38
  99. data/test/stack_printer_test.rb +77 -78
  100. data/test/stack_test.rb +138 -138
  101. data/test/start_stop_test.rb +112 -112
  102. data/test/test_helper.rb +267 -275
  103. data/test/thread_test.rb +187 -187
  104. data/test/unique_call_path_test.rb +202 -202
  105. data/test/yarv_test.rb +55 -55
  106. metadata +17 -96
  107. data/doc/LICENSE.html +0 -115
  108. data/doc/README_rdoc.html +0 -637
  109. data/doc/Rack.html +0 -96
  110. data/doc/Rack/RubyProf.html +0 -233
  111. data/doc/Rack/RubyProf/RackProfiler.html +0 -343
  112. data/doc/RubyProf.html +0 -974
  113. data/doc/RubyProf/AbstractPrinter.html +0 -625
  114. data/doc/RubyProf/AggregateCallInfo.html +0 -552
  115. data/doc/RubyProf/CallInfo.html +0 -579
  116. data/doc/RubyProf/CallInfoPrinter.html +0 -121
  117. data/doc/RubyProf/CallInfoVisitor.html +0 -199
  118. data/doc/RubyProf/CallStackPrinter.html +0 -1127
  119. data/doc/RubyProf/CallTreePrinter.html +0 -725
  120. data/doc/RubyProf/Cmd.html +0 -637
  121. data/doc/RubyProf/DeprecationWarnings.html +0 -148
  122. data/doc/RubyProf/DotPrinter.html +0 -258
  123. data/doc/RubyProf/FlatPrinter.html +0 -164
  124. data/doc/RubyProf/FlatPrinterWithLineNumbers.html +0 -210
  125. data/doc/RubyProf/GraphHtmlPrinter.html +0 -558
  126. data/doc/RubyProf/GraphPrinter.html +0 -140
  127. data/doc/RubyProf/MethodInfo.html +0 -676
  128. data/doc/RubyProf/MultiPrinter.html +0 -574
  129. data/doc/RubyProf/Profile.html +0 -908
  130. data/doc/RubyProf/Profile/ExcludeCommonMethods.html +0 -411
  131. data/doc/RubyProf/Profile/LegacyMethodElimination.html +0 -158
  132. data/doc/RubyProf/ProfileTask.html +0 -491
  133. data/doc/RubyProf/Thread.html +0 -275
  134. data/doc/created.rid +0 -33
  135. data/doc/css/fonts.css +0 -167
  136. data/doc/css/rdoc.css +0 -590
  137. data/doc/examples/flat_txt.html +0 -139
  138. data/doc/examples/graph_html.html +0 -910
  139. data/doc/examples/graph_txt.html +0 -248
  140. data/doc/fonts/Lato-Light.ttf +0 -0
  141. data/doc/fonts/Lato-LightItalic.ttf +0 -0
  142. data/doc/fonts/Lato-Regular.ttf +0 -0
  143. data/doc/fonts/Lato-RegularItalic.ttf +0 -0
  144. data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
  145. data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
  146. data/doc/images/add.png +0 -0
  147. data/doc/images/arrow_up.png +0 -0
  148. data/doc/images/brick.png +0 -0
  149. data/doc/images/brick_link.png +0 -0
  150. data/doc/images/bug.png +0 -0
  151. data/doc/images/bullet_black.png +0 -0
  152. data/doc/images/bullet_toggle_minus.png +0 -0
  153. data/doc/images/bullet_toggle_plus.png +0 -0
  154. data/doc/images/date.png +0 -0
  155. data/doc/images/delete.png +0 -0
  156. data/doc/images/find.png +0 -0
  157. data/doc/images/loadingAnimation.gif +0 -0
  158. data/doc/images/macFFBgHack.png +0 -0
  159. data/doc/images/package.png +0 -0
  160. data/doc/images/page_green.png +0 -0
  161. data/doc/images/page_white_text.png +0 -0
  162. data/doc/images/page_white_width.png +0 -0
  163. data/doc/images/plugin.png +0 -0
  164. data/doc/images/ruby.png +0 -0
  165. data/doc/images/tag_blue.png +0 -0
  166. data/doc/images/tag_green.png +0 -0
  167. data/doc/images/transparent.png +0 -0
  168. data/doc/images/wrench.png +0 -0
  169. data/doc/images/wrench_orange.png +0 -0
  170. data/doc/images/zoom.png +0 -0
  171. data/doc/index.html +0 -666
  172. data/doc/js/darkfish.js +0 -161
  173. data/doc/js/jquery.js +0 -4
  174. data/doc/js/navigation.js +0 -142
  175. data/doc/js/navigation.js.gz +0 -0
  176. data/doc/js/search.js +0 -109
  177. data/doc/js/search_index.js +0 -1
  178. data/doc/js/search_index.js.gz +0 -0
  179. data/doc/js/searcher.js +0 -229
  180. data/doc/js/searcher.js.gz +0 -0
  181. data/doc/table_of_contents.html +0 -1052
  182. data/examples/cachegrind.out.1 +0 -114
  183. data/examples/cachegrind.out.1.32313213 +0 -114
  184. data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +0 -108
  185. data/ext/ruby_prof/vc/ruby_prof_19.vcxproj +0 -110
@@ -1,275 +1,267 @@
1
- # encoding: UTF-8
2
-
3
- # Make RubyMine happy
4
- require "rubygems"
5
- gem "minitest"
6
-
7
- if ENV["RM_INFO"] || ENV["TEAMCITY_VERSION"]
8
- if RUBY_PLATFORM =~ /(win32|mingw)/
9
- gem "win32console"
10
- end
11
- gem "minitest-reporters"
12
- require 'minitest/reporters'
13
- MiniTest::Reporters.use!
14
- end
15
-
16
- require "minitest/pride" if RUBY_VERSION == "1.9.3"
17
-
18
- # To make testing/debugging easier, test within this source tree versus an installed gem
19
- dir = File.dirname(__FILE__)
20
- root = File.expand_path(File.join(dir, '..'))
21
- lib = File.expand_path(File.join(root, 'lib'))
22
- ext = File.expand_path(File.join(root, 'ext', 'ruby_prof'))
23
-
24
- $LOAD_PATH << lib
25
- $LOAD_PATH << ext
26
-
27
- require 'ruby-prof'
28
-
29
- # stub deprecation warnings
30
- module RubyProf
31
- module SuppressDeprecationWarnings
32
- def deprecation_warning(*args)
33
- super if ENV['SHOW_RUBY_PROF_DEPRECATION_WARNINGS'] == '1'
34
- end
35
- end
36
- extend SuppressDeprecationWarnings
37
- end
38
-
39
- require 'minitest/autorun'
40
-
41
- class TestCase < Minitest::Test
42
- # I know this sucks, but ...
43
- def assert_nothing_raised(*)
44
- yield
45
- end
46
-
47
- def before_setup
48
- # make sure to exclude all threads except the one running the test
49
- # minitest allocates a thread pool and they would otherwise show
50
- # up in the profile data, breaking tests randomly
51
- RubyProf.exclude_threads = Thread.list.select{|t| t != Thread.current}
52
- end
53
-
54
- def after_teardown
55
- # reset exclude threads after testing
56
- RubyProf.exclude_threads = nil
57
- end
58
- end
59
-
60
- require File.expand_path('../prime', __FILE__)
61
-
62
- # Some classes used in measurement tests
63
- module RubyProf
64
- class C1
65
- def C1.hello
66
- sleep(0.1)
67
- end
68
-
69
- def hello
70
- sleep(0.2)
71
- end
72
- end
73
-
74
- module M1
75
- def hello
76
- sleep(0.3)
77
- end
78
- end
79
-
80
- class C2
81
- include M1
82
- extend M1
83
- end
84
-
85
- class C3
86
- def hello
87
- sleep(0.4)
88
- end
89
- end
90
-
91
- module M4
92
- def hello
93
- sleep(0.5)
94
- end
95
- end
96
-
97
- module M5
98
- include M4
99
- def goodbye
100
- hello
101
- end
102
- end
103
-
104
- class C6
105
- include M5
106
- def test
107
- goodbye
108
- end
109
- end
110
-
111
- class C7
112
- def self.busy_wait
113
- t = Time.now.to_f
114
- while Time.now.to_f - t < 0.1; end
115
- end
116
-
117
- def self.sleep_wait
118
- sleep 0.1
119
- end
120
-
121
- def busy_wait
122
- t = Time.now.to_f
123
- while Time.now.to_f - t < 0.2; end
124
- end
125
-
126
- def sleep_wait
127
- sleep 0.2
128
- end
129
- end
130
-
131
- module M7
132
- def busy_wait
133
- t = Time.now.to_f
134
- while Time.now.to_f - t < 0.3; end
135
- end
136
-
137
- def sleep_wait
138
- sleep 0.3
139
- end
140
- end
141
-
142
- class C8
143
- include M7
144
- extend M7
145
- end
146
-
147
- def self.ruby_major_version
148
- match = RUBY_VERSION.match(/(\d)\.(\d)/)
149
- return Integer(match[1])
150
- end
151
-
152
- def self.ruby_minor_version
153
- match = RUBY_VERSION.match(/(\d)\.(\d)/)
154
- return Integer(match[2])
155
- end
156
-
157
- def self.parent_object
158
- if ruby_major_version == 1 && ruby_minor_version == 8
159
- Object
160
- else
161
- BasicObject
162
- end
163
- end
164
-
165
- def self.ruby_2?
166
- ruby_major_version == 2
167
- end
168
-
169
- # store printer output in this directory
170
- def self.tmpdir
171
- File.expand_path('../../tmp', __FILE__)
172
- end
173
- end
174
-
175
- module MemoryTestHelper
176
- def memory_test_helper
177
- result = RubyProf.profile {Array.new}
178
- total = result.threads.first.methods.inject(0) { |sum, m| sum + m.total_time }
179
- assert(total < 1_000_000, 'Total should not have subtract overflow error')
180
- total
181
- end
182
- end
183
-
184
- module PrinterTestHelper
185
- Metrics = Struct.new(:name, :total, :self_t, :wait, :child, :calls)
186
- class Metrics
187
- def pp
188
- "%s[total: %.2f, self: %.2f, wait: %.2f, child: %.2f, calls: %s]" %
189
- [name, total, self_t, wait, child, calls]
190
- end
191
- end
192
-
193
- Entry = Struct.new(:total_p, :self_p, :metrics, :parents, :children)
194
- class Entry
195
- def child(name)
196
- children.detect{|m| m.name == name}
197
- end
198
-
199
- def parent(name)
200
- parents.detect{|m| m.name == name}
201
- end
202
-
203
- def pp
204
- res = ""
205
- res << "NODE (total%%: %.2f, self%%: %.2f) %s\n" % [total_p, self_p, metrics.pp]
206
- res << " PARENTS:\n"
207
- parents.each {|m| res << " " + m.pp << "\n"}
208
- res << " CHILDREN:\n"
209
- children.each {|m| res << " " + m.pp << "\n"}
210
- res
211
- end
212
- end
213
-
214
- class MetricsArray < Array
215
- def metrics_for(name)
216
- detect {|e| e.metrics.name == name}
217
- end
218
-
219
- def pp(io = STDOUT)
220
- entries = map do |e|
221
- begin
222
- e.pp
223
- rescue
224
- puts $!.message + e.inspect
225
- ""
226
- end
227
- end
228
- io.puts entries.join("--------------------------------------------------\n")
229
- end
230
-
231
- def self.parse(str)
232
- res = new
233
- entry = nil
234
- relatives = []
235
- state = :preamble
236
-
237
- str.each_line do |l|
238
- line = l.chomp.strip
239
- if line =~ /-----/
240
- if state == :preamble
241
- state = :parsing_parents
242
- entry = Entry.new
243
- elsif state == :parsing_parents
244
- entry = Entry.new
245
- elsif state == :parsing_children
246
- entry.children = relatives
247
- res << entry
248
- entry = Entry.new
249
- relatives = []
250
- state = :parsing_parents
251
- end
252
- elsif line =~ /^\s*$/ || line =~ /indicates recursively called methods/
253
- next
254
- elsif state != :preamble
255
- elements = line.split(/\s+/)
256
- method = elements.pop
257
- numbers = elements[0..-2].map(&:to_f)
258
- metrics = Metrics.new(method, *numbers[-4..-1], elements[-1])
259
- if numbers.size == 6
260
- entry.metrics = metrics
261
- entry.total_p = numbers[0]
262
- entry.self_p = numbers[1]
263
- entry.parents = relatives
264
- entry.children = relatives = []
265
- state = :parsing_children
266
- res << entry
267
- else
268
- relatives << metrics
269
- end
270
- end
271
- end
272
- res
273
- end
274
- end
275
- end
1
+ # encoding: UTF-8
2
+
3
+ require "rubygems"
4
+ gem "minitest"
5
+
6
+ # To make testing/debugging easier, test within this source tree versus an installed gem
7
+ dir = File.dirname(__FILE__)
8
+ root = File.expand_path(File.join(dir, '..'))
9
+ lib = File.expand_path(File.join(root, 'lib'))
10
+ ext = File.expand_path(File.join(root, 'ext', 'ruby_prof'))
11
+
12
+ $LOAD_PATH << lib
13
+ $LOAD_PATH << ext
14
+
15
+ require 'ruby-prof'
16
+
17
+ # stub deprecation warnings
18
+ module RubyProf
19
+ module SuppressDeprecationWarnings
20
+ def deprecation_warning(*args)
21
+ super if ENV['SHOW_RUBY_PROF_DEPRECATION_WARNINGS'] == '1'
22
+ end
23
+ end
24
+ extend SuppressDeprecationWarnings
25
+ end
26
+
27
+ require 'minitest/autorun'
28
+
29
+ class TestCase < Minitest::Test
30
+ # I know this sucks, but ...
31
+ def assert_nothing_raised(*)
32
+ yield
33
+ end
34
+
35
+ def before_setup
36
+ # make sure to exclude all threads except the one running the test
37
+ # minitest allocates a thread pool and they would otherwise show
38
+ # up in the profile data, breaking tests randomly
39
+ RubyProf.exclude_threads = Thread.list.select{|t| t != Thread.current}
40
+ end
41
+
42
+ def after_teardown
43
+ # reset exclude threads after testing
44
+ RubyProf.exclude_threads = nil
45
+ end
46
+ end
47
+
48
+ require File.expand_path('../prime', __FILE__)
49
+
50
+ # Some classes used in measurement tests
51
+ module RubyProf
52
+ class C1
53
+ def C1.hello
54
+ sleep(0.1)
55
+ end
56
+
57
+ def hello
58
+ sleep(0.2)
59
+ end
60
+ end
61
+
62
+ module M1
63
+ def hello
64
+ sleep(0.3)
65
+ end
66
+ end
67
+
68
+ class C2
69
+ include M1
70
+ extend M1
71
+ end
72
+
73
+ class C3
74
+ def hello
75
+ sleep(0.4)
76
+ end
77
+ end
78
+
79
+ module M4
80
+ def hello
81
+ sleep(0.5)
82
+ end
83
+ end
84
+
85
+ module M5
86
+ include M4
87
+ def goodbye
88
+ hello
89
+ end
90
+ end
91
+
92
+ class C6
93
+ include M5
94
+ def test
95
+ goodbye
96
+ end
97
+ end
98
+
99
+ class C7
100
+ def self.busy_wait
101
+ t = Time.now.to_f
102
+ while Time.now.to_f - t < 0.1; end
103
+ end
104
+
105
+ def self.sleep_wait
106
+ sleep 0.1
107
+ end
108
+
109
+ def busy_wait
110
+ t = Time.now.to_f
111
+ while Time.now.to_f - t < 0.2; end
112
+ end
113
+
114
+ def sleep_wait
115
+ sleep 0.2
116
+ end
117
+ end
118
+
119
+ module M7
120
+ def busy_wait
121
+ t = Time.now.to_f
122
+ while Time.now.to_f - t < 0.3; end
123
+ end
124
+
125
+ def sleep_wait
126
+ sleep 0.3
127
+ end
128
+ end
129
+
130
+ class C8
131
+ include M7
132
+ extend M7
133
+ end
134
+
135
+ def self.ruby_major_version
136
+ match = RUBY_VERSION.match(/(\d)\.(\d)/)
137
+ return Integer(match[1])
138
+ end
139
+
140
+ def self.ruby_minor_version
141
+ match = RUBY_VERSION.match(/(\d)\.(\d)/)
142
+ return Integer(match[2])
143
+ end
144
+
145
+ def self.parent_object
146
+ if ruby_major_version == 1 && ruby_minor_version == 8
147
+ Object
148
+ else
149
+ BasicObject
150
+ end
151
+ end
152
+
153
+ def self.ruby_2?
154
+ ruby_major_version == 2
155
+ end
156
+
157
+ # store printer output in this directory
158
+ def self.tmpdir
159
+ path = File.expand_path('../../tmp', __FILE__)
160
+ unless Dir.exist?(path)
161
+ Dir.mkdir(path)
162
+ end
163
+ path
164
+ end
165
+ end
166
+
167
+ module MemoryTestHelper
168
+ def memory_test_helper
169
+ result = RubyProf.profile {Array.new}
170
+ total = result.threads.first.methods.inject(0) { |sum, m| sum + m.total_time }
171
+ assert(total < 1_000_000, 'Total should not have subtract overflow error')
172
+ total
173
+ end
174
+ end
175
+
176
+ module PrinterTestHelper
177
+ Metrics = Struct.new(:name, :total, :self_t, :wait, :child, :calls)
178
+ class Metrics
179
+ def pp
180
+ "%s[total: %.2f, self: %.2f, wait: %.2f, child: %.2f, calls: %s]" %
181
+ [name, total, self_t, wait, child, calls]
182
+ end
183
+ end
184
+
185
+ Entry = Struct.new(:total_p, :self_p, :metrics, :parents, :children)
186
+ class Entry
187
+ def child(name)
188
+ children.detect{|m| m.name == name}
189
+ end
190
+
191
+ def parent(name)
192
+ parents.detect{|m| m.name == name}
193
+ end
194
+
195
+ def pp
196
+ res = ""
197
+ res << "NODE (total%%: %.2f, self%%: %.2f) %s\n" % [total_p, self_p, metrics.pp]
198
+ res << " PARENTS:\n"
199
+ parents.each {|m| res << " " + m.pp << "\n"}
200
+ res << " CHILDREN:\n"
201
+ children.each {|m| res << " " + m.pp << "\n"}
202
+ res
203
+ end
204
+ end
205
+
206
+ class MetricsArray < Array
207
+ def metrics_for(name)
208
+ detect {|e| e.metrics.name == name}
209
+ end
210
+
211
+ def pp(io = STDOUT)
212
+ entries = map do |e|
213
+ begin
214
+ e.pp
215
+ rescue
216
+ puts $!.message + e.inspect
217
+ ""
218
+ end
219
+ end
220
+ io.puts entries.join("--------------------------------------------------\n")
221
+ end
222
+
223
+ def self.parse(str)
224
+ res = new
225
+ entry = nil
226
+ relatives = []
227
+ state = :preamble
228
+
229
+ str.each_line do |l|
230
+ line = l.chomp.strip
231
+ if line =~ /-----/
232
+ if state == :preamble
233
+ state = :parsing_parents
234
+ entry = Entry.new
235
+ elsif state == :parsing_parents
236
+ entry = Entry.new
237
+ elsif state == :parsing_children
238
+ entry.children = relatives
239
+ res << entry
240
+ entry = Entry.new
241
+ relatives = []
242
+ state = :parsing_parents
243
+ end
244
+ elsif line =~ /^\s*$/ || line =~ /indicates recursively called methods/
245
+ next
246
+ elsif state != :preamble
247
+ elements = line.split(/\s+/)
248
+ method = elements.pop
249
+ numbers = elements[0..-2].map(&:to_f)
250
+ metrics = Metrics.new(method, *numbers[-4..-1], elements[-1])
251
+ if numbers.size == 6
252
+ entry.metrics = metrics
253
+ entry.total_p = numbers[0]
254
+ entry.self_p = numbers[1]
255
+ entry.parents = relatives
256
+ entry.children = relatives = []
257
+ state = :parsing_children
258
+ res << entry
259
+ else
260
+ relatives << metrics
261
+ end
262
+ end
263
+ end
264
+ res
265
+ end
266
+ end
267
+ end