airbnb-ruby-prof 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,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,79 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+ require 'timeout'
6
+ require 'set'
7
+ begin
8
+ require 'fiber'
9
+ rescue LoadError
10
+ end
11
+
12
+ # -- Tests ----
13
+ class FiberTest < TestCase
14
+
15
+ def fiber_test
16
+ @fiber_ids << Fiber.current.object_id
17
+ enum = Enumerator.new do |yielder|
18
+ [1,2].each do |x|
19
+ @fiber_ids << Fiber.current.object_id
20
+ sleep 0.1
21
+ yielder.yield x
22
+ end
23
+ end
24
+ while true
25
+ begin
26
+ enum.next
27
+ rescue StopIteration
28
+ break
29
+ end
30
+ end
31
+ sleep 0.1
32
+ end
33
+
34
+ def setup
35
+ # Need to use wall time for this test due to the sleep calls
36
+ RubyProf::measure_mode = RubyProf::WALL_TIME
37
+ @fiber_ids = Set.new
38
+ @root_fiber = Fiber.current.object_id
39
+ @thread_id = Thread.current.object_id
40
+ end
41
+
42
+ def test_fibers
43
+ result = RubyProf.profile { fiber_test }
44
+ profiled_fiber_ids = result.threads.map(&:fiber_id)
45
+ assert_equal(2, result.threads.length)
46
+ assert_equal([@thread_id], result.threads.map(&:id).uniq)
47
+ assert_equal(@fiber_ids, Set.new(profiled_fiber_ids))
48
+
49
+ assert profiled_fiber_ids.include?(@root_fiber)
50
+ assert(root_fiber_profile = result.threads.detect{|t| t.fiber_id == @root_fiber})
51
+ assert(enum_fiber_profile = result.threads.detect{|t| t.fiber_id != @root_fiber})
52
+
53
+ assert_in_delta(0.3, root_fiber_profile.total_time, 0.05)
54
+ assert_in_delta(0.2, enum_fiber_profile.total_time, 0.05)
55
+
56
+ assert(method_next = root_fiber_profile.methods.detect{|m| m.full_name == "Enumerator#next"})
57
+ assert(method_each = enum_fiber_profile.methods.detect{|m| m.full_name == "Enumerator#each"})
58
+
59
+ assert_in_delta(0.2, method_next.total_time, 0.05)
60
+ assert_in_delta(0.2, method_each.total_time, 0.05)
61
+ end
62
+
63
+ def test_merged_fibers
64
+ result = RubyProf.profile(merge_fibers: true) { fiber_test }
65
+ assert_equal(1, result.threads.length)
66
+
67
+ profile = result.threads.first
68
+ assert_equal 0, profile.fiber_id
69
+
70
+ assert_in_delta(0.3, profile.total_time, 0.05)
71
+
72
+ assert(method_next = profile.methods.detect{|m| m.full_name == "Enumerator#next"})
73
+ assert(method_each = profile.methods.detect{|m| m.full_name == "Enumerator#each"})
74
+
75
+ assert_in_delta(0.2, method_next.total_time, 0.05)
76
+ assert_in_delta(0.2, method_each.total_time, 0.05)
77
+ end
78
+
79
+ end
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ # issue 137 is about correctly attributing time of recursive children
7
+
8
+ class RecursiveChildrenTest < TestCase
9
+ class SlowClass
10
+ def time_sink
11
+ 1234567890 ** 100 == 0
12
+ end
13
+ end
14
+
15
+ class SlowSearcher
16
+ def do_find(slow_objects)
17
+ slow_objects.find(&:time_sink)
18
+ end
19
+ end
20
+
21
+ class MainClass
22
+ def self.main_method
23
+ slow_objects = [SlowClass.new] * 100_000
24
+ slow_searcher = SlowSearcher.new
25
+ slow_searcher.do_find(slow_objects)
26
+ end
27
+ end
28
+
29
+ include PrinterTestHelper
30
+
31
+ def setup
32
+ # Need to use wall time for this test due to the sleep calls
33
+ RubyProf::measure_mode = RubyProf::WALL_TIME
34
+ end
35
+
36
+ def test_simple
37
+ result = RubyProf.profile do
38
+ # make array each recursive
39
+ [1].each do
40
+ MainClass.main_method
41
+ end
42
+ end
43
+
44
+ # methods = result.threads.first.methods.sort.reverse
45
+
46
+ printer = RubyProf::GraphPrinter.new(result)
47
+
48
+ buffer = ''
49
+ printer.print(StringIO.new(buffer))
50
+
51
+ puts buffer if ENV['SHOW_RUBY_PROF_PRINTER_OUTPUT'] == "1"
52
+
53
+ parsed_output = MetricsArray.parse(buffer)
54
+
55
+ assert( enum_find = parsed_output.metrics_for("Enumerable#find") )
56
+ assert( array_each = enum_find.child("Array#each") )
57
+
58
+ assert_operator enum_find.metrics.total, :>=, array_each.total
59
+ assert_operator enum_find.metrics.total, :>, 0
60
+ assert_in_delta enum_find.metrics.total, array_each.total, 0.02
61
+ end
62
+
63
+ end
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ class LineNumbers
7
+ def method1
8
+ end
9
+
10
+ def method2
11
+ method1
12
+ end
13
+
14
+ def method3
15
+ sleep(1)
16
+ end
17
+ end
18
+
19
+ # -- Tests ----
20
+ class LineNumbersTest < TestCase
21
+ def test_function_line_no
22
+ numbers = LineNumbers.new
23
+
24
+ result = RubyProf.profile do
25
+ numbers.method2
26
+ end
27
+
28
+ methods = result.threads.first.methods.sort.reverse
29
+ assert_equal(3, methods.length)
30
+
31
+ method = methods[0]
32
+ assert_equal('LineNumbersTest#test_function_line_no', method.full_name)
33
+ assert_equal(25, method.line)
34
+
35
+ method = methods[1]
36
+ assert_equal('LineNumbers#method2', method.full_name)
37
+ assert_equal(10, method.line)
38
+
39
+ method = methods[2]
40
+ assert_equal('LineNumbers#method1', method.full_name)
41
+ assert_equal(7, method.line)
42
+ end
43
+
44
+ def test_c_function
45
+ numbers = LineNumbers.new
46
+
47
+ result = RubyProf.profile do
48
+ numbers.method3
49
+ end
50
+
51
+ methods = result.threads.first.methods.sort_by {|method| method.full_name}
52
+ assert_equal(3, methods.length)
53
+
54
+ # Methods:
55
+ # LineNumbers#method3
56
+ # LineNumbersTest#test_c_function
57
+ # Kernel#sleep
58
+
59
+ method = methods[0]
60
+ assert_equal('Kernel#sleep', method.full_name)
61
+ assert_equal(0, method.line)
62
+
63
+ method = methods[1]
64
+ assert_equal('LineNumbers#method3', method.full_name)
65
+ assert_equal(14, method.line)
66
+
67
+ method = methods[2]
68
+ assert_equal('LineNumbersTest#test_c_function', method.full_name)
69
+ assert_equal(48, method.line)
70
+ end
71
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ class MeasureAllocationsTest < TestCase
7
+ def test_allocations_mode
8
+ RubyProf::measure_mode = RubyProf::ALLOCATIONS
9
+ assert_equal(RubyProf::ALLOCATIONS, RubyProf::measure_mode)
10
+ end
11
+
12
+ def test_allocations_enabled_defined
13
+ assert(defined?(RubyProf::ALLOCATIONS_ENABLED))
14
+ end
15
+
16
+ if RubyProf::ALLOCATIONS_ENABLED
17
+ def test_allocations
18
+ t = RubyProf.measure_allocations
19
+ refute_empty("a" + "b")
20
+ u = RubyProf.measure_allocations
21
+ assert_kind_of Integer, t
22
+ assert_kind_of Integer, u
23
+ assert_operator t, :<, u
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require File.expand_path('../test_helper', __FILE__)
5
+
6
+ class MeasureCpuTimeTest < TestCase
7
+ def setup
8
+ RubyProf::measure_mode = RubyProf::CPU_TIME
9
+ end
10
+
11
+ def teardown
12
+ RubyProf::measure_mode = RubyProf::WALL_TIME
13
+ end
14
+
15
+ def test_mode
16
+ assert_equal(RubyProf::CPU_TIME, RubyProf::measure_mode)
17
+ end
18
+
19
+ def test_cpu_time_enabled_defined
20
+ assert(defined?(RubyProf::CPU_TIME_ENABLED))
21
+ end
22
+
23
+ def test_class_methods
24
+ result = RubyProf.profile do
25
+ RubyProf::C7.busy_wait
26
+ end
27
+
28
+ # Length should be greater 2:
29
+ # MeasureCpuTimeTest#test_class_methods
30
+ # <Class::RubyProf::C1>#busy_wait
31
+ # ....
32
+
33
+ methods = result.threads.first.methods.sort.reverse[0..1]
34
+ assert_equal(2, methods.length)
35
+
36
+ # Check the names
37
+ assert_equal('MeasureCpuTimeTest#test_class_methods', methods[0].full_name)
38
+ assert_equal('<Class::RubyProf::C7>#busy_wait', methods[1].full_name)
39
+
40
+ # Check times
41
+ assert_in_delta(0.1, methods[0].total_time, 0.05)
42
+ assert_in_delta(0, methods[0].wait_time, 0.05)
43
+ assert_in_delta(0, methods[0].self_time, 0.05)
44
+
45
+ assert_in_delta(0.1, methods[1].total_time, 0.05)
46
+ assert_in_delta(0, methods[1].wait_time, 0.05)
47
+ assert_in_delta(0, methods[1].self_time, 0.05)
48
+ end
49
+
50
+ def test_instance_methods
51
+ result = RubyProf.profile do
52
+ RubyProf::C7.new.busy_wait
53
+ end
54
+
55
+ methods = result.threads.first.methods.sort.reverse[0..1]
56
+ assert_equal(2, methods.length)
57
+
58
+ # Methods at this point:
59
+ # MeasureCpuTimeTest#test_instance_methods
60
+ # C7#busy_wait
61
+ # ...
62
+
63
+ names = methods.map(&:full_name)
64
+ assert_equal('MeasureCpuTimeTest#test_instance_methods', names[0])
65
+ assert_equal('RubyProf::C7#busy_wait', names[1])
66
+
67
+
68
+ # Check times
69
+ assert_in_delta(0.2, methods[0].total_time, 0.03)
70
+ assert_in_delta(0, methods[0].wait_time, 0.03)
71
+ assert_in_delta(0, methods[0].self_time, 0.03)
72
+
73
+ assert_in_delta(0.2, methods[1].total_time, 0.03)
74
+ assert_in_delta(0, methods[1].wait_time, 0.03)
75
+ assert_in_delta(0, methods[1].self_time, 0.2)
76
+ end
77
+
78
+ def test_module_methods
79
+ result = RubyProf.profile do
80
+ RubyProf::C8.busy_wait
81
+ end
82
+
83
+ # Methods:
84
+ # MeasureCpuTimeTest#test_module_methods
85
+ # M1#busy_wait
86
+ # ...
87
+
88
+ methods = result.threads.first.methods.sort.reverse[0..1]
89
+ assert_equal(2, methods.length)
90
+
91
+ assert_equal('MeasureCpuTimeTest#test_module_methods', methods[0].full_name)
92
+ assert_equal('RubyProf::M7#busy_wait', methods[1].full_name)
93
+
94
+ # Check times
95
+ assert_in_delta(0.3, methods[0].total_time, 0.1)
96
+ assert_in_delta(0, methods[0].wait_time, 0.02)
97
+ assert_in_delta(0, methods[0].self_time, 0.02)
98
+
99
+ assert_in_delta(0.3, methods[1].total_time, 0.1)
100
+ assert_in_delta(0, methods[1].wait_time, 0.02)
101
+ assert_in_delta(0, methods[1].self_time, 0.1)
102
+ end
103
+
104
+ def test_module_instance_methods
105
+ result = RubyProf.profile do
106
+ RubyProf::C8.new.busy_wait
107
+ end
108
+
109
+ # Methods:
110
+ # MeasureCpuTimeTest#test_module_instance_methods
111
+ # M7#busy_wait
112
+ # ...
113
+
114
+ methods = result.threads.first.methods.sort.reverse[0..1]
115
+ assert_equal(2, methods.length)
116
+ names = methods.map(&:full_name)
117
+ assert_equal('MeasureCpuTimeTest#test_module_instance_methods', names[0])
118
+ assert_equal('RubyProf::M7#busy_wait', names[1])
119
+
120
+ # Check times
121
+ assert_in_delta(0.3, methods[0].total_time, 0.1)
122
+ assert_in_delta(0, methods[0].wait_time, 0.1)
123
+ assert_in_delta(0, methods[0].self_time, 0.1)
124
+
125
+ assert_in_delta(0.3, methods[1].total_time, 0.1)
126
+ assert_in_delta(0, methods[1].wait_time, 0.01)
127
+ assert_in_delta(0, methods[1].self_time, 0.1)
128
+ end
129
+
130
+ def test_singleton
131
+ c3 = RubyProf::C3.new
132
+
133
+ class << c3
134
+ def busy_wait
135
+ end
136
+ end
137
+
138
+ result = RubyProf.profile do
139
+ c3.busy_wait
140
+ end
141
+
142
+ methods = result.threads.first.methods.sort.reverse
143
+ assert_equal(2, methods.length)
144
+
145
+ assert_equal('MeasureCpuTimeTest#test_singleton', methods[0].full_name)
146
+ assert_equal('<Object::RubyProf::C3>#busy_wait', methods[1].full_name)
147
+
148
+ assert_in_delta(0, methods[0].total_time, 0.01)
149
+ assert_in_delta(0, methods[0].wait_time, 0.01)
150
+ assert_in_delta(0, methods[0].self_time, 0.01)
151
+
152
+ assert_in_delta(0, methods[1].total_time, 0.01)
153
+ assert_in_delta(0, methods[1].wait_time, 0.01)
154
+ assert_in_delta(0, methods[1].self_time, 0.01)
155
+ end
156
+
157
+
158
+ def test_sleeping_does_accumulate_wall_time
159
+ RubyProf::measure_mode = RubyProf::WALL_TIME
160
+ result = RubyProf.profile do
161
+ sleep 0.1
162
+ end
163
+ methods = result.threads.first.methods.sort.reverse
164
+ assert_equal(["MeasureCpuTimeTest#test_sleeping_does_accumulate_wall_time", "Kernel#sleep"], methods.map(&:full_name))
165
+ assert_in_delta(0.1, methods[1].total_time, 0.01)
166
+ assert_equal(0, methods[1].wait_time)
167
+ assert_in_delta(0.1, methods[1].self_time, 0.01)
168
+ end
169
+
170
+ def test_sleeping_does_not_accumulate_significant_cpu_time
171
+ result = RubyProf.profile do
172
+ sleep 0.1
173
+ end
174
+ methods = result.threads.first.methods.sort.reverse
175
+ assert_equal(["MeasureCpuTimeTest#test_sleeping_does_not_accumulate_significant_cpu_time", "Kernel#sleep"], methods.map(&:full_name))
176
+ assert_in_delta(0, methods[1].total_time, 0.01)
177
+ assert_equal(0, methods[1].wait_time)
178
+ assert_in_delta(0, methods[1].self_time, 0.01)
179
+ end
180
+
181
+ def test_waiting_for_threads_does_not_accumulate_cpu_time
182
+ background_thread = nil
183
+ result = RubyProf.profile do
184
+ background_thread = Thread.new{ sleep 0.1 }
185
+ background_thread.join
186
+ end
187
+ # check number of threads
188
+ assert_equal(2, result.threads.length)
189
+ fg, bg = result.threads
190
+ assert(fg.methods.map(&:full_name).include?("Thread#join"))
191
+ assert(bg.methods.map(&:full_name).include?("Kernel#sleep"))
192
+ assert_in_delta(0, fg.total_time, 0.01)
193
+ assert_in_delta(0, bg.total_time, 0.01)
194
+ end
195
+
196
+ def test_waiting_for_threads_does_accumulate_wall_time
197
+ RubyProf::measure_mode = RubyProf::WALL_TIME
198
+ background_thread = nil
199
+ result = RubyProf.profile do
200
+ background_thread = Thread.new{ sleep 0.1 }
201
+ background_thread.join
202
+ end
203
+ # check number of threads
204
+ assert_equal(2, result.threads.length)
205
+ fg, bg = result.threads
206
+ assert(fg.methods.map(&:full_name).include?("Thread#join"))
207
+ assert(bg.methods.map(&:full_name).include?("Kernel#sleep"))
208
+ assert_in_delta(0.1, fg.total_time, 0.01)
209
+ assert_in_delta(0.1, fg.wait_time, 0.01)
210
+ assert_in_delta(0.1, bg.total_time, 0.01)
211
+ end
212
+
213
+ end