ruby-prof 1.0.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 (97) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +523 -0
  3. data/LICENSE +25 -0
  4. data/README.rdoc +5 -0
  5. data/Rakefile +110 -0
  6. data/bin/ruby-prof +380 -0
  7. data/bin/ruby-prof-check-trace +45 -0
  8. data/ext/ruby_prof/extconf.rb +36 -0
  9. data/ext/ruby_prof/rp_allocation.c +292 -0
  10. data/ext/ruby_prof/rp_allocation.h +31 -0
  11. data/ext/ruby_prof/rp_call_info.c +283 -0
  12. data/ext/ruby_prof/rp_call_info.h +35 -0
  13. data/ext/ruby_prof/rp_measure_allocations.c +52 -0
  14. data/ext/ruby_prof/rp_measure_memory.c +42 -0
  15. data/ext/ruby_prof/rp_measure_process_time.c +63 -0
  16. data/ext/ruby_prof/rp_measure_wall_time.c +62 -0
  17. data/ext/ruby_prof/rp_measurement.c +236 -0
  18. data/ext/ruby_prof/rp_measurement.h +49 -0
  19. data/ext/ruby_prof/rp_method.c +642 -0
  20. data/ext/ruby_prof/rp_method.h +70 -0
  21. data/ext/ruby_prof/rp_profile.c +881 -0
  22. data/ext/ruby_prof/rp_profile.h +36 -0
  23. data/ext/ruby_prof/rp_stack.c +196 -0
  24. data/ext/ruby_prof/rp_stack.h +56 -0
  25. data/ext/ruby_prof/rp_thread.c +338 -0
  26. data/ext/ruby_prof/rp_thread.h +36 -0
  27. data/ext/ruby_prof/ruby_prof.c +48 -0
  28. data/ext/ruby_prof/ruby_prof.h +17 -0
  29. data/ext/ruby_prof/vc/ruby_prof.sln +31 -0
  30. data/ext/ruby_prof/vc/ruby_prof.vcxproj +143 -0
  31. data/lib/ruby-prof.rb +53 -0
  32. data/lib/ruby-prof/assets/call_stack_printer.css.html +117 -0
  33. data/lib/ruby-prof/assets/call_stack_printer.js.html +385 -0
  34. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  35. data/lib/ruby-prof/assets/graph_printer.html.erb +356 -0
  36. data/lib/ruby-prof/call_info.rb +57 -0
  37. data/lib/ruby-prof/call_info_visitor.rb +38 -0
  38. data/lib/ruby-prof/compatibility.rb +109 -0
  39. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  40. data/lib/ruby-prof/measurement.rb +14 -0
  41. data/lib/ruby-prof/method_info.rb +90 -0
  42. data/lib/ruby-prof/printers/abstract_printer.rb +118 -0
  43. data/lib/ruby-prof/printers/call_info_printer.rb +51 -0
  44. data/lib/ruby-prof/printers/call_stack_printer.rb +269 -0
  45. data/lib/ruby-prof/printers/call_tree_printer.rb +151 -0
  46. data/lib/ruby-prof/printers/dot_printer.rb +132 -0
  47. data/lib/ruby-prof/printers/flat_printer.rb +52 -0
  48. data/lib/ruby-prof/printers/graph_html_printer.rb +64 -0
  49. data/lib/ruby-prof/printers/graph_printer.rb +114 -0
  50. data/lib/ruby-prof/printers/multi_printer.rb +127 -0
  51. data/lib/ruby-prof/profile.rb +33 -0
  52. data/lib/ruby-prof/rack.rb +171 -0
  53. data/lib/ruby-prof/task.rb +147 -0
  54. data/lib/ruby-prof/thread.rb +35 -0
  55. data/lib/ruby-prof/version.rb +3 -0
  56. data/lib/unprof.rb +10 -0
  57. data/ruby-prof.gemspec +58 -0
  58. data/test/abstract_printer_test.rb +26 -0
  59. data/test/alias_test.rb +129 -0
  60. data/test/basic_test.rb +129 -0
  61. data/test/call_info_visitor_test.rb +31 -0
  62. data/test/duplicate_names_test.rb +32 -0
  63. data/test/dynamic_method_test.rb +53 -0
  64. data/test/enumerable_test.rb +21 -0
  65. data/test/exceptions_test.rb +24 -0
  66. data/test/exclude_methods_test.rb +146 -0
  67. data/test/exclude_threads_test.rb +53 -0
  68. data/test/line_number_test.rb +161 -0
  69. data/test/marshal_test.rb +119 -0
  70. data/test/measure_allocations.rb +30 -0
  71. data/test/measure_allocations_test.rb +385 -0
  72. data/test/measure_allocations_trace_test.rb +385 -0
  73. data/test/measure_memory_trace_test.rb +756 -0
  74. data/test/measure_process_time_test.rb +849 -0
  75. data/test/measure_times.rb +54 -0
  76. data/test/measure_wall_time_test.rb +459 -0
  77. data/test/multi_printer_test.rb +71 -0
  78. data/test/no_method_class_test.rb +15 -0
  79. data/test/parser_timings.rb +24 -0
  80. data/test/pause_resume_test.rb +166 -0
  81. data/test/prime.rb +56 -0
  82. data/test/printer_call_tree_test.rb +31 -0
  83. data/test/printer_flat_test.rb +68 -0
  84. data/test/printer_graph_html_test.rb +60 -0
  85. data/test/printer_graph_test.rb +41 -0
  86. data/test/printers_test.rb +141 -0
  87. data/test/printing_recursive_graph_test.rb +81 -0
  88. data/test/rack_test.rb +157 -0
  89. data/test/recursive_test.rb +210 -0
  90. data/test/singleton_test.rb +38 -0
  91. data/test/stack_printer_test.rb +64 -0
  92. data/test/start_stop_test.rb +109 -0
  93. data/test/test_helper.rb +24 -0
  94. data/test/thread_test.rb +144 -0
  95. data/test/unique_call_path_test.rb +190 -0
  96. data/test/yarv_test.rb +56 -0
  97. metadata +189 -0
@@ -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
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ # Test data
7
+ # A
8
+ # / \
9
+ # B C
10
+ # \
11
+ # B
12
+
13
+ class STPT
14
+ def a
15
+ 100.times{b}
16
+ 300.times{c}
17
+ c;c;c
18
+ end
19
+
20
+ def b
21
+ sleep 0
22
+ end
23
+
24
+ def c
25
+ 5.times{b}
26
+ end
27
+ end
28
+
29
+ class StackPrinterTest < TestCase
30
+ def setup
31
+ # Need to use wall time for this test due to the sleep calls
32
+ RubyProf::measure_mode = RubyProf::WALL_TIME
33
+ end
34
+
35
+ def test_stack_can_be_printed
36
+ start_time = Time.now
37
+ RubyProf.start
38
+ 5.times{STPT.new.a}
39
+ result = RubyProf.stop
40
+ end_time = Time.now
41
+ expected_time = end_time - start_time
42
+
43
+ file_contents = nil
44
+ file_contents = print(result)
45
+ re = /Thread: (\d+)(, Fiber: (\d+))? \([\.0-9]+.[\.0-9]+% ~ ([\.0-9]+)\)/
46
+ assert_match(re, file_contents)
47
+ file_contents =~ re
48
+ actual_time = $4.to_f
49
+ assert_in_delta(expected_time, actual_time, 0.1)
50
+ end
51
+
52
+ private
53
+ def print(result)
54
+ test = caller.first =~ /in `(.*)'/ ? $1 : "test"
55
+ testfile_name = "#{Dir.tmpdir}/ruby_prof_#{test}.html"
56
+ # puts "printing to #{testfile_name}"
57
+ printer = RubyProf::CallStackPrinter.new(result)
58
+ File.open(testfile_name, "w") {|f| printer.print(f, :threshold => 0, :min_percent => 0, :title => "ruby_prof #{test}")}
59
+ system("open '#{testfile_name}'") if RUBY_PLATFORM =~ /darwin/ && ENV['SHOW_RUBY_PROF_PRINTER_OUTPUT']=="1"
60
+ assert File.exist?(testfile_name), "#{testfile_name} does not exist"
61
+ assert File.readable?(testfile_name), "#{testfile_name} is no readable"
62
+ File.read(testfile_name)
63
+ end
64
+ end
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ class StartStopTest < TestCase
7
+ def setup
8
+ # Need to use wall time for this test due to the sleep calls
9
+ RubyProf::measure_mode = RubyProf::WALL_TIME
10
+ end
11
+
12
+ def method1
13
+ RubyProf.start
14
+ method2
15
+ end
16
+
17
+ def method2
18
+ method3
19
+ end
20
+
21
+ def method3
22
+ sleep(2)
23
+ @result = RubyProf.stop
24
+ end
25
+
26
+ def test_extra_stop_should_raise
27
+ RubyProf.start
28
+ assert_raises(RuntimeError) do
29
+ RubyProf.start
30
+ end
31
+
32
+ assert_raises(RuntimeError) do
33
+ RubyProf.profile {}
34
+ end
35
+
36
+ RubyProf.stop # ok
37
+ assert_raises(RuntimeError) do
38
+ RubyProf.stop
39
+ end
40
+ end
41
+
42
+ def test_different_methods
43
+ method1
44
+
45
+ # Ruby prof should be stopped
46
+ assert_equal(false, RubyProf.running?)
47
+
48
+ methods = @result.threads.first.methods.sort.reverse
49
+ assert_equal(4, methods.length)
50
+
51
+ method = methods[0]
52
+ assert_equal('StartStopTest#method1', method.full_name)
53
+ assert_equal(1, method.called)
54
+ assert_in_delta(2, method.total_time, 0.05)
55
+ assert_in_delta(0, method.wait_time, 0.02)
56
+ assert_in_delta(0, method.self_time, 0.02)
57
+ assert_in_delta(2, method.children_time, 0.05)
58
+
59
+ assert_equal(1, method.callees.length)
60
+ call_info = method.callees[0]
61
+ assert_equal('StartStopTest#method2', call_info.target.full_name)
62
+
63
+ method = methods[1]
64
+ assert_equal('StartStopTest#method2', method.full_name)
65
+ assert_equal(1, method.called)
66
+ assert_in_delta(2, method.total_time, 0.05)
67
+ assert_in_delta(0, method.wait_time, 0.02)
68
+ assert_in_delta(0, method.self_time, 0.02)
69
+ assert_in_delta(2, method.children_time, 0.05)
70
+
71
+ assert_equal(1, method.callers.length)
72
+ call_info = method.callers[0]
73
+ assert_equal('StartStopTest#method1', call_info.parent.full_name)
74
+
75
+ assert_equal(1, method.callees.length)
76
+ call_info = method.callees[0]
77
+ assert_equal('StartStopTest#method3', call_info.target.full_name)
78
+
79
+ method = methods[2]
80
+ assert_equal('StartStopTest#method3', method.full_name)
81
+ assert_equal(1, method.called)
82
+ assert_in_delta(2, method.total_time, 0.02)
83
+ assert_in_delta(0, method.wait_time, 0.02)
84
+ assert_in_delta(0, method.self_time, 0.02)
85
+ assert_in_delta(2, method.children_time, 0.02)
86
+
87
+ assert_equal(1, method.callers.length)
88
+ call_info = method.callers[0]
89
+ assert_equal('StartStopTest#method2', call_info.parent.full_name)
90
+
91
+ assert_equal(1, method.callees.length)
92
+ call_info = method.callees[0]
93
+ assert_equal('Kernel#sleep', call_info.target.full_name)
94
+
95
+ method = methods[3]
96
+ assert_equal('Kernel#sleep', method.full_name)
97
+ assert_equal(1, method.called)
98
+ assert_in_delta(2, method.total_time, 0.02)
99
+ assert_in_delta(0, method.wait_time, 0.02)
100
+ assert_in_delta(2, method.self_time, 0.02)
101
+ assert_in_delta(0, method.children_time, 0.02)
102
+
103
+ assert_equal(1, method.callers.length)
104
+ call_info = method.callers[0]
105
+ assert_equal('StartStopTest#method3', call_info.parent.full_name)
106
+
107
+ assert_equal(0, method.callees.length)
108
+ end
109
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+
3
+ require "rubygems"
4
+ gem "minitest"
5
+ require 'singleton'
6
+
7
+ # To make testing/debugging easier, test within this source tree versus an installed gem
8
+ dir = File.dirname(__FILE__)
9
+ root = File.expand_path(File.join(dir, '..'))
10
+ lib = File.expand_path(File.join(root, 'lib'))
11
+ ext = File.expand_path(File.join(root, 'ext', 'ruby_prof'))
12
+
13
+ $LOAD_PATH << lib
14
+ $LOAD_PATH << ext
15
+
16
+ require 'ruby-prof'
17
+
18
+ # Disable minitest parallel tests. The problem is the thread switching will cahnge test results
19
+ # (self vs wait time)
20
+ ENV["N"] = "0"
21
+ require 'minitest/autorun'
22
+
23
+ class TestCase < Minitest::Test
24
+ end
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+ require 'timeout'
6
+ require 'benchmark'
7
+
8
+ # -- Tests ----
9
+ class ThreadTest < TestCase
10
+ def setup
11
+ # Need to use wall time for this test due to the sleep calls
12
+ RubyProf::measure_mode = RubyProf::WALL_TIME
13
+ end
14
+
15
+ def test_thread_count
16
+ RubyProf.start
17
+
18
+ thread = Thread.new do
19
+ sleep(1)
20
+ end
21
+
22
+ thread.join
23
+ result = RubyProf.stop
24
+ assert_equal(2, result.threads.length)
25
+ end
26
+
27
+ def test_thread_identity
28
+ RubyProf.start
29
+ sleep_thread = Thread.new do
30
+ sleep(1)
31
+ end
32
+ sleep_thread.join
33
+ result = RubyProf.stop
34
+
35
+ thread_ids = result.threads.map {|thread| thread.id}.sort
36
+ threads = [Thread.current, sleep_thread]
37
+ assert_equal(2, result.threads.length)
38
+
39
+ assert(thread_ids.include?(threads[0].object_id))
40
+ assert(thread_ids.include?(threads[1].object_id))
41
+
42
+ assert_instance_of(Thread, ObjectSpace._id2ref(thread_ids[0]))
43
+ assert(threads.include?(ObjectSpace._id2ref(thread_ids[0])))
44
+
45
+ assert_instance_of(Thread, ObjectSpace._id2ref(thread_ids[1]))
46
+ assert(threads.include?(ObjectSpace._id2ref(thread_ids[1])))
47
+ end
48
+
49
+ def test_thread_timings
50
+ RubyProf.start
51
+ thread = Thread.new do
52
+ sleep 0
53
+ # force it to hit thread.join, below, first
54
+ # thus forcing sleep(1), below, to be counted as (wall) self_time
55
+ # since we currently count time "in some other thread" as self.wait_time
56
+ # for whatever reason
57
+ sleep(1)
58
+ end
59
+ thread.join
60
+ result = RubyProf.stop
61
+
62
+ # Check background thread
63
+ assert_equal(2, result.threads.length)
64
+
65
+ rp_thread = result.threads.detect {|t| t.id == thread.object_id}
66
+ methods = rp_thread.methods.sort.reverse
67
+ # fails on travis. why?
68
+ # expected_methods = ["ThreadTest#test_thread_timings", "Kernel#sleep"]
69
+ # assert_equal(expected_methods, methods.map(&:full_name))
70
+
71
+ method = methods[0]
72
+ assert_equal('ThreadTest#test_thread_timings', method.full_name)
73
+ assert_equal(1, method.called)
74
+ assert_in_delta(1, method.total_time, 0.05)
75
+ assert_in_delta(0, method.self_time, 0.05)
76
+ assert_in_delta(0, method.wait_time, 0.05)
77
+ assert_in_delta(1, method.children_time, 0.05)
78
+ assert_equal(1, method.callers.length)
79
+
80
+ method = methods[1]
81
+ assert_equal('Kernel#sleep', method.full_name)
82
+ assert_equal(2, method.called)
83
+ assert_in_delta(1, method.total_time, 0.05)
84
+ assert_in_delta(1.0, method.self_time, 0.05)
85
+ assert_in_delta(0, method.wait_time, 0.05)
86
+ assert_in_delta(0, method.children_time, 0.05)
87
+
88
+ assert_equal(1, method.callers.length)
89
+ assert_equal(0, method.callees.length)
90
+
91
+ # Check foreground thread
92
+ rp_thread = result.threads.detect {|athread| athread.id == Thread.current.object_id}
93
+ methods = rp_thread.methods.sort.reverse
94
+ assert_equal(4, methods.length)
95
+ methods = methods.sort.reverse
96
+
97
+ method = methods[0]
98
+ assert_equal('ThreadTest#test_thread_timings', method.full_name)
99
+ # the sub calls to Object#new, when popped,
100
+ # cause the parent frame to be created for method #test_thread_timings, which means a +1 when it's popped in the end
101
+ # xxxx a test that shows it the other way, too (never creates parent frame--if that's even possible)
102
+ assert_equal(1, method.called)
103
+ assert_in_delta(1, method.total_time, 0.05)
104
+ assert_in_delta(0, method.self_time, 0.05)
105
+ assert_in_delta(0, method.wait_time, 0.05)
106
+ assert_in_delta(1, method.children_time, 0.05)
107
+
108
+ assert_equal(1, method.callers.length)
109
+ assert_equal(2, method.callees.length)
110
+
111
+ method = methods[1]
112
+ assert_equal('Thread#join', method.full_name)
113
+ assert_equal(1, method.called)
114
+ assert_in_delta(1, method.total_time, 0.05)
115
+ assert_in_delta(0, method.self_time, 0.05)
116
+ assert_in_delta(1.0, method.wait_time, 0.05)
117
+ assert_in_delta(0, method.children_time, 0.05)
118
+
119
+ assert_equal(1, method.callers.length)
120
+ assert_equal(0, method.callees.length)
121
+
122
+ method = methods[2]
123
+ assert_equal('<Class::Thread>#new', method.full_name)
124
+ assert_equal(1, method.called)
125
+ assert_in_delta(0, method.total_time, 0.05)
126
+ assert_in_delta(0, method.self_time, 0.05)
127
+ assert_in_delta(0, method.wait_time, 0.05)
128
+ assert_in_delta(0, method.children_time, 0.05)
129
+
130
+ assert_equal(1, method.callers.length)
131
+ assert_equal(1, method.callees.length)
132
+
133
+ method = methods[3]
134
+ assert_equal('Thread#initialize', method.full_name)
135
+ assert_equal(1, method.called)
136
+ assert_in_delta(0, method.total_time, 0.05)
137
+ assert_in_delta(0, method.self_time, 0.05)
138
+ assert_in_delta(0, method.wait_time, 0.05)
139
+ assert_in_delta(0, method.children_time, 0.05)
140
+
141
+ assert_equal(1, method.callers.length)
142
+ assert_equal(0, method.callees.length)
143
+ end
144
+ end
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ class UniqueCallPath
7
+ def method_a(i)
8
+ if i==1
9
+ method_b
10
+ else
11
+ method_c
12
+ end
13
+ end
14
+
15
+ def method_b
16
+ method_c
17
+ end
18
+
19
+ def method_c
20
+ end
21
+
22
+ def method_k(i)
23
+ method_a(i)
24
+ end
25
+ end
26
+
27
+
28
+ # -- Tests ----
29
+ class UniqueCallPathTest < TestCase
30
+ def test_root_method
31
+ unique_call_path = UniqueCallPath.new
32
+
33
+ result = RubyProf.profile do
34
+ unique_call_path.method_a(1)
35
+ end
36
+
37
+ root_methods = Array.new
38
+ result.threads.each do |thread|
39
+ thread.methods.each do | m |
40
+ if m.root?
41
+ root_methods.push(m)
42
+ end
43
+ end
44
+ end
45
+
46
+ assert_equal(1, root_methods.length)
47
+ assert_equal("UniqueCallPathTest#test_root_method", root_methods[0].full_name)
48
+ end
49
+
50
+ def test_root_children
51
+ unique_call_path = UniqueCallPath.new
52
+
53
+ result = RubyProf.profile do
54
+ unique_call_path.method_a(1)
55
+ unique_call_path.method_k(2)
56
+ end
57
+
58
+ root_methods = Array.new
59
+ result.threads.each do |thread|
60
+ thread.methods.each do | m |
61
+ if m.root?
62
+ root_methods.push(m)
63
+ end
64
+ end
65
+ end
66
+
67
+ assert_equal(1, root_methods.length)
68
+
69
+ root_children = Array.new
70
+ root_methods[0].callees.each do | c |
71
+ if c.parent.eql?(root_methods[0])
72
+ root_children.push(c)
73
+ end
74
+ end
75
+
76
+ children = root_children.sort do |c1, c2|
77
+ c1.target.full_name <=> c2.target.full_name
78
+ end
79
+
80
+ assert_equal(2, children.length)
81
+ assert_equal("UniqueCallPath#method_a", children[0].target.full_name)
82
+ assert_equal("UniqueCallPath#method_k", children[1].target.full_name)
83
+ end
84
+
85
+ def test_children_of
86
+ unique_call_path = UniqueCallPath.new
87
+
88
+ result = RubyProf.profile do
89
+ unique_call_path.method_a(1)
90
+ unique_call_path.method_k(2)
91
+ end
92
+
93
+ root_methods = Array.new
94
+ result.threads.each do |thread|
95
+ thread.methods.each do | m |
96
+ if m.root?
97
+ root_methods.push(m)
98
+ end
99
+ end
100
+ end
101
+
102
+ assert_equal(1, root_methods.length)
103
+ method = root_methods[0]
104
+ assert_equal('UniqueCallPathTest#test_children_of', method.full_name)
105
+
106
+ call_info_a = root_methods[0].callees.detect do |call_info|
107
+ call_info.target.full_name == "UniqueCallPath#method_a"
108
+ end
109
+ refute_nil(call_info_a)
110
+
111
+ children_of_a = Array.new
112
+
113
+ call_info_a.target.callees.each do | c |
114
+ if c.parent.eql?(call_info_a)
115
+ children_of_a.push(c)
116
+ end
117
+ end
118
+
119
+ assert_equal(2, call_info_a.target.callees.length)
120
+
121
+ children_of_a = children_of_a.sort do |c1, c2|
122
+ c1.target.full_name <=> c2.target.full_name
123
+ end
124
+
125
+ assert_equal(0, children_of_a.length)
126
+ end
127
+
128
+ def test_id2ref
129
+ unique_call_path = UniqueCallPath.new
130
+
131
+ result = RubyProf.profile do
132
+ unique_call_path.method_a(1)
133
+ end
134
+
135
+ root_methods = Array.new
136
+ result.threads.each do |thread|
137
+ thread.methods.each do | m |
138
+ if m.root?
139
+ root_methods.push(m)
140
+ end
141
+ end
142
+ end
143
+
144
+ child = root_methods[0].callees[0]
145
+ refute_equal(0, child.object_id)
146
+ #assert_equal(RubyProf::CallInfo.id2ref(child.id).target.full_name, child.target.full_name)
147
+ end
148
+
149
+ def test_unique_path
150
+ unique_call_path = UniqueCallPath.new
151
+
152
+ result = RubyProf.profile do
153
+ unique_call_path.method_a(1)
154
+ unique_call_path.method_k(1)
155
+ end
156
+
157
+ root_methods = Array.new
158
+ result.threads.each do |thread|
159
+ thread.methods.each do | m |
160
+ if m.root?
161
+ root_methods.push(m)
162
+ end
163
+ end
164
+ end
165
+
166
+ assert_equal(1, root_methods.length)
167
+
168
+ call_info_a = root_methods[0].callees.detect do |call_info|
169
+ call_info.target.full_name == "UniqueCallPath#method_a"
170
+ end
171
+ refute_nil(call_info_a)
172
+
173
+ children_of_a = Array.new
174
+ call_info_a.target.callees.each do |c|
175
+ if c.parent.eql?(call_info_a.target)
176
+ children_of_a.push(c)
177
+ end
178
+ end
179
+
180
+ assert_equal(1, call_info_a.target.callees.length)
181
+
182
+ children_of_a = children_of_a.sort do |c1, c2|
183
+ c1.target.full_name <=> c2.target.full_name
184
+ end
185
+
186
+ assert_equal(1, children_of_a.length)
187
+ assert_equal(2, children_of_a[0].called)
188
+ assert_equal("UniqueCallPath#method_b", children_of_a[0].target.full_name)
189
+ end
190
+ end