ruby-prof 1.1.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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +532 -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 +279 -0
  10. data/ext/ruby_prof/rp_allocation.h +31 -0
  11. data/ext/ruby_prof/rp_call_info.c +271 -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 +67 -0
  16. data/ext/ruby_prof/rp_measure_wall_time.c +62 -0
  17. data/ext/ruby_prof/rp_measurement.c +230 -0
  18. data/ext/ruby_prof/rp_measurement.h +50 -0
  19. data/ext/ruby_prof/rp_method.c +630 -0
  20. data/ext/ruby_prof/rp_method.h +70 -0
  21. data/ext/ruby_prof/rp_profile.c +895 -0
  22. data/ext/ruby_prof/rp_profile.h +37 -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 +337 -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 +52 -0
  32. data/lib/ruby-prof/assets/call_stack_printer.html.erb +713 -0
  33. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  34. data/lib/ruby-prof/assets/graph_printer.html.erb +356 -0
  35. data/lib/ruby-prof/call_info.rb +57 -0
  36. data/lib/ruby-prof/call_info_visitor.rb +38 -0
  37. data/lib/ruby-prof/compatibility.rb +109 -0
  38. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  39. data/lib/ruby-prof/measurement.rb +14 -0
  40. data/lib/ruby-prof/method_info.rb +90 -0
  41. data/lib/ruby-prof/printers/abstract_printer.rb +127 -0
  42. data/lib/ruby-prof/printers/call_info_printer.rb +51 -0
  43. data/lib/ruby-prof/printers/call_stack_printer.rb +182 -0
  44. data/lib/ruby-prof/printers/call_tree_printer.rb +151 -0
  45. data/lib/ruby-prof/printers/dot_printer.rb +132 -0
  46. data/lib/ruby-prof/printers/flat_printer.rb +52 -0
  47. data/lib/ruby-prof/printers/graph_html_printer.rb +63 -0
  48. data/lib/ruby-prof/printers/graph_printer.rb +114 -0
  49. data/lib/ruby-prof/printers/multi_printer.rb +127 -0
  50. data/lib/ruby-prof/profile.rb +33 -0
  51. data/lib/ruby-prof/rack.rb +171 -0
  52. data/lib/ruby-prof/task.rb +147 -0
  53. data/lib/ruby-prof/thread.rb +35 -0
  54. data/lib/ruby-prof/version.rb +3 -0
  55. data/lib/unprof.rb +10 -0
  56. data/ruby-prof.gemspec +58 -0
  57. data/test/abstract_printer_test.rb +26 -0
  58. data/test/alias_test.rb +129 -0
  59. data/test/basic_test.rb +129 -0
  60. data/test/call_info_visitor_test.rb +31 -0
  61. data/test/duplicate_names_test.rb +32 -0
  62. data/test/dynamic_method_test.rb +53 -0
  63. data/test/enumerable_test.rb +21 -0
  64. data/test/exceptions_test.rb +24 -0
  65. data/test/exclude_methods_test.rb +146 -0
  66. data/test/exclude_threads_test.rb +53 -0
  67. data/test/fiber_test.rb +73 -0
  68. data/test/gc_test.rb +96 -0
  69. data/test/line_number_test.rb +161 -0
  70. data/test/marshal_test.rb +119 -0
  71. data/test/measure_allocations.rb +30 -0
  72. data/test/measure_allocations_test.rb +385 -0
  73. data/test/measure_allocations_trace_test.rb +385 -0
  74. data/test/measure_memory_trace_test.rb +756 -0
  75. data/test/measure_process_time_test.rb +849 -0
  76. data/test/measure_times.rb +54 -0
  77. data/test/measure_wall_time_test.rb +459 -0
  78. data/test/multi_printer_test.rb +71 -0
  79. data/test/no_method_class_test.rb +15 -0
  80. data/test/parser_timings.rb +24 -0
  81. data/test/pause_resume_test.rb +166 -0
  82. data/test/prime.rb +56 -0
  83. data/test/printer_call_stack_test.rb +28 -0
  84. data/test/printer_call_tree_test.rb +31 -0
  85. data/test/printer_flat_test.rb +68 -0
  86. data/test/printer_graph_html_test.rb +60 -0
  87. data/test/printer_graph_test.rb +41 -0
  88. data/test/printers_test.rb +141 -0
  89. data/test/printing_recursive_graph_test.rb +81 -0
  90. data/test/rack_test.rb +157 -0
  91. data/test/recursive_test.rb +210 -0
  92. data/test/singleton_test.rb +38 -0
  93. data/test/stack_printer_test.rb +64 -0
  94. data/test/start_stop_test.rb +109 -0
  95. data/test/test_helper.rb +24 -0
  96. data/test/thread_test.rb +144 -0
  97. data/test/unique_call_path_test.rb +190 -0
  98. data/test/yarv_test.rb +56 -0
  99. metadata +191 -0
@@ -0,0 +1,210 @@
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
+ return if n == 0
11
+ simple(n-1)
12
+ end
13
+
14
+ # More complicated recursive test
15
+ def render_partial(i)
16
+ sleep(1)
17
+ case i
18
+ when 0
19
+ render_partial(10)
20
+ when 1
21
+ 2.times do |j|
22
+ render_partial(j + 10)
23
+ end
24
+ end
25
+ end
26
+
27
+ def render
28
+ 2.times do |i|
29
+ render_partial(i)
30
+ end
31
+ end
32
+ end
33
+
34
+ # -- Tests ----
35
+ class RecursiveTest < TestCase
36
+ def setup
37
+ # Need to use wall time for this test due to the sleep calls
38
+ RubyProf::measure_mode = RubyProf::WALL_TIME
39
+ end
40
+
41
+ include SimpleRecursion
42
+
43
+ def test_simple
44
+ result = RubyProf.profile do
45
+ simple(1)
46
+ end
47
+
48
+ methods = result.threads.first.methods.sort.reverse
49
+ assert_equal(3, methods.length)
50
+
51
+ # Method 0: RecursiveTest#test_simple
52
+ method = methods[0]
53
+ assert_equal('RecursiveTest#test_simple', method.full_name)
54
+ assert_equal(1, method.called)
55
+ refute(method.recursive?)
56
+ assert_in_delta(2, method.total_time, 0.1)
57
+ assert_in_delta(0, method.self_time, 0.01)
58
+ assert_in_delta(0, method.wait_time, 0.01)
59
+ assert_in_delta(2, method.children_time, 0.1)
60
+
61
+ assert_equal(1, method.callers.length)
62
+ call_info = method.callers[0]
63
+ assert_nil(call_info.parent)
64
+
65
+ assert_equal(1, method.callees.length)
66
+ call_info = method.callees[0]
67
+ assert_equal('SimpleRecursion#simple', call_info.target.full_name)
68
+
69
+ # Method 1: SimpleRecursion#simple
70
+ method = methods[1]
71
+ assert_equal('SimpleRecursion#simple', method.full_name)
72
+ assert_equal(2, method.called)
73
+ assert(method.recursive?)
74
+ assert_in_delta(2, method.total_time, 0.1)
75
+ assert_in_delta(0, method.self_time, 0.1)
76
+ assert_in_delta(0, method.wait_time, 0.1)
77
+ assert_in_delta(2, method.children_time, 0.1)
78
+
79
+ assert_equal(2, method.callers.length)
80
+ call_info = method.callers[0]
81
+ assert_equal('RecursiveTest#test_simple', call_info.parent.full_name)
82
+
83
+ call_info = method.callers[1]
84
+ assert_equal('SimpleRecursion#simple', call_info.parent.full_name)
85
+
86
+ assert_equal(2, method.callees.length)
87
+ call_info = method.callees[0]
88
+ assert_equal('Kernel#sleep', call_info.target.full_name)
89
+
90
+ call_info = method.callees[1]
91
+ assert_equal('SimpleRecursion#simple', call_info.target.full_name)
92
+
93
+ # Method 2: Kernel#sleep
94
+ method = methods[2]
95
+ assert_equal('Kernel#sleep', method.full_name)
96
+ assert_equal(2, method.called)
97
+ refute(method.recursive?)
98
+ assert_in_delta(2, method.total_time, 0.1)
99
+ assert_in_delta(2, method.self_time, 0.1)
100
+ assert_in_delta(0, method.wait_time, 0.1)
101
+ assert_in_delta(0, method.children_time, 0.1)
102
+
103
+ assert_equal(1, method.callers.length)
104
+ call_info = method.callers[0]
105
+ assert_equal('SimpleRecursion#simple', call_info.parent.full_name)
106
+ assert_equal(0, method.callees.length)
107
+
108
+ assert_equal(0, method.callees.length)
109
+ end
110
+
111
+ def test_cycle
112
+ result = RubyProf.profile do
113
+ render
114
+ end
115
+
116
+ methods = result.threads.first.methods.sort.reverse
117
+ assert_equal(5, methods.length)
118
+
119
+ method = methods[0]
120
+ assert_equal('RecursiveTest#test_cycle', method.full_name)
121
+ assert_equal(1, method.called)
122
+ refute(method.recursive?)
123
+ assert_in_delta(5, method.total_time, 0.1)
124
+ assert_in_delta(0, method.self_time, 0.01)
125
+ assert_in_delta(0, method.wait_time, 0.01)
126
+ assert_in_delta(5, method.children_time, 0.1)
127
+
128
+ assert_equal(1, method.callers.length)
129
+ call_info = method.callers[0]
130
+ assert_nil(call_info.parent)
131
+
132
+ assert_equal(1, method.callees.length)
133
+ call_info = method.callees[0]
134
+ assert_equal('SimpleRecursion#render', call_info.target.full_name)
135
+
136
+ method = methods[1]
137
+ assert_equal('SimpleRecursion#render', method.full_name)
138
+ assert_equal(1, method.called)
139
+ refute(method.recursive?)
140
+ assert_in_delta(5, method.total_time, 0.1)
141
+ assert_in_delta(0, method.self_time, 0.01)
142
+ assert_in_delta(0, method.wait_time, 0.01)
143
+ assert_in_delta(5, method.children_time, 0.1)
144
+
145
+ assert_equal(1, method.callers.length)
146
+ call_info = method.callers[0]
147
+ assert_equal('RecursiveTest#test_cycle', call_info.parent.full_name)
148
+
149
+ assert_equal(1, method.callees.length)
150
+ call_info = method.callees[0]
151
+ assert_equal('Integer#times', call_info.target.full_name)
152
+
153
+ method = methods[2]
154
+ assert_equal('Integer#times', method.full_name)
155
+ assert_equal(2, method.called)
156
+ assert(method.recursive?)
157
+ assert_in_delta(5, method.total_time, 0.1)
158
+ assert_in_delta(0, method.self_time, 0.1)
159
+ assert_in_delta(0, method.wait_time, 0.1)
160
+ assert_in_delta(5, method.children_time, 0.1)
161
+
162
+ assert_equal(2, method.callers.length)
163
+ call_info = method.callers[0]
164
+ assert_equal('SimpleRecursion#render', call_info.parent.full_name)
165
+
166
+ call_info = method.callers[1]
167
+ assert_equal('SimpleRecursion#render_partial', call_info.parent.full_name)
168
+
169
+ assert_equal(1, method.callees.length)
170
+ call_info = method.callees[0]
171
+ assert_equal('SimpleRecursion#render_partial', call_info.target.full_name)
172
+
173
+ method = methods[3]
174
+ assert_equal('SimpleRecursion#render_partial', method.full_name)
175
+ assert_equal(5, method.called)
176
+ assert(method.recursive?)
177
+ assert_in_delta(5, method.total_time, 0.1)
178
+ assert_in_delta(0, method.self_time, 0.1)
179
+ assert_in_delta(0, method.wait_time, 0.01)
180
+ assert_in_delta(5, method.children_time, 0.05)
181
+
182
+ assert_equal(2, method.callers.length)
183
+ call_info = method.callers[0]
184
+ assert_equal('Integer#times', call_info.parent.full_name)
185
+
186
+ call_info = method.callers[1]
187
+ assert_equal('SimpleRecursion#render_partial', call_info.parent.full_name)
188
+
189
+ assert_equal(3, method.callees.length)
190
+ call_info = method.callees[0]
191
+ assert_equal('Kernel#sleep', call_info.target.full_name)
192
+
193
+ call_info = method.callees[1]
194
+ assert_equal('SimpleRecursion#render_partial', call_info.target.full_name)
195
+
196
+ call_info = method.callees[2]
197
+ assert_equal('Integer#times', call_info.target.full_name)
198
+
199
+ method = methods[4]
200
+ assert_equal('Kernel#sleep', method.full_name)
201
+ assert_equal(5, method.called)
202
+ refute(method.recursive?)
203
+ assert_in_delta(5, method.total_time, 0.1)
204
+ assert_in_delta(5, method.self_time, 0.1)
205
+ assert_in_delta(0, method.wait_time, 0.01)
206
+ assert_in_delta(0, method.children_time, 0.01)
207
+
208
+ assert_equal(0, method.callees.length)
209
+ end
210
+ 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
@@ -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