acunote-ruby-prof 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/CHANGES +240 -0
  2. data/LICENSE +23 -0
  3. data/README.rdoc +439 -0
  4. data/Rakefile +148 -0
  5. data/bin/ruby-prof +236 -0
  6. data/examples/empty.png +0 -0
  7. data/examples/flat.txt +55 -0
  8. data/examples/graph.dot +106 -0
  9. data/examples/graph.html +823 -0
  10. data/examples/graph.png +0 -0
  11. data/examples/graph.txt +170 -0
  12. data/examples/minus.png +0 -0
  13. data/examples/multi.flat.txt +23 -0
  14. data/examples/multi.graph.html +906 -0
  15. data/examples/multi.grind.dat +194 -0
  16. data/examples/multi.stack.html +573 -0
  17. data/examples/plus.png +0 -0
  18. data/examples/stack.html +573 -0
  19. data/ext/ruby_prof/extconf.rb +43 -0
  20. data/ext/ruby_prof/measure_allocations.h +58 -0
  21. data/ext/ruby_prof/measure_cpu_time.h +152 -0
  22. data/ext/ruby_prof/measure_gc_runs.h +76 -0
  23. data/ext/ruby_prof/measure_gc_time.h +57 -0
  24. data/ext/ruby_prof/measure_memory.h +101 -0
  25. data/ext/ruby_prof/measure_process_time.h +52 -0
  26. data/ext/ruby_prof/measure_wall_time.h +53 -0
  27. data/ext/ruby_prof/mingw/Rakefile +23 -0
  28. data/ext/ruby_prof/mingw/build.rake +38 -0
  29. data/ext/ruby_prof/ruby_prof.c +1834 -0
  30. data/ext/ruby_prof/ruby_prof.h +190 -0
  31. data/ext/ruby_prof/version.h +4 -0
  32. data/lib/ruby-prof.rb +62 -0
  33. data/lib/ruby-prof/abstract_printer.rb +41 -0
  34. data/lib/ruby-prof/aggregate_call_info.rb +68 -0
  35. data/lib/ruby-prof/call_info.rb +112 -0
  36. data/lib/ruby-prof/call_stack_printer.rb +751 -0
  37. data/lib/ruby-prof/call_tree_printer.rb +133 -0
  38. data/lib/ruby-prof/dot_printer.rb +153 -0
  39. data/lib/ruby-prof/empty.png +0 -0
  40. data/lib/ruby-prof/flat_printer.rb +78 -0
  41. data/lib/ruby-prof/flat_printer_with_line_numbers.rb +72 -0
  42. data/lib/ruby-prof/graph_html_printer.rb +278 -0
  43. data/lib/ruby-prof/graph_printer.rb +245 -0
  44. data/lib/ruby-prof/method_info.rb +131 -0
  45. data/lib/ruby-prof/minus.png +0 -0
  46. data/lib/ruby-prof/multi_printer.rb +54 -0
  47. data/lib/ruby-prof/plus.png +0 -0
  48. data/lib/ruby-prof/rack.rb +30 -0
  49. data/lib/ruby-prof/result.rb +70 -0
  50. data/lib/ruby-prof/symbol_to_proc.rb +8 -0
  51. data/lib/ruby-prof/task.rb +146 -0
  52. data/lib/ruby-prof/test.rb +148 -0
  53. data/lib/unprof.rb +8 -0
  54. data/rails/environment/profile.rb +24 -0
  55. data/rails/example/example_test.rb +9 -0
  56. data/rails/profile_test_helper.rb +21 -0
  57. data/test/aggregate_test.rb +136 -0
  58. data/test/basic_test.rb +290 -0
  59. data/test/current_failures_windows +8 -0
  60. data/test/do_nothing.rb +0 -0
  61. data/test/duplicate_names_test.rb +32 -0
  62. data/test/enumerable_test.rb +16 -0
  63. data/test/exceptions_test.rb +15 -0
  64. data/test/exclude_threads_test.rb +54 -0
  65. data/test/exec_test.rb +14 -0
  66. data/test/line_number_test.rb +73 -0
  67. data/test/measurement_test.rb +122 -0
  68. data/test/method_elimination_test.rb +74 -0
  69. data/test/module_test.rb +44 -0
  70. data/test/multi_printer_test.rb +81 -0
  71. data/test/no_method_class_test.rb +13 -0
  72. data/test/prime.rb +55 -0
  73. data/test/prime_test.rb +13 -0
  74. data/test/printers_test.rb +164 -0
  75. data/test/recursive_test.rb +236 -0
  76. data/test/ruby-prof-bin +20 -0
  77. data/test/singleton_test.rb +38 -0
  78. data/test/stack_printer_test.rb +74 -0
  79. data/test/stack_test.rb +138 -0
  80. data/test/start_stop_test.rb +112 -0
  81. data/test/test_suite.rb +32 -0
  82. data/test/thread_test.rb +173 -0
  83. data/test/unique_call_path_test.rb +225 -0
  84. metadata +185 -0
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'ruby-prof'
5
+
6
+ class StartStopTest < Test::Unit::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_raise(RuntimeError) do
29
+ RubyProf.start
30
+ end
31
+
32
+ assert_raise(RuntimeError) do
33
+ RubyProf.profile {}
34
+ end
35
+
36
+ RubyProf.stop # ok
37
+ assert_raise(RuntimeError) do
38
+ RubyProf.stop
39
+ end
40
+ end
41
+
42
+
43
+ def test_different_methods
44
+ method1
45
+
46
+ # Ruby prof should be stopped
47
+ assert_equal(false, RubyProf.running?)
48
+
49
+
50
+ # Length should be 4:
51
+ # StartStopTest#method1
52
+ # StartStopTest#method2
53
+ # StartStopTest#method3
54
+ # Kernel#sleep
55
+
56
+ methods = @result.threads.values.first.sort.reverse
57
+ assert_equal(4, methods.length)
58
+
59
+ # Check StackTest#test_call_sequence
60
+ method = methods[0]
61
+ assert_equal('StartStopTest#method1', method.full_name)
62
+ assert_equal(1, method.called)
63
+ assert_in_delta(2, method.total_time, 0.05)
64
+ assert_in_delta(0, method.wait_time, 0.01)
65
+ assert_in_delta(0, method.self_time, 0.01)
66
+ assert_in_delta(2, method.children_time, 0.05)
67
+ assert_equal(1, method.call_infos.length)
68
+
69
+ call_info = method.call_infos[0]
70
+ assert_equal('StartStopTest#method1', call_info.call_sequence)
71
+ assert_equal(1, call_info.children.length)
72
+
73
+ method = methods[1]
74
+ assert_equal('StartStopTest#method2', method.full_name)
75
+ assert_equal(1, method.called)
76
+ assert_in_delta(2, method.total_time, 0.05)
77
+ assert_in_delta(0, method.wait_time, 0.01)
78
+ assert_in_delta(0, method.self_time, 0.01)
79
+ assert_in_delta(2, method.children_time, 0.05)
80
+ assert_equal(1, method.call_infos.length)
81
+
82
+ call_info = method.call_infos[0]
83
+ assert_equal('StartStopTest#method1->StartStopTest#method2', call_info.call_sequence)
84
+ assert_equal(1, call_info.children.length)
85
+
86
+ method = methods[2]
87
+ assert_equal('StartStopTest#method3', method.full_name)
88
+ assert_equal(1, method.called)
89
+ assert_in_delta(2, method.total_time, 0.01)
90
+ assert_in_delta(0, method.wait_time, 0.01)
91
+ assert_in_delta(0, method.self_time, 0.01)
92
+ assert_in_delta(2, method.children_time, 0.01)
93
+ assert_equal(1, method.call_infos.length)
94
+
95
+ call_info = method.call_infos[0]
96
+ assert_equal('StartStopTest#method1->StartStopTest#method2->StartStopTest#method3', call_info.call_sequence)
97
+ assert_equal(1, call_info.children.length)
98
+
99
+ method = methods[3]
100
+ assert_equal('Kernel#sleep', method.full_name)
101
+ assert_equal(1, method.called)
102
+ assert_in_delta(2, method.total_time, 0.01)
103
+ assert_in_delta(0, method.wait_time, 0.01)
104
+ assert_in_delta(2, method.self_time, 0.01)
105
+ assert_in_delta(0, method.children_time, 0.01)
106
+ assert_equal(1, method.call_infos.length)
107
+
108
+ call_info = method.call_infos[0]
109
+ assert_equal('StartStopTest#method1->StartStopTest#method2->StartStopTest#method3->Kernel#sleep', call_info.call_sequence)
110
+ assert_equal(0, call_info.children.length)
111
+ end
112
+ end
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'rubygems'
3
+ require 'redgreen'
4
+ rescue LoadError
5
+ end
6
+
7
+ require 'test/unit'
8
+
9
+ require 'aggregate_test'
10
+ require 'basic_test'
11
+ require 'duplicate_names_test'
12
+ require 'exceptions_test'
13
+ require 'line_number_test'
14
+ require 'measurement_test'
15
+ require 'module_test'
16
+ require 'no_method_class_test'
17
+ require 'prime_test'
18
+ require 'printers_test'
19
+ require 'recursive_test'
20
+ require 'singleton_test'
21
+ require 'stack_test'
22
+ require 'start_stop_test'
23
+ require 'thread_test'
24
+ require 'unique_call_path_test'
25
+ require 'stack_printer_test'
26
+ require 'multi_printer_test'
27
+ require 'method_elimination_test'
28
+
29
+ # Can't use this one here cause it breaks
30
+ # the rest of the unit tets (Ruby Prof gets
31
+ # started twice).
32
+ #require 'profile_unit_test'
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'ruby-prof'
4
+ require 'timeout'
5
+
6
+ # -- Tests ----
7
+ class ThreadTest < Test::Unit::TestCase
8
+ def setup
9
+ # Need to use wall time for this test due to the sleep calls
10
+ RubyProf::measure_mode = RubyProf::WALL_TIME
11
+ end
12
+
13
+ def test_thread_count
14
+ RubyProf.start
15
+
16
+ thread = Thread.new do
17
+ sleep(1)
18
+ end
19
+
20
+ thread.join
21
+ result = RubyProf.stop
22
+ assert_equal(2, result.threads.keys.length) # this should pass...
23
+ end
24
+
25
+ def test_thread_identity
26
+ RubyProf.start
27
+ thread = Thread.new do
28
+ sleep(1)
29
+ end
30
+ thread.join
31
+ result = RubyProf.stop
32
+
33
+ thread_ids = result.threads.keys.sort
34
+ threads = [Thread.current, thread]
35
+ assert_equal(2, thread_ids.length) # should pass
36
+
37
+ assert(thread_ids.include?(threads[0].object_id))
38
+ assert(thread_ids.include?(threads[1].object_id))
39
+
40
+ assert_instance_of(Thread, ObjectSpace._id2ref(thread_ids[0]))
41
+ assert(threads.include?(ObjectSpace._id2ref(thread_ids[0])))
42
+
43
+ assert_instance_of(Thread, ObjectSpace._id2ref(thread_ids[1]))
44
+ assert(threads.include?(ObjectSpace._id2ref(thread_ids[1])))
45
+ end
46
+
47
+ def test_thread_timings
48
+ RubyProf.start
49
+ thread = Thread.new do
50
+ sleep 0 # force it to hit thread.join, below, first
51
+ # thus forcing sleep(1), below, to be counted as (wall) self_time
52
+ # since we currently count time "in some other thread" as self.wait_time
53
+ # for whatever reason
54
+ sleep(1)
55
+ end
56
+ thread.join
57
+ result = RubyProf.stop
58
+
59
+ # Check background thread
60
+ assert_equal(2, result.threads.length)
61
+ methods = result.threads[thread.object_id].sort.reverse
62
+ assert_equal(2, methods.length)
63
+
64
+ method = methods[0]
65
+ assert_equal('ThreadTest#test_thread_timings', method.full_name)
66
+ assert_equal(1, method.called)
67
+ assert_in_delta(1, method.total_time, 0.05)
68
+ assert_in_delta(0, method.self_time, 0.01)
69
+ assert_in_delta(0, method.wait_time, 0.01)
70
+ assert_in_delta(1, method.children_time, 0.01)
71
+ assert_equal(1, method.call_infos.length)
72
+ call_info = method.call_infos[0]
73
+ assert_equal('ThreadTest#test_thread_timings', call_info.call_sequence)
74
+ assert_equal(1, call_info.children.length)
75
+
76
+ method = methods[1]
77
+ assert_equal('Kernel#sleep', method.full_name)
78
+ assert_equal(2, method.called)
79
+ assert_in_delta(1, method.total_time, 0.01)
80
+ assert_in_delta(1.0, method.self_time, 0.01)
81
+ assert_in_delta(0, method.wait_time, 0.01)
82
+ assert_in_delta(0, method.children_time, 0.01)
83
+
84
+ assert_equal(1, method.call_infos.length)
85
+ call_info = method.call_infos[0]
86
+ assert_equal('ThreadTest#test_thread_timings->Kernel#sleep', call_info.call_sequence)
87
+ assert_equal(0, call_info.children.length)
88
+
89
+ # Check foreground thread
90
+ methods = result.threads[Thread.current.object_id].sort.reverse
91
+ assert_equal(4, methods.length)
92
+ methods = methods.sort.reverse
93
+
94
+ method = methods[0]
95
+ assert_equal('ThreadTest#test_thread_timings', method.full_name)
96
+ # the sub calls to Object#new, when popped,
97
+ # cause the parent frame to be created for method #test_thread_timings, which means a +1 when it's popped in the end
98
+ # xxxx a test that shows it the other way, too (never creates parent frame--if that's even possible)
99
+ assert_equal(1, method.called)
100
+ assert_in_delta(1, method.total_time, 0.01)
101
+ assert_in_delta(0, method.self_time, 0.05)
102
+ assert_in_delta(0, method.wait_time, 0.05)
103
+ assert_in_delta(1, method.children_time, 0.01)
104
+
105
+ assert_equal(1, method.call_infos.length)
106
+ call_info = method.call_infos[0]
107
+ assert_equal('ThreadTest#test_thread_timings', call_info.call_sequence)
108
+ assert_equal(2, call_info.children.length)
109
+
110
+ method = methods[1]
111
+ assert_equal('Thread#join', method.full_name)
112
+ assert_equal(1, method.called)
113
+ assert_in_delta(1, method.total_time, 0.01)
114
+ assert_in_delta(0, method.self_time, 0.01)
115
+ assert_in_delta(1.0, method.wait_time, 0.01)
116
+ assert_in_delta(0, method.children_time, 0.01)
117
+
118
+ assert_equal(1, method.call_infos.length)
119
+ call_info = method.call_infos[0]
120
+ assert_equal('ThreadTest#test_thread_timings->Thread#join', call_info.call_sequence)
121
+ assert_equal(0, call_info.children.length)
122
+
123
+ method = methods[2]
124
+ assert_equal('<Class::Thread>#new', method.full_name)
125
+ assert_equal(1, method.called)
126
+ assert_in_delta(0, method.total_time, 0.01)
127
+ assert_in_delta(0, method.self_time, 0.01)
128
+ assert_in_delta(0, method.wait_time, 0.01)
129
+ assert_in_delta(0, method.children_time, 0.01)
130
+
131
+ assert_equal(1, method.call_infos.length)
132
+ call_info = method.call_infos[0]
133
+ assert_equal('ThreadTest#test_thread_timings-><Class::Thread>#new', call_info.call_sequence)
134
+ assert_equal(1, call_info.children.length)
135
+
136
+ method = methods[3]
137
+ assert_equal('Thread#initialize', method.full_name)
138
+ assert_equal(1, method.called)
139
+ assert_in_delta(0, method.total_time, 0.01)
140
+ assert_in_delta(0, method.self_time, 0.01)
141
+ assert_in_delta(0, method.wait_time, 0.01)
142
+ assert_in_delta(0, method.children_time, 0.01)
143
+
144
+ assert_equal(1, method.call_infos.length)
145
+ call_info = method.call_infos[0]
146
+ assert_equal('ThreadTest#test_thread_timings-><Class::Thread>#new->Thread#initialize', call_info.call_sequence)
147
+ assert_equal(0, call_info.children.length)
148
+ end
149
+
150
+ # useless test
151
+ def test_thread_back_and_forth
152
+ result = RubyProf.profile do
153
+ a = Thread.new { 100_000.times { sleep 0 }}
154
+ b = Thread.new { 100_000.times { sleep 0 }}
155
+ a.join
156
+ b.join
157
+ end
158
+ assert result.threads.values.flatten.sort[-1].total_time < 10 # 10s
159
+ end
160
+
161
+ def test_thread
162
+ result = RubyProf.profile do
163
+ begin
164
+ status = Timeout::timeout(2) do
165
+ while true
166
+ next
167
+ end
168
+ end
169
+ rescue Timeout::Error
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'ruby-prof'
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
+ c = 3
21
+ end
22
+
23
+ def method_k(i)
24
+ method_a(i)
25
+ end
26
+ end
27
+
28
+
29
+ # -- Tests ----
30
+ class UniqueCallPathTest < Test::Unit::TestCase
31
+ def test_root_method
32
+ unique_call_path = UniqueCallPath.new
33
+
34
+ result = RubyProf.profile do
35
+ unique_call_path.method_a(1)
36
+ end
37
+
38
+ root_methods = Array.new
39
+ result.threads.each do | thread_id, methods |
40
+ methods.each do | m |
41
+ if m.root?
42
+ root_methods.push(m)
43
+ end
44
+ end
45
+ end
46
+
47
+ assert_equal(1, root_methods.length)
48
+ assert_equal("UniqueCallPathTest#test_root_method", root_methods[0].full_name)
49
+ end
50
+
51
+ def test_root_children
52
+ unique_call_path = UniqueCallPath.new
53
+
54
+ result = RubyProf.profile do
55
+ unique_call_path.method_a(1)
56
+ unique_call_path.method_k(2)
57
+ end
58
+
59
+ root_methods = Array.new
60
+ result.threads.each do | thread_id, methods |
61
+ methods.each do | m |
62
+ if m.root?
63
+ root_methods.push(m)
64
+ end
65
+ end
66
+ end
67
+
68
+ assert_equal(1, root_methods.length)
69
+
70
+ root_children = Array.new
71
+ root_methods[0].children.each do | c |
72
+ if c.parent.target.eql?(root_methods[0])
73
+ root_children.push(c)
74
+ end
75
+ end
76
+
77
+ children = root_children.sort do |c1, c2|
78
+ c1.target.full_name <=> c2.target.full_name
79
+ end
80
+
81
+ assert_equal(2, children.length)
82
+ assert_equal("UniqueCallPath#method_a", children[0].target.full_name)
83
+ assert_equal("UniqueCallPath#method_k", children[1].target.full_name)
84
+ end
85
+
86
+ def test_children_of
87
+ unique_call_path = UniqueCallPath.new
88
+
89
+ result = RubyProf.profile do
90
+ unique_call_path.method_a(1)
91
+ unique_call_path.method_k(2)
92
+ end
93
+
94
+ root_methods = Array.new
95
+ result.threads.each do | thread_id, methods |
96
+ methods.each do | m |
97
+ if m.root?
98
+ root_methods.push(m)
99
+ end
100
+ end
101
+ end
102
+
103
+ assert_equal(1, root_methods.length)
104
+ method = root_methods[0]
105
+ assert_equal('UniqueCallPathTest#test_children_of', method.full_name)
106
+
107
+ call_info_a = nil
108
+ root_methods[0].children.each do | c |
109
+ if c.target.full_name == "UniqueCallPath#method_a"
110
+ call_info_a = c
111
+ break
112
+ end
113
+ end
114
+
115
+ assert !call_info_a.nil?
116
+
117
+ children_of_a = Array.new
118
+
119
+ call_info_a.children.each do | c |
120
+ if c.parent.eql?(call_info_a)
121
+ children_of_a.push(c)
122
+ end
123
+ end
124
+
125
+ if RUBY_VERSION < '1.9'
126
+ assert_equal(4, call_info_a.target.children.length)
127
+ else
128
+ assert_equal(2, call_info_a.target.children.length)
129
+ end
130
+
131
+ children_of_a = children_of_a.sort do |c1, c2|
132
+ c1.target.full_name <=> c2.target.full_name
133
+ end
134
+ if RUBY_VERSION < '1.9'
135
+ assert_equal(2, children_of_a.length)
136
+ assert_equal("Fixnum#==", children_of_a[0].target.full_name)
137
+ assert_equal("UniqueCallPath#method_b", children_of_a[1].target.full_name)
138
+ else
139
+ assert_equal(1, children_of_a.length)
140
+ assert_equal("UniqueCallPath#method_b", children_of_a[0].target.full_name)
141
+ end
142
+
143
+ end
144
+
145
+ def test_id2ref
146
+ unique_call_path = UniqueCallPath.new
147
+
148
+ result = RubyProf.profile do
149
+ unique_call_path.method_a(1)
150
+ end
151
+
152
+ root_methods = Array.new
153
+ result.threads.each do | thread_id, methods |
154
+ methods.each do | m |
155
+ if m.root?
156
+ root_methods.push(m)
157
+ end
158
+ end
159
+ end
160
+
161
+ child = root_methods[0].children[0]
162
+
163
+ assert_not_equal(0, child.object_id)
164
+ #assert_equal(RubyProf::CallInfo.id2ref(child.id).target.full_name, child.target.full_name)
165
+ end
166
+
167
+ def test_unique_path
168
+ unique_call_path = UniqueCallPath.new
169
+
170
+ result = RubyProf.profile do
171
+ unique_call_path.method_a(1)
172
+ unique_call_path.method_k(1)
173
+ end
174
+
175
+ root_methods = Array.new
176
+ result.threads.each do | thread_id, methods |
177
+ methods.each do | m |
178
+ if m.root?
179
+ root_methods.push(m)
180
+ end
181
+ end
182
+ end
183
+
184
+ assert_equal(1, root_methods.length)
185
+
186
+ call_info_a = nil
187
+ root_methods[0].children.each do | c |
188
+ if c.target.full_name == "UniqueCallPath#method_a"
189
+ call_info_a = c
190
+ break
191
+ end
192
+ end
193
+
194
+ assert !call_info_a.nil?
195
+
196
+ children_of_a = Array.new
197
+ call_info_a.children.each do |c|
198
+ if c.parent.eql?(call_info_a)
199
+ children_of_a.push(c)
200
+ end
201
+ end
202
+
203
+ if RUBY_VERSION < '1.9'
204
+ assert_equal(4, call_info_a.target.children.length)
205
+ else
206
+ assert_equal(2, call_info_a.target.children.length)
207
+ end
208
+
209
+ children_of_a = children_of_a.sort do |c1, c2|
210
+ c1.target.full_name <=> c2.target.full_name
211
+ end
212
+
213
+ if RUBY_VERSION < '1.9'
214
+ assert_equal(2, children_of_a.length)
215
+ assert_equal(1, children_of_a[0].called)
216
+ assert_equal("Fixnum#==", children_of_a[0].target.full_name)
217
+ assert_equal(1, children_of_a[1].called)
218
+ assert_equal("UniqueCallPath#method_b", children_of_a[1].target.full_name)
219
+ else
220
+ assert_equal(1, children_of_a.length)
221
+ assert_equal(1, children_of_a[0].called)
222
+ assert_equal("UniqueCallPath#method_b", children_of_a[0].target.full_name)
223
+ end
224
+ end
225
+ end