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,127 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+ require 'stringio'
6
+ require 'fileutils'
7
+
8
+ # --- code to be tested ---
9
+ module PRGT
10
+ extend self
11
+
12
+ def f(n)
13
+ n.times { sleep 0.1 }
14
+ end
15
+
16
+ def g(n)
17
+ n.times { sleep 0.2 }
18
+ end
19
+
20
+ def run
21
+ 2.times { f(2); g(4) }
22
+ end
23
+ end
24
+
25
+ # --- expected test output ---
26
+ =begin
27
+ Measure Mode: wall_time
28
+ Thread ID: 70238775664960
29
+ Fiber ID: 70238784046840
30
+ Total Time: 2.040249824523926
31
+ Sort by: total_time
32
+
33
+ %total %self total self wait child calls Name
34
+ --------------------------------------------------------------------------------
35
+ 100.00% 0.00% 2.040 0.000 0.000 2.040 1 PrintingRecursiveGraphTest#setup
36
+ 2.040 0.000 0.000 2.040 1/1 PRGT#run
37
+ --------------------------------------------------------------------------------
38
+ 2.040 0.000 0.000 2.040 1/1 PrintingRecursiveGraphTest#setup
39
+ 100.00% 0.00% 2.040 0.000 0.000 2.040 1 PRGT#run
40
+ 2.040 0.000 0.000 2.040 1/5 Integer#times
41
+ --------------------------------------------------------------------------------
42
+ 0.409 0.000 0.000 0.409 2/5 Prgt#f
43
+ 1.631 0.000 0.000 1.631 2/5 PRGT#g
44
+ 2.040 0.000 0.000 2.040 1/5 PRGT#run
45
+ 100.00% 0.00% 2.040 0.000 0.000 2.040 5 *Integer#times
46
+ 2.040 2.040 0.000 0.000 12/12 Kernel#sleep
47
+ 1.631 0.000 0.000 1.631 2/2 PRGT#g
48
+ 0.409 0.000 0.000 0.409 2/2 PRGT#f
49
+ --------------------------------------------------------------------------------
50
+ 2.040 2.040 0.000 0.000 12/12 Integer#times
51
+ 99.99% 99.99% 2.040 2.040 0.000 0.000 12 Kernel#sleep
52
+ --------------------------------------------------------------------------------
53
+ 1.631 0.000 0.000 1.631 2/2 Integer#times
54
+ 79.94% 0.00% 1.631 0.000 0.000 1.631 2 PRGT#g
55
+ 1.631 0.000 0.000 1.631 2/5 Integer#times
56
+ --------------------------------------------------------------------------------
57
+ 0.409 0.000 0.000 0.409 2/2 Integer#times
58
+ 20.05% 0.00% 0.409 0.000 0.000 0.409 2 PRGT#f
59
+ 0.409 0.000 0.000 0.409 2/5 Integer#times
60
+
61
+ * indicates recursively called methods
62
+ =end
63
+
64
+ class PrintingRecursiveGraphTest < TestCase
65
+ include PrinterTestHelper
66
+
67
+ def setup
68
+ # WALL_TIME so we can use sleep in our test and get same measurements on linux and windows
69
+ RubyProf::measure_mode = RubyProf::WALL_TIME
70
+ @result = RubyProf.profile do
71
+ PRGT.run
72
+ end
73
+ end
74
+
75
+ def test_printing_rescursive_graph
76
+ printer = RubyProf::GraphPrinter.new(@result)
77
+
78
+ buffer = ''
79
+ printer.print(StringIO.new(buffer))
80
+
81
+ puts buffer if ENV['SHOW_RUBY_PROF_PRINTER_OUTPUT'] == "1"
82
+
83
+ parsed_output = MetricsArray.parse(buffer)
84
+
85
+ assert( integer_times = parsed_output.metrics_for("*Integer#times") )
86
+
87
+ actual_parents = integer_times.parents.map(&:name)
88
+ expected_parents = %w(PRGT#f PRGT#g PRGT#run)
89
+ assert_equal expected_parents, actual_parents
90
+
91
+ actual_children = integer_times.children.map(&:name)
92
+ expected_children = %w(Kernel#sleep PRGT#g PRGT#f)
93
+ assert_equal expected_children, actual_children
94
+
95
+ assert( fp = integer_times.parent("PRGT#f") )
96
+ assert_in_delta(fp.total, fp.child, 0.01)
97
+ assert_equal("2/5", fp.calls)
98
+
99
+ assert( gp = integer_times.parent("PRGT#g") )
100
+ assert_in_delta(gp.total, gp.child, 0.01)
101
+ assert_equal("2/5", gp.calls)
102
+
103
+ assert( rp = integer_times.parent("PRGT#run") )
104
+ assert_in_delta(rp.total, rp.child, 0.01)
105
+ assert_equal("1/5", rp.calls)
106
+
107
+ assert_in_delta(4*fp.total, gp.total, 0.05)
108
+ assert_in_delta(fp.total + gp.total, rp.total, 0.05)
109
+ assert_in_delta(integer_times.metrics.total, rp.total, 0.05)
110
+
111
+ assert( fc = integer_times.child("PRGT#f") )
112
+ assert_in_delta(fc.total, fc.child, 0.01)
113
+ assert_equal("2/2", fc.calls)
114
+
115
+ assert( gc = integer_times.child("PRGT#g") )
116
+ assert_in_delta(gc.total, gc.child, 0.01)
117
+ assert_equal("2/2", gc.calls)
118
+
119
+ assert( ks = integer_times.child("Kernel#sleep") )
120
+ assert_in_delta(ks.total, ks.self_t, 0.01)
121
+ assert_equal("12/12", ks.calls)
122
+
123
+ assert_in_delta(4*fc.total, gc.total, 0.05)
124
+ assert_in_delta(fp.total + gc.total, ks.total, 0.05)
125
+ assert_in_delta(integer_times.metrics.total, ks.total, 0.05)
126
+ end
127
+ end
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ class FakeRackApp
7
+ def call(env)
8
+ end
9
+ end
10
+
11
+ module Rack
12
+ class Request
13
+ def initialize(env)
14
+ if env == :fake_env
15
+ @env = {}
16
+ else
17
+ @env = env
18
+ end
19
+ end
20
+
21
+ def path
22
+ @env[:path] || '/path/to/resource.json'
23
+ end
24
+ end
25
+ end
26
+
27
+ class RackTest < TestCase
28
+ def test_create_print_path
29
+ path = Dir.mktmpdir
30
+ Dir.delete(path)
31
+
32
+ Rack::RubyProf.new(FakeRackApp.new, :path => path)
33
+
34
+ assert(Dir.exist?(path))
35
+ end
36
+
37
+ def test_create_profile_reports
38
+ path = Dir.mktmpdir
39
+
40
+ adapter = Rack::RubyProf.new(FakeRackApp.new, :path => path)
41
+
42
+ adapter.call(:fake_env)
43
+
44
+ %w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
45
+ file_path = ::File.join(path, "path-to-resource.json-#{base_name}")
46
+ assert(File.exist?(file_path))
47
+ end
48
+ end
49
+
50
+ def test_skip_paths
51
+ path = Dir.mktmpdir
52
+
53
+ adapter = Rack::RubyProf.new(FakeRackApp.new, :path => path, :skip_paths => [%r{\.json$}])
54
+
55
+ adapter.call(:fake_env)
56
+
57
+ %w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
58
+ file_path = ::File.join(path, "path-to-resource.json-#{base_name}")
59
+ assert(!File.exist?(file_path))
60
+ end
61
+ end
62
+
63
+ def test_only_paths
64
+ path = Dir.mktmpdir
65
+
66
+ adapter = Rack::RubyProf.new(FakeRackApp.new, :path => path, :only_paths => [%r{\.json$}])
67
+
68
+ adapter.call({path: '/path/to/resource.json'})
69
+
70
+ %w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
71
+ file_path = ::File.join(path, "path-to-resource.json-#{base_name}")
72
+ assert(File.exist?(file_path))
73
+ end
74
+
75
+ adapter.call({path: '/path/to/resource.html'})
76
+ %w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
77
+ file_path = ::File.join(path, "path-to-resource.html-#{base_name}")
78
+ assert(!File.exist?(file_path))
79
+ end
80
+ end
81
+
82
+ def test_allows_lazy_filename_setting
83
+ path = Dir.mktmpdir
84
+
85
+ printer = {::RubyProf::FlatPrinter => lambda { 'dynamic.txt' }}
86
+ adapter = Rack::RubyProf.new(FakeRackApp.new, :path => path, :printers => printer)
87
+
88
+ adapter.call(:fake_env)
89
+
90
+ file_path = ::File.join(path, 'path-to-resource.json-dynamic.txt')
91
+ assert(File.exist?(file_path))
92
+ end
93
+ end
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ module SimpleRecursion
7
+ # Simple recursive test
8
+ def simple(n)
9
+ sleep(1)
10
+ n -= 1
11
+ return if n == 0
12
+ simple(n)
13
+ end
14
+
15
+
16
+ # More complicated recursive test
17
+ def render_partial(i)
18
+ sleep(1)
19
+ case i
20
+ when 0
21
+ render_partial(10)
22
+ when 1
23
+ 2.times do |j|
24
+ render_partial(j + 10)
25
+ end
26
+ end
27
+ end
28
+
29
+ def render
30
+ 2.times do |i|
31
+ render_partial(i)
32
+ end
33
+ end
34
+ end
35
+
36
+ # -- Tests ----
37
+ class RecursiveTest < TestCase
38
+ def setup
39
+ # Need to use wall time for this test due to the sleep calls
40
+ RubyProf::measure_mode = RubyProf::WALL_TIME
41
+ end
42
+
43
+ include SimpleRecursion
44
+
45
+ def test_simple
46
+ result = RubyProf.profile do
47
+ simple(2)
48
+ end
49
+
50
+ methods = result.threads.first.methods.sort.reverse
51
+ assert_equal(3, methods.length)
52
+
53
+ # Method 0: RecursiveTest#test_simple
54
+ method = methods[0]
55
+ assert_equal('RecursiveTest#test_simple', method.full_name)
56
+ assert_equal(1, method.called)
57
+ assert_in_delta(2, method.total_time, 0.1)
58
+ assert_in_delta(0, method.self_time, 0.01)
59
+ assert_in_delta(0, method.wait_time, 0.01)
60
+ assert_in_delta(2, method.children_time, 0.1)
61
+
62
+ assert_equal(1, method.call_infos.length)
63
+ call_info = method.call_infos[0]
64
+ assert(!call_info.recursive?)
65
+ assert_equal('RecursiveTest#test_simple', call_info.call_sequence)
66
+ assert_equal(1, call_info.children.length)
67
+
68
+ # Method 1: SimpleRecursion#simple
69
+ method = methods[1]
70
+ assert_equal('SimpleRecursion#simple', method.full_name)
71
+ assert_equal(2, method.called)
72
+ assert_in_delta(2, method.total_time, 0.1)
73
+ assert_in_delta(0, method.self_time, 0.1)
74
+ assert_in_delta(0, method.wait_time, 0.1)
75
+ assert_in_delta(2, method.children_time, 0.1)
76
+
77
+ assert_equal(2, method.call_infos.length)
78
+
79
+ call_info = method.call_infos.first
80
+ assert_equal(2, call_info.children.length)
81
+ assert_equal('RecursiveTest#test_simple->SimpleRecursion#simple', call_info.call_sequence)
82
+ assert(!call_info.recursive?)
83
+
84
+ call_info = method.call_infos.last
85
+ assert_equal(1, call_info.children.length)
86
+ assert_equal('RecursiveTest#test_simple->SimpleRecursion#simple->SimpleRecursion#simple', call_info.call_sequence)
87
+ assert(call_info.recursive?)
88
+
89
+ method = methods[2]
90
+ assert_equal('Kernel#sleep', method.full_name)
91
+ assert_equal(2, method.called)
92
+ assert_in_delta(2, method.total_time, 0.1)
93
+ assert_in_delta(2, method.self_time, 0.1)
94
+ assert_in_delta(0, method.wait_time, 0.1)
95
+ assert_in_delta(0, method.children_time, 0.1)
96
+
97
+ assert_equal(2, method.call_infos.length)
98
+ call_info = method.call_infos[0]
99
+ assert_equal('RecursiveTest#test_simple->SimpleRecursion#simple->Kernel#sleep', call_info.call_sequence)
100
+ assert_equal(0, call_info.children.length)
101
+ assert(!call_info.recursive?)
102
+
103
+ call_info = method.call_infos[1]
104
+ assert_equal('RecursiveTest#test_simple->SimpleRecursion#simple->SimpleRecursion#simple->Kernel#sleep', call_info.call_sequence)
105
+ assert_equal(0, call_info.children.length)
106
+ assert(!call_info.recursive?)
107
+ end
108
+
109
+ def test_cycle
110
+ result = RubyProf.profile do
111
+ render
112
+ end
113
+
114
+ methods = result.threads.first.methods.sort.reverse
115
+ assert_equal(5, methods.length)
116
+
117
+ method = methods[0]
118
+ assert_equal('RecursiveTest#test_cycle', method.full_name)
119
+ assert_equal(1, method.called)
120
+ assert_in_delta(5, method.total_time, 0.1)
121
+ assert_in_delta(0, method.self_time, 0.01)
122
+ assert_in_delta(0, method.wait_time, 0.01)
123
+ assert_in_delta(5, method.children_time, 0.1)
124
+
125
+ assert_equal(1, method.call_infos.length)
126
+ call_info = method.call_infos[0]
127
+ assert_equal('RecursiveTest#test_cycle', call_info.call_sequence)
128
+ assert_equal(1, call_info.children.length)
129
+ assert(!call_info.recursive?)
130
+
131
+ method = methods[1]
132
+ assert_equal('SimpleRecursion#render', method.full_name)
133
+ assert_equal(1, method.called)
134
+ assert_in_delta(5, method.total_time, 0.1)
135
+ assert_in_delta(0, method.self_time, 0.01)
136
+ assert_in_delta(0, method.wait_time, 0.01)
137
+ assert_in_delta(5, method.children_time, 0.1)
138
+
139
+ assert_equal(1, method.call_infos.length)
140
+ call_info = method.call_infos[0]
141
+ assert_equal('RecursiveTest#test_cycle->SimpleRecursion#render', call_info.call_sequence)
142
+ assert_equal(1, call_info.children.length)
143
+ assert(!call_info.recursive?)
144
+
145
+ method = methods[2]
146
+ assert_equal('Integer#times', method.full_name)
147
+ assert_equal(2, method.called)
148
+ assert_in_delta(5, method.total_time, 0.1)
149
+ assert_in_delta(0, method.self_time, 0.1)
150
+ assert_in_delta(0, method.wait_time, 0.1)
151
+ assert_in_delta(5, method.children_time, 0.1)
152
+
153
+ assert_equal(2, method.call_infos.length)
154
+ call_info = method.call_infos[0]
155
+ assert_equal('RecursiveTest#test_cycle->SimpleRecursion#render->Integer#times', call_info.call_sequence)
156
+ assert_equal(1, call_info.children.length)
157
+ assert(!call_info.recursive?)
158
+
159
+ call_info = method.call_infos[1]
160
+ assert_equal('RecursiveTest#test_cycle->SimpleRecursion#render->Integer#times->SimpleRecursion#render_partial->Integer#times', call_info.call_sequence)
161
+ assert_equal(1, call_info.children.length)
162
+ assert(call_info.recursive?)
163
+
164
+ method = methods[3]
165
+ assert_equal('SimpleRecursion#render_partial', method.full_name)
166
+ assert_equal(5, method.called)
167
+ assert_in_delta(5, method.total_time, 0.1)
168
+ assert_in_delta(0, method.self_time, 0.1)
169
+ assert_in_delta(0, method.wait_time, 0.01)
170
+ assert_in_delta(5, method.children_time, 0.05)
171
+
172
+ assert_equal(3, method.call_infos.length)
173
+ call_info = method.call_infos[0]
174
+ assert_equal('RecursiveTest#test_cycle->SimpleRecursion#render->Integer#times->SimpleRecursion#render_partial', call_info.call_sequence)
175
+ assert_equal(3, call_info.children.length)
176
+ assert(!call_info.recursive?)
177
+
178
+ call_info = method.call_infos[1]
179
+ assert_equal('RecursiveTest#test_cycle->SimpleRecursion#render->Integer#times->SimpleRecursion#render_partial->SimpleRecursion#render_partial', call_info.call_sequence)
180
+ assert_equal(1, call_info.children.length)
181
+ assert(call_info.recursive?)
182
+
183
+ call_info = method.call_infos[2]
184
+ assert_equal('RecursiveTest#test_cycle->SimpleRecursion#render->Integer#times->SimpleRecursion#render_partial->Integer#times->SimpleRecursion#render_partial', call_info.call_sequence)
185
+ assert_equal(1, call_info.children.length)
186
+ assert(call_info.recursive?)
187
+
188
+ method = methods[4]
189
+ assert_equal('Kernel#sleep', method.full_name)
190
+ assert_equal(5, method.called)
191
+ assert_in_delta(5, method.total_time, 0.1)
192
+ assert_in_delta(5, method.self_time, 0.1)
193
+ assert_in_delta(0, method.wait_time, 0.01)
194
+ assert_in_delta(0, method.children_time, 0.01)
195
+
196
+ assert_equal(3, method.call_infos.length)
197
+ call_info = method.call_infos[0]
198
+ assert_equal('RecursiveTest#test_cycle->SimpleRecursion#render->Integer#times->SimpleRecursion#render_partial->Kernel#sleep', call_info.call_sequence)
199
+ assert_equal(0, call_info.children.length)
200
+ assert(!call_info.recursive?)
201
+
202
+ call_info = method.call_infos[1]
203
+ assert_equal('RecursiveTest#test_cycle->SimpleRecursion#render->Integer#times->SimpleRecursion#render_partial->SimpleRecursion#render_partial->Kernel#sleep', call_info.call_sequence)
204
+ assert_equal(0, call_info.children.length)
205
+ assert(!call_info.recursive?)
206
+
207
+ call_info = method.call_infos[2]
208
+ assert_equal('RecursiveTest#test_cycle->SimpleRecursion#render->Integer#times->SimpleRecursion#render_partial->Integer#times->SimpleRecursion#render_partial->Kernel#sleep', call_info.call_sequence)
209
+ assert_equal(0, call_info.children.length)
210
+ assert(!call_info.recursive?)
211
+ end
212
+ end
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+ require 'timeout'
6
+
7
+ # -- Test for bug [#5657]
8
+ # http://rubyforge.org/tracker/index.php?func=detail&aid=5657&group_id=1814&atid=7060
9
+
10
+
11
+ class A
12
+ attr_accessor :as
13
+ def initialize
14
+ @as = []
15
+ class << @as
16
+ def <<(an_a)
17
+ super
18
+ end
19
+ end
20
+ end
21
+
22
+ def <<(an_a)
23
+ @as << an_a
24
+ end
25
+ end
26
+
27
+ class SingletonTest < TestCase
28
+ def test_singleton
29
+ result = RubyProf.profile do
30
+ a = A.new
31
+ a << :first_thing
32
+ assert_equal(1, a.as.size)
33
+ end
34
+ printer = RubyProf::FlatPrinter.new(result)
35
+ output = ENV['SHOW_RUBY_PROF_PRINTER_OUTPUT'] == "1" ? STDOUT : ''
36
+ printer.print(output)
37
+ end
38
+ end