ruby-prof 1.4.4-x64-mingw-ucrt

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 (106) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +608 -0
  3. data/LICENSE +25 -0
  4. data/README.md +5 -0
  5. data/Rakefile +98 -0
  6. data/bin/ruby-prof +328 -0
  7. data/bin/ruby-prof-check-trace +45 -0
  8. data/ext/ruby_prof/extconf.rb +22 -0
  9. data/ext/ruby_prof/rp_aggregate_call_tree.c +59 -0
  10. data/ext/ruby_prof/rp_aggregate_call_tree.h +13 -0
  11. data/ext/ruby_prof/rp_allocation.c +287 -0
  12. data/ext/ruby_prof/rp_allocation.h +31 -0
  13. data/ext/ruby_prof/rp_call_tree.c +367 -0
  14. data/ext/ruby_prof/rp_call_tree.h +43 -0
  15. data/ext/ruby_prof/rp_call_trees.c +288 -0
  16. data/ext/ruby_prof/rp_call_trees.h +28 -0
  17. data/ext/ruby_prof/rp_measure_allocations.c +47 -0
  18. data/ext/ruby_prof/rp_measure_memory.c +46 -0
  19. data/ext/ruby_prof/rp_measure_process_time.c +66 -0
  20. data/ext/ruby_prof/rp_measure_wall_time.c +64 -0
  21. data/ext/ruby_prof/rp_measurement.c +237 -0
  22. data/ext/ruby_prof/rp_measurement.h +50 -0
  23. data/ext/ruby_prof/rp_method.c +491 -0
  24. data/ext/ruby_prof/rp_method.h +62 -0
  25. data/ext/ruby_prof/rp_profile.c +915 -0
  26. data/ext/ruby_prof/rp_profile.h +35 -0
  27. data/ext/ruby_prof/rp_stack.c +212 -0
  28. data/ext/ruby_prof/rp_stack.h +53 -0
  29. data/ext/ruby_prof/rp_thread.c +362 -0
  30. data/ext/ruby_prof/rp_thread.h +39 -0
  31. data/ext/ruby_prof/ruby_prof.c +52 -0
  32. data/ext/ruby_prof/ruby_prof.h +26 -0
  33. data/ext/ruby_prof/vc/ruby_prof.sln +39 -0
  34. data/ext/ruby_prof/vc/ruby_prof.vcxproj +160 -0
  35. data/lib/3.1/ruby_prof.so +0 -0
  36. data/lib/ruby-prof/assets/call_stack_printer.html.erb +711 -0
  37. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  38. data/lib/ruby-prof/assets/graph_printer.html.erb +355 -0
  39. data/lib/ruby-prof/call_tree.rb +57 -0
  40. data/lib/ruby-prof/call_tree_visitor.rb +36 -0
  41. data/lib/ruby-prof/compatibility.rb +99 -0
  42. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  43. data/lib/ruby-prof/measurement.rb +17 -0
  44. data/lib/ruby-prof/method_info.rb +78 -0
  45. data/lib/ruby-prof/printers/abstract_printer.rb +137 -0
  46. data/lib/ruby-prof/printers/call_info_printer.rb +53 -0
  47. data/lib/ruby-prof/printers/call_stack_printer.rb +180 -0
  48. data/lib/ruby-prof/printers/call_tree_printer.rb +147 -0
  49. data/lib/ruby-prof/printers/dot_printer.rb +132 -0
  50. data/lib/ruby-prof/printers/flat_printer.rb +53 -0
  51. data/lib/ruby-prof/printers/graph_html_printer.rb +63 -0
  52. data/lib/ruby-prof/printers/graph_printer.rb +113 -0
  53. data/lib/ruby-prof/printers/multi_printer.rb +127 -0
  54. data/lib/ruby-prof/profile.rb +37 -0
  55. data/lib/ruby-prof/rack.rb +95 -0
  56. data/lib/ruby-prof/task.rb +147 -0
  57. data/lib/ruby-prof/thread.rb +20 -0
  58. data/lib/ruby-prof/version.rb +3 -0
  59. data/lib/ruby-prof.rb +52 -0
  60. data/lib/unprof.rb +10 -0
  61. data/ruby-prof.gemspec +64 -0
  62. data/test/abstract_printer_test.rb +26 -0
  63. data/test/alias_test.rb +122 -0
  64. data/test/basic_test.rb +43 -0
  65. data/test/call_tree_visitor_test.rb +32 -0
  66. data/test/call_trees_test.rb +66 -0
  67. data/test/duplicate_names_test.rb +32 -0
  68. data/test/dynamic_method_test.rb +67 -0
  69. data/test/enumerable_test.rb +21 -0
  70. data/test/exceptions_test.rb +24 -0
  71. data/test/exclude_methods_test.rb +151 -0
  72. data/test/exclude_threads_test.rb +53 -0
  73. data/test/fiber_test.rb +129 -0
  74. data/test/gc_test.rb +100 -0
  75. data/test/inverse_call_tree_test.rb +175 -0
  76. data/test/line_number_test.rb +158 -0
  77. data/test/marshal_test.rb +145 -0
  78. data/test/measure_allocations.rb +26 -0
  79. data/test/measure_allocations_test.rb +333 -0
  80. data/test/measure_memory_test.rb +688 -0
  81. data/test/measure_process_time_test.rb +1614 -0
  82. data/test/measure_times.rb +56 -0
  83. data/test/measure_wall_time_test.rb +426 -0
  84. data/test/multi_printer_test.rb +71 -0
  85. data/test/no_method_class_test.rb +15 -0
  86. data/test/pause_resume_test.rb +175 -0
  87. data/test/prime.rb +54 -0
  88. data/test/prime_script.rb +6 -0
  89. data/test/printer_call_stack_test.rb +27 -0
  90. data/test/printer_call_tree_test.rb +30 -0
  91. data/test/printer_flat_test.rb +99 -0
  92. data/test/printer_graph_html_test.rb +59 -0
  93. data/test/printer_graph_test.rb +40 -0
  94. data/test/printers_test.rb +141 -0
  95. data/test/printing_recursive_graph_test.rb +81 -0
  96. data/test/profile_test.rb +16 -0
  97. data/test/rack_test.rb +93 -0
  98. data/test/recursive_test.rb +430 -0
  99. data/test/singleton_test.rb +38 -0
  100. data/test/stack_printer_test.rb +64 -0
  101. data/test/start_stop_test.rb +109 -0
  102. data/test/test_helper.rb +13 -0
  103. data/test/thread_test.rb +144 -0
  104. data/test/unique_call_path_test.rb +136 -0
  105. data/test/yarv_test.rb +60 -0
  106. metadata +187 -0
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ class DuplicateNamesTest < TestCase
7
+ def test_names
8
+ result = RubyProf::profile do
9
+ str = %{module Foo; class Bar; def foo; end end end}
10
+
11
+ eval str
12
+ Foo::Bar.new.foo
13
+ DuplicateNamesTest.class_eval {remove_const :Foo}
14
+
15
+ eval str
16
+ Foo::Bar.new.foo
17
+ DuplicateNamesTest.class_eval {remove_const :Foo}
18
+
19
+ eval str
20
+ Foo::Bar.new.foo
21
+ end
22
+
23
+ # There should be 3 foo methods
24
+ methods = result.threads.first.methods.sort.reverse
25
+
26
+ methods = methods.select do |method|
27
+ method.full_name == 'DuplicateNamesTest::Foo::Bar#foo'
28
+ end
29
+
30
+ assert_equal(3, methods.length)
31
+ end
32
+ end
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path("../test_helper", __FILE__)
5
+
6
+ class DynamicMethodTest < TestCase
7
+
8
+ class FruitMedley
9
+ define_method(:apple) do
10
+ sleep(0.1)
11
+ "I'm a peach"
12
+ end
13
+
14
+ define_method(:orange) do
15
+ sleep(0.2)
16
+ "I'm an orange"
17
+ end
18
+
19
+ [:banana, :peach].each_with_index do |fruit,i|
20
+ define_method(fruit) do
21
+ sleep(i == 0 ? 0.3 : 0.4)
22
+ "I'm a #{fruit}"
23
+ end
24
+ end
25
+ end
26
+
27
+ def setup
28
+ # Need to use wall time for this test due to the sleep calls
29
+ RubyProf::measure_mode = RubyProf::WALL_TIME
30
+ end
31
+
32
+ def test_dynamic_method
33
+ medley = FruitMedley.new
34
+ result = RubyProf.profile do
35
+ medley.apple
36
+ medley.orange
37
+ medley.banana
38
+ medley.peach
39
+ end
40
+
41
+ methods = result.threads.first.methods.sort.reverse
42
+
43
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.1')
44
+ expected_method_names = %w(
45
+ DynamicMethodTest#test_dynamic_method
46
+ Kernel#sleep
47
+ DynamicMethodTest::FruitMedley#peach
48
+ DynamicMethodTest::FruitMedley#banana
49
+ DynamicMethodTest::FruitMedley#orange
50
+ DynamicMethodTest::FruitMedley#apple
51
+ Symbol#to_s
52
+ )
53
+ else
54
+ expected_method_names = %w(
55
+ DynamicMethodTest#test_dynamic_method
56
+ Kernel#sleep
57
+ DynamicMethodTest::FruitMedley#peach
58
+ DynamicMethodTest::FruitMedley#banana
59
+ DynamicMethodTest::FruitMedley#orange
60
+ DynamicMethodTest::FruitMedley#apple
61
+ Integer#==
62
+ )
63
+ end
64
+
65
+ assert_equal expected_method_names.join("\n"), methods.map(&:full_name).join("\n")
66
+ end
67
+ end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ # -- Test for bug
7
+ # http://github.com/rdp/ruby-prof/issues#issue/12
8
+
9
+ class EnumerableTest < TestCase
10
+ def test_enumerable
11
+ result = RubyProf.profile do
12
+ 3.times { [1,2,3].any? {|n| n} }
13
+ end
14
+ methods = if RUBY_VERSION >= "2.2.0"
15
+ %w(EnumerableTest#test_enumerable Integer#times Array#any?)
16
+ else
17
+ %w(EnumerableTest#test_enumerable Integer#times Enumerable#any? Array#each)
18
+ end
19
+ assert_equal(methods, result.threads.first.methods.map(&:full_name))
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ class ExceptionsTest < TestCase
7
+ def test_profile
8
+ result = begin
9
+ RubyProf.profile do
10
+ raise(RuntimeError, 'Test error')
11
+ end
12
+ rescue
13
+ end
14
+ assert_kind_of(RubyProf::Profile, result)
15
+ end
16
+
17
+ def test_profile_allows_exceptions
18
+ assert_raises(RuntimeError) do
19
+ RubyProf.profile(:allow_exceptions => true) do
20
+ raise(RuntimeError, 'Test error')
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ module ExcludeMethodsModule
7
+ def c
8
+ 1.times { |i| ExcludeMethodsModule.d }
9
+ end
10
+
11
+ def self.d
12
+ 1.times { |i| ExcludeMethodsClass.e }
13
+ end
14
+ end
15
+
16
+ class ExcludeMethodsClass
17
+ include ExcludeMethodsModule
18
+
19
+ def a
20
+ 1.times { |i| b }
21
+ end
22
+
23
+ def b
24
+ 1.times { |i| c; self.class.e }
25
+ end
26
+
27
+ def self.e
28
+ 1.times { |i| f }
29
+ end
30
+
31
+ def self.f
32
+ sleep 0.1
33
+ end
34
+ end
35
+
36
+ class ExcludeMethodsTest < TestCase
37
+ def setup
38
+ # Need to use wall time for this test due to the sleep calls
39
+ RubyProf::measure_mode = RubyProf::WALL_TIME
40
+ end
41
+
42
+ def test_methods_can_be_profiled
43
+ obj = ExcludeMethodsClass.new
44
+ prf = RubyProf::Profile.new
45
+
46
+ result = prf.profile {obj.a}
47
+ methods = result.threads.first.methods.sort.reverse
48
+ assert_equal(10, methods.count)
49
+ assert_equal('ExcludeMethodsTest#test_methods_can_be_profiled', methods[0].full_name)
50
+ assert_equal('ExcludeMethodsClass#a', methods[1].full_name)
51
+ assert_equal('Integer#times', methods[2].full_name)
52
+ assert_equal('ExcludeMethodsClass#b', methods[3].full_name)
53
+ assert_equal('<Class::ExcludeMethodsClass>#e', methods[4].full_name)
54
+ assert_equal('<Class::ExcludeMethodsClass>#f', methods[5].full_name)
55
+ assert_equal('Kernel#sleep', methods[6].full_name)
56
+ assert_equal('ExcludeMethodsModule#c', methods[7].full_name)
57
+ assert_equal('<Module::ExcludeMethodsModule>#d', methods[8].full_name)
58
+ assert_equal('Kernel#class', methods[9].full_name)
59
+ end
60
+
61
+ def test_methods_can_be_hidden1
62
+ obj = ExcludeMethodsClass.new
63
+ prf = RubyProf::Profile.new
64
+
65
+ prf.exclude_methods!(Integer, :times)
66
+
67
+ result = prf.profile {obj.a}
68
+ methods = result.threads.first.methods.sort.reverse
69
+
70
+ assert_equal(9, methods.count)
71
+ assert_equal('ExcludeMethodsTest#test_methods_can_be_hidden1', methods[0].full_name)
72
+ assert_equal('ExcludeMethodsClass#a', methods[1].full_name)
73
+ assert_equal('ExcludeMethodsClass#b', methods[2].full_name)
74
+ assert_equal('<Class::ExcludeMethodsClass>#e', methods[3].full_name)
75
+ assert_equal('<Class::ExcludeMethodsClass>#f', methods[4].full_name)
76
+ assert_equal('Kernel#sleep', methods[5].full_name)
77
+ assert_equal('ExcludeMethodsModule#c', methods[6].full_name)
78
+ assert_equal('<Module::ExcludeMethodsModule>#d', methods[7].full_name)
79
+ assert_equal('Kernel#class', methods[8].full_name)
80
+ end
81
+
82
+ def test_methods_can_be_hidden2
83
+ obj = ExcludeMethodsClass.new
84
+ prf = RubyProf::Profile.new
85
+
86
+ prf.exclude_methods!(Integer, :times)
87
+ prf.exclude_methods!(ExcludeMethodsClass.singleton_class, :f)
88
+ prf.exclude_methods!(ExcludeMethodsModule.singleton_class, :d)
89
+
90
+ result = prf.profile {obj.a}
91
+ methods = result.threads.first.methods.sort.reverse
92
+
93
+ assert_equal(7, methods.count)
94
+ assert_equal('ExcludeMethodsTest#test_methods_can_be_hidden2', methods[0].full_name)
95
+ assert_equal('ExcludeMethodsClass#a', methods[1].full_name)
96
+ assert_equal('ExcludeMethodsClass#b', methods[2].full_name)
97
+ assert_equal('<Class::ExcludeMethodsClass>#e', methods[3].full_name)
98
+ assert_equal('Kernel#sleep', methods[4].full_name)
99
+ assert_equal('ExcludeMethodsModule#c', methods[5].full_name)
100
+ assert_equal('Kernel#class', methods[6].full_name)
101
+ end
102
+
103
+ def test_exclude_common_methods1
104
+ obj = ExcludeMethodsClass.new
105
+ prf = RubyProf::Profile.new
106
+
107
+ prf.exclude_common_methods!
108
+
109
+ result = prf.profile {obj.a}
110
+ methods = result.threads.first.methods.sort.reverse
111
+
112
+ assert_equal(9, methods.count)
113
+ assert_equal('ExcludeMethodsTest#test_exclude_common_methods1', methods[0].full_name)
114
+ assert_equal('ExcludeMethodsClass#a', methods[1].full_name)
115
+ assert_equal('ExcludeMethodsClass#b', methods[2].full_name)
116
+ assert_equal('<Class::ExcludeMethodsClass>#e', methods[3].full_name)
117
+ assert_equal('<Class::ExcludeMethodsClass>#f', methods[4].full_name)
118
+ assert_equal('Kernel#sleep', methods[5].full_name)
119
+ assert_equal('ExcludeMethodsModule#c', methods[6].full_name)
120
+ assert_equal('<Module::ExcludeMethodsModule>#d', methods[7].full_name)
121
+ assert_equal('Kernel#class', methods[8].full_name)
122
+ end
123
+
124
+ def test_exclude_common_methods2
125
+ obj = ExcludeMethodsClass.new
126
+
127
+ result = RubyProf.profile(exclude_common: true) { 5.times {obj.a} }
128
+ methods = result.threads.first.methods.sort.reverse
129
+
130
+ assert_equal(9, methods.count)
131
+ assert_equal('ExcludeMethodsTest#test_exclude_common_methods2', methods[0].full_name)
132
+ assert_equal('ExcludeMethodsClass#a', methods[1].full_name)
133
+ assert_equal('ExcludeMethodsClass#b', methods[2].full_name)
134
+ end
135
+
136
+ private
137
+
138
+ def assert_method_has_been_excluded(result, excluded_method)
139
+ result.threads.each do |thread|
140
+ thread.methods.each do |method|
141
+ method.call_trees.each do |ci|
142
+ assert(ci.target != excluded_method, "broken self")
143
+ assert(ci.parent.target != excluded_method, "broken parent") if ci.parent
144
+ ci.children.each do |callee|
145
+ assert(callee.target != excluded_method, "broken kid")
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+
7
+ # -- Tests ----
8
+ class ExcludeThreadsTest < TestCase
9
+ def test_exclude_threads
10
+
11
+ def thread1_proc
12
+ sleep(0.5)
13
+ sleep(2)
14
+ end
15
+
16
+ def thread2_proc
17
+ sleep(0.5)
18
+ sleep(2)
19
+ end
20
+
21
+ thread1 = Thread.new do
22
+ thread1_proc
23
+ end
24
+
25
+ thread2 = Thread.new do
26
+ thread2_proc
27
+ end
28
+
29
+ # exclude_threads already includes the minitest thread pool
30
+ RubyProf.exclude_threads += [ thread2 ]
31
+
32
+ RubyProf.start
33
+
34
+ thread1.join
35
+ thread2.join
36
+
37
+ result = RubyProf.stop
38
+
39
+ assert_equal(2, result.threads.length)
40
+
41
+ output = Array.new
42
+ result.threads.each do |thread|
43
+ thread.methods.each do | m |
44
+ if m.full_name.index("ExcludeThreadsTest#thread") == 0
45
+ output.push(m.full_name)
46
+ end
47
+ end
48
+ end
49
+
50
+ assert_equal(1, output.length)
51
+ assert_equal("ExcludeThreadsTest#thread1_proc", output[0])
52
+ end
53
+ end
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+ require 'fiber'
6
+ require 'timeout'
7
+ require 'set'
8
+
9
+ # -- Tests ----
10
+ class FiberTest < TestCase
11
+
12
+ def enumerator_with_fibers
13
+ enum = Enumerator.new do |yielder|
14
+ [1,2].each do |x|
15
+ yielder.yield x
16
+ end
17
+ end
18
+
19
+ enum.next
20
+ enum.next
21
+ end
22
+
23
+ def fiber_yield_resume
24
+ fiber = Fiber.new do
25
+ Fiber.yield 1
26
+ Fiber.yield 2
27
+ end
28
+
29
+ fiber.resume
30
+ fiber.resume
31
+ end
32
+
33
+ def setup
34
+ # Need to use wall time for this test due to the sleep calls
35
+ RubyProf::measure_mode = RubyProf::WALL_TIME
36
+ end
37
+
38
+ def test_fibers
39
+ result = RubyProf.profile { enumerator_with_fibers }
40
+
41
+ assert_equal(2, result.threads.size)
42
+
43
+ thread1 = result.threads[0]
44
+ methods = thread1.methods.sort.reverse
45
+ assert_equal(5, methods.count)
46
+
47
+ method = methods[0]
48
+ assert_equal('FiberTest#test_fibers', method.full_name)
49
+ assert_equal(1, method.called)
50
+
51
+ method = methods[1]
52
+ assert_equal('FiberTest#enumerator_with_fibers', method.full_name)
53
+ assert_equal(1, method.called)
54
+
55
+ method = methods[2]
56
+ assert_equal('Enumerator#next', method.full_name)
57
+ assert_equal(2, method.called)
58
+
59
+ method = methods[3]
60
+ assert_equal('Class#new', method.full_name)
61
+ assert_equal(1, method.called)
62
+
63
+ method = methods[4]
64
+ assert_equal('Enumerator#initialize', method.full_name)
65
+ assert_equal(1, method.called)
66
+
67
+ thread2 = result.threads[1]
68
+ methods = thread2.methods.sort.reverse
69
+ assert_equal(4, methods.count)
70
+
71
+ method = methods[0]
72
+ assert_equal('Enumerator#each', method.full_name)
73
+ assert_equal(1, method.called)
74
+
75
+ method = methods[1]
76
+ assert_equal('Enumerator::Generator#each', method.full_name)
77
+ assert_equal(1, method.called)
78
+
79
+ method = methods[2]
80
+ assert_equal('Array#each', method.full_name)
81
+ assert_equal(1, method.called)
82
+
83
+ method = methods[3]
84
+ assert_equal('Enumerator::Yielder#yield', method.full_name)
85
+ assert_equal(2, method.called)
86
+ end
87
+
88
+ def test_fiber_resume
89
+ result = RubyProf.profile { fiber_yield_resume }
90
+
91
+ assert_equal(2, result.threads.size)
92
+
93
+ thread1 = result.threads[0]
94
+ methods = thread1.methods.sort.reverse
95
+ assert_equal(5, methods.count)
96
+
97
+ method = methods[0]
98
+ assert_equal('FiberTest#test_fiber_resume', method.full_name)
99
+ assert_equal(1, method.called)
100
+
101
+ method = methods[1]
102
+ assert_equal('FiberTest#fiber_yield_resume', method.full_name)
103
+ assert_equal(1, method.called)
104
+
105
+ method = methods[2]
106
+ assert_equal('Fiber#resume', method.full_name)
107
+ assert_equal(2, method.called)
108
+
109
+ method = methods[3]
110
+ assert_equal('Class#new', method.full_name)
111
+ assert_equal(1, method.called)
112
+
113
+ method = methods[4]
114
+ assert_equal('Fiber#initialize', method.full_name)
115
+ assert_equal(1, method.called)
116
+
117
+ thread1 = result.threads[1]
118
+ methods = thread1.methods.sort.reverse
119
+ assert_equal(2, methods.count)
120
+
121
+ method = methods[0]
122
+ assert_equal('FiberTest#fiber_yield_resume', method.full_name)
123
+ assert_equal(1, method.called)
124
+
125
+ method = methods[1]
126
+ assert_equal('<Class::Fiber>#yield', method.full_name)
127
+ assert_equal(2, method.called)
128
+ end
129
+ end
data/test/gc_test.rb ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+ Minitest::Test.i_suck_and_my_tests_are_order_dependent!
6
+
7
+ class GcTest < TestCase
8
+ def setup
9
+ GC.stress = true
10
+ end
11
+
12
+ def teardown
13
+ GC.stress = false
14
+ end
15
+
16
+ def some_method
17
+ Array.new(3 * 4)
18
+ end
19
+
20
+ def run_profile
21
+ RubyProf.profile do
22
+ self.some_method
23
+ end
24
+ end
25
+
26
+ def test_hold_onto_thread
27
+ threads = 5.times.reduce(Array.new) do |array, i|
28
+ array.concat(run_profile.threads)
29
+ array
30
+ end
31
+
32
+ GC.start
33
+
34
+ threads.each do |thread|
35
+ refute_nil(thread.id)
36
+ end
37
+ end
38
+
39
+
40
+ def test_hold_onto_method
41
+ methods = 5.times.reduce(Array.new) do |array, i|
42
+ profile = run_profile
43
+ array.concat(profile.threads.map(&:methods).flatten)
44
+ array
45
+ end
46
+
47
+ GC.start
48
+
49
+ methods.each do |method|
50
+ refute_nil(method.method_name)
51
+ end
52
+ end
53
+
54
+ def test_hold_onto_call_trees
55
+ method_call_infos = 5.times.reduce(Array.new) do |array, i|
56
+ profile = run_profile
57
+ call_trees = profile.threads.map(&:methods).flatten.map(&:call_trees).flatten
58
+ array.concat(call_trees)
59
+ array
60
+ end
61
+
62
+ GC.start
63
+
64
+ method_call_infos.each do |call_trees|
65
+ refute_empty(call_trees.call_trees)
66
+ end
67
+ end
68
+
69
+ def test_hold_onto_measurements
70
+ measurements = 5.times.reduce(Array.new) do |array, i|
71
+ profile = run_profile
72
+ measurements_2 = profile.threads.map(&:methods).flatten.map(&:measurement)
73
+ array.concat(measurements_2)
74
+ array
75
+ end
76
+
77
+ GC.start
78
+
79
+ measurements.each do |measurement|
80
+ error = assert_raises(RuntimeError) do
81
+ measurement.total_time
82
+ end
83
+ assert_match(/RubyProf::Measurement instance has already been freed/, error.message)
84
+ end
85
+ assert(true)
86
+ end
87
+
88
+ def test_hold_onto_root_call_tree
89
+ call_trees = 5.times.reduce(Array.new) do |array, i|
90
+ array.concat(run_profile.threads.map(&:call_tree))
91
+ array
92
+ end
93
+
94
+ GC.start
95
+
96
+ call_trees.each do |call_tree|
97
+ refute_nil(call_tree.source_file)
98
+ end
99
+ end
100
+ end