skaes-ruby-prof 0.7.3

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 (67) hide show
  1. data/CHANGES +202 -0
  2. data/LICENSE +23 -0
  3. data/README +436 -0
  4. data/Rakefile +129 -0
  5. data/bin/ruby-prof +207 -0
  6. data/examples/flat.txt +55 -0
  7. data/examples/graph.html +823 -0
  8. data/examples/graph.txt +170 -0
  9. data/ext/extconf.rb +34 -0
  10. data/ext/measure_allocations.h +58 -0
  11. data/ext/measure_cpu_time.h +152 -0
  12. data/ext/measure_gc_runs.h +76 -0
  13. data/ext/measure_gc_time.h +57 -0
  14. data/ext/measure_memory.h +101 -0
  15. data/ext/measure_process_time.h +52 -0
  16. data/ext/measure_wall_time.h +53 -0
  17. data/ext/mingw/Rakefile +23 -0
  18. data/ext/mingw/build.rake +38 -0
  19. data/ext/ruby_prof.c +1747 -0
  20. data/ext/ruby_prof.h +185 -0
  21. data/ext/vc/ruby_prof.sln +20 -0
  22. data/ext/vc/ruby_prof.vcproj +241 -0
  23. data/ext/version.h +4 -0
  24. data/lib/ruby-prof.rb +51 -0
  25. data/lib/ruby-prof/abstract_printer.rb +41 -0
  26. data/lib/ruby-prof/aggregate_call_info.rb +68 -0
  27. data/lib/ruby-prof/call_info.rb +112 -0
  28. data/lib/ruby-prof/call_stack_printer.rb +746 -0
  29. data/lib/ruby-prof/call_tree_printer.rb +84 -0
  30. data/lib/ruby-prof/empty.png +0 -0
  31. data/lib/ruby-prof/flat_printer.rb +79 -0
  32. data/lib/ruby-prof/graph_html_printer.rb +272 -0
  33. data/lib/ruby-prof/graph_printer.rb +164 -0
  34. data/lib/ruby-prof/method_info.rb +131 -0
  35. data/lib/ruby-prof/minus.png +0 -0
  36. data/lib/ruby-prof/multi_printer.rb +55 -0
  37. data/lib/ruby-prof/plus.png +0 -0
  38. data/lib/ruby-prof/result.rb +70 -0
  39. data/lib/ruby-prof/task.rb +146 -0
  40. data/lib/ruby-prof/test.rb +148 -0
  41. data/lib/unprof.rb +8 -0
  42. data/rails/environment/profile.rb +24 -0
  43. data/rails/example/example_test.rb +9 -0
  44. data/rails/profile_test_helper.rb +21 -0
  45. data/test/aggregate_test.rb +136 -0
  46. data/test/basic_test.rb +283 -0
  47. data/test/duplicate_names_test.rb +32 -0
  48. data/test/exceptions_test.rb +15 -0
  49. data/test/exclude_threads_test.rb +54 -0
  50. data/test/line_number_test.rb +73 -0
  51. data/test/measurement_test.rb +121 -0
  52. data/test/method_elimination_test.rb +74 -0
  53. data/test/module_test.rb +54 -0
  54. data/test/multi_printer_test.rb +81 -0
  55. data/test/no_method_class_test.rb +13 -0
  56. data/test/prime.rb +58 -0
  57. data/test/prime_test.rb +13 -0
  58. data/test/printers_test.rb +73 -0
  59. data/test/recursive_test.rb +215 -0
  60. data/test/singleton_test.rb +38 -0
  61. data/test/stack_printer_test.rb +74 -0
  62. data/test/stack_test.rb +138 -0
  63. data/test/start_stop_test.rb +95 -0
  64. data/test/test_suite.rb +26 -0
  65. data/test/thread_test.rb +159 -0
  66. data/test/unique_call_path_test.rb +206 -0
  67. metadata +128 -0
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ require 'ruby-prof'
3
+
4
+ # Make sure this works with no class or method
5
+ result = RubyProf.profile do
6
+ sleep 1
7
+ end
8
+
9
+ methods = result.threads.values.first
10
+ global_method = methods.sort_by {|method| method.full_name}.first
11
+ if global_method.full_name != 'Global#[No method]'
12
+ raise(RuntimeError, "Wrong method name. Expected: Global#[No method]. Actual: #{global_method.full_name}")
13
+ end
@@ -0,0 +1,58 @@
1
+ # A silly little test program that finds prime numbers. It
2
+ # is intentionally badly designed to show off the use
3
+ # of ruby-prof.
4
+ #
5
+ # Source from http://people.cs.uchicago.edu/~bomb154/154/maclabs/profilers-lab/
6
+
7
+ def make_random_array(length, maxnum)
8
+ result = Array.new(length)
9
+ result.each_index do |i|
10
+ result[i] = rand(maxnum)
11
+ end
12
+
13
+ result
14
+ end
15
+
16
+ def is_prime(x)
17
+ y = 2
18
+ y.upto(x-1) do |i|
19
+ return false if (x % i) == 0
20
+ end
21
+ true
22
+ end
23
+
24
+ def find_primes(arr)
25
+ result = arr.select do |value|
26
+ is_prime(value)
27
+ end
28
+ result
29
+ end
30
+
31
+ def find_largest(primes)
32
+ largest = primes.first
33
+
34
+ # Intentionally use upto for example purposes
35
+ # (upto is also called from is_prime)
36
+ 0.upto(primes.length-1) do |i|
37
+ sleep(0.02)
38
+ prime = primes[i]
39
+ if prime > largest
40
+ largest = prime
41
+ end
42
+ end
43
+ largest
44
+ end
45
+
46
+ def run_primes
47
+ length = 10
48
+ maxnum = 10000
49
+
50
+ # Create random numbers
51
+ random_array = make_random_array(length, maxnum)
52
+
53
+ # Find the primes
54
+ primes = find_primes(random_array)
55
+
56
+ # Find the largest primes
57
+ largest = find_largest(primes)
58
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'ruby-prof'
4
+ require 'prime'
5
+
6
+ # -- Tests ----
7
+ class PrimeTest< Test::Unit::TestCase
8
+ def test_consistency
9
+ result = RubyProf.profile do
10
+ run_primes
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'ruby-prof'
4
+ require 'prime'
5
+
6
+ # -- Tests ----
7
+ class PrintersTest < Test::Unit::TestCase
8
+ def setup
9
+ RubyProf::measure_mode = RubyProf::PROCESS_TIME
10
+ @result = RubyProf.profile do
11
+ run_primes
12
+ end
13
+ end
14
+
15
+ def test_printers
16
+ output = ENV['SHOW_FILES'] == "1" ? STDOUT : ''
17
+
18
+ printer = RubyProf::FlatPrinter.new(@result)
19
+ printer.print(output)
20
+
21
+ printer = RubyProf::GraphHtmlPrinter.new(@result)
22
+ printer.print(output)
23
+
24
+ printer = RubyProf::GraphPrinter.new(@result)
25
+ printer.print(output)
26
+
27
+ printer = RubyProf::CallTreePrinter.new(@result)
28
+ printer.print(output)
29
+
30
+ # we should get here
31
+ assert(true)
32
+ end
33
+
34
+ def test_flat_string
35
+ output = ''
36
+
37
+ printer = RubyProf::FlatPrinter.new(@result)
38
+ assert_nothing_raised { printer.print(output) }
39
+
40
+ assert_match(/Thread ID: -?\d+/i, output)
41
+ assert_match(/Total: \d+\.\d+/i, output)
42
+ assert_match(/Object#run_primes/i, output)
43
+ end
44
+
45
+ def test_graph_html_string
46
+ output = ''
47
+ printer = RubyProf::GraphHtmlPrinter.new(@result)
48
+ assert_nothing_raised { printer.print(output) }
49
+
50
+ assert_match( /DTD HTML 4\.01/i, output )
51
+ assert_match( %r{<th>Total Time</th>}i, output )
52
+ assert_match( /Object#run_primes/i, output )
53
+ end
54
+
55
+ def test_graph_string
56
+ output = ''
57
+ printer = RubyProf::GraphPrinter.new(@result)
58
+ assert_nothing_raised { printer.print(output) }
59
+
60
+ assert_match( /Thread ID: -?\d+/i, output )
61
+ assert_match( /Total Time: \d+\.\d+/i, output )
62
+ assert_match( /Object#run_primes/i, output )
63
+ end
64
+
65
+ def test_call_tree_string
66
+ output = ''
67
+ printer = RubyProf::CallTreePrinter.new(@result)
68
+ assert_nothing_raised { printer.print(output) }
69
+
70
+ assert_match(/fn=Object::find_primes/i, output)
71
+ assert_match(/events: process_time/i, output)
72
+ end
73
+ end
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'ruby-prof'
4
+
5
+ def simple(n)
6
+ sleep(1)
7
+ n -= 1
8
+ return if n == 0
9
+ simple(n)
10
+ end
11
+
12
+ def cycle(n)
13
+ sub_cycle(n)
14
+ end
15
+
16
+ def sub_cycle(n)
17
+ sleep(1)
18
+ n -= 1
19
+ return if n == 0
20
+ cycle(n)
21
+ end
22
+
23
+
24
+ # -- Tests ----
25
+ class RecursiveTest < Test::Unit::TestCase
26
+ def setup
27
+ # Need to use wall time for this test due to the sleep calls
28
+ RubyProf::measure_mode = RubyProf::WALL_TIME
29
+ end
30
+
31
+ def test_simple
32
+ result = RubyProf.profile do
33
+ simple(2)
34
+ end
35
+
36
+ methods = result.threads.values.first.sort.reverse
37
+ assert_equal(5, methods.length)
38
+
39
+ method = methods[0]
40
+ assert_equal('RecursiveTest#test_simple', method.full_name)
41
+ assert_equal(1, method.called)
42
+ assert_in_delta(2, method.total_time, 0.01)
43
+ assert_in_delta(0, method.self_time, 0.01)
44
+ assert_in_delta(0, method.wait_time, 0.01)
45
+ assert_in_delta(2, method.children_time, 0.01)
46
+
47
+ assert_equal(1, method.call_infos.length)
48
+ call_info = method.call_infos[0]
49
+ assert_equal('RecursiveTest#test_simple', call_info.call_sequence)
50
+ assert_equal(1, call_info.children.length)
51
+
52
+ method = methods[1]
53
+ assert_equal('Object#simple', method.full_name)
54
+ assert_equal(2, method.called)
55
+ assert_in_delta(2, method.total_time, 0.01)
56
+ assert_in_delta(0, method.self_time, 0.01)
57
+ assert_in_delta(0, method.wait_time, 0.01)
58
+ assert_in_delta(2, method.children_time, 0.01)
59
+
60
+ assert_equal(2, method.call_infos.length)
61
+ call_info = method.call_infos[0]
62
+ assert_equal('RecursiveTest#test_simple->Object#simple', call_info.call_sequence)
63
+ assert_equal(4, call_info.children.length)
64
+
65
+ method = methods[2]
66
+ assert_equal('Kernel#sleep', method.full_name)
67
+ assert_equal(2, method.called)
68
+ assert_in_delta(2, method.total_time, 0.01)
69
+ assert_in_delta(2, method.self_time, 0.01)
70
+ assert_in_delta(0, method.wait_time, 0.01)
71
+ assert_in_delta(0, method.children_time, 0.01)
72
+
73
+ assert_equal(2, method.call_infos.length)
74
+ call_info = method.call_infos[0]
75
+ assert_equal('RecursiveTest#test_simple->Object#simple->Kernel#sleep', call_info.call_sequence)
76
+ assert_equal(0, call_info.children.length)
77
+
78
+ call_info = method.call_infos[1]
79
+ assert_equal('RecursiveTest#test_simple->Object#simple->Object#simple->Kernel#sleep', call_info.call_sequence)
80
+ assert_equal(0, call_info.children.length)
81
+
82
+ method = methods[3]
83
+ assert_equal('Fixnum#-', method.full_name)
84
+ assert_equal(2, method.called)
85
+ assert_in_delta(0, method.total_time, 0.01)
86
+ assert_in_delta(0, method.self_time, 0.01)
87
+ assert_in_delta(0, method.wait_time, 0.01)
88
+ assert_in_delta(0, method.children_time, 0.01)
89
+
90
+ assert_equal(2, method.call_infos.length)
91
+ call_info = method.call_infos[0]
92
+ assert_equal('RecursiveTest#test_simple->Object#simple->Fixnum#-', call_info.call_sequence)
93
+ assert_equal(0, call_info.children.length)
94
+
95
+ call_info = method.call_infos[1]
96
+ assert_equal('RecursiveTest#test_simple->Object#simple->Object#simple->Fixnum#-', call_info.call_sequence)
97
+ assert_equal(0, call_info.children.length)
98
+
99
+ method = methods[4]
100
+ assert_equal('Fixnum#==', method.full_name)
101
+ assert_equal(2, method.called)
102
+ assert_in_delta(0, method.total_time, 0.01)
103
+ assert_in_delta(0, method.self_time, 0.01)
104
+ assert_in_delta(0, method.wait_time, 0.01)
105
+ assert_in_delta(0, method.children_time, 0.01)
106
+
107
+ assert_equal(2, method.call_infos.length)
108
+ call_info = method.call_infos[0]
109
+ assert_equal('RecursiveTest#test_simple->Object#simple->Fixnum#==', call_info.call_sequence)
110
+ assert_equal(0, call_info.children.length)
111
+
112
+ call_info = method.call_infos[1]
113
+ assert_equal('RecursiveTest#test_simple->Object#simple->Object#simple->Fixnum#==', call_info.call_sequence)
114
+ assert_equal(0, call_info.children.length)
115
+ end
116
+
117
+ def test_cycle
118
+ result = RubyProf.profile do
119
+ cycle(2)
120
+ end
121
+
122
+ methods = result.threads.values.first.sort.reverse
123
+ assert_equal(6, methods.length)
124
+
125
+ method = methods[0]
126
+ assert_equal('RecursiveTest#test_cycle', method.full_name)
127
+ assert_equal(1, method.called)
128
+ assert_in_delta(2, method.total_time, 0.01)
129
+ assert_in_delta(0, method.self_time, 0.01)
130
+ assert_in_delta(0, method.wait_time, 0.01)
131
+ assert_in_delta(2, method.children_time, 0.01)
132
+
133
+ assert_equal(1, method.call_infos.length)
134
+ call_info = method.call_infos[0]
135
+ assert_equal('RecursiveTest#test_cycle', call_info.call_sequence)
136
+ assert_equal(1, call_info.children.length)
137
+
138
+ method = methods[1]
139
+ assert_equal('Object#cycle', method.full_name)
140
+ assert_equal(2, method.called)
141
+ assert_in_delta(2, method.total_time, 0.01)
142
+ assert_in_delta(0, method.self_time, 0.01)
143
+ assert_in_delta(0, method.wait_time, 0.01)
144
+ assert_in_delta(2, method.children_time, 0.01)
145
+
146
+ assert_equal(2, method.call_infos.length)
147
+ call_info = method.call_infos[0]
148
+ assert_equal('RecursiveTest#test_cycle->Object#cycle', call_info.call_sequence)
149
+ assert_equal(1, call_info.children.length)
150
+
151
+ method = methods[2]
152
+ assert_equal('Object#sub_cycle', method.full_name)
153
+ assert_equal(2, method.called)
154
+ assert_in_delta(2, method.total_time, 0.01)
155
+ assert_in_delta(0, method.self_time, 0.01)
156
+ assert_in_delta(0, method.wait_time, 0.01)
157
+ assert_in_delta(2, method.children_time, 0.01)
158
+
159
+ assert_equal(2, method.call_infos.length)
160
+ call_info = method.call_infos[0]
161
+ assert_equal('RecursiveTest#test_cycle->Object#cycle->Object#sub_cycle', call_info.call_sequence)
162
+ assert_equal(4, call_info.children.length)
163
+
164
+ method = methods[3]
165
+ assert_equal('Kernel#sleep', method.full_name)
166
+ assert_equal(2, method.called)
167
+ assert_in_delta(2, method.total_time, 0.01)
168
+ assert_in_delta(2, method.self_time, 0.01)
169
+ assert_in_delta(0, method.wait_time, 0.01)
170
+ assert_in_delta(0, method.children_time, 0.01)
171
+
172
+ assert_equal(2, method.call_infos.length)
173
+ call_info = method.call_infos[0]
174
+ assert_equal('RecursiveTest#test_cycle->Object#cycle->Object#sub_cycle->Kernel#sleep', call_info.call_sequence)
175
+ assert_equal(0, call_info.children.length)
176
+
177
+ call_info = method.call_infos[1]
178
+ assert_equal('RecursiveTest#test_cycle->Object#cycle->Object#sub_cycle->Object#cycle->Object#sub_cycle->Kernel#sleep', call_info.call_sequence)
179
+ assert_equal(0, call_info.children.length)
180
+
181
+ method = methods[4]
182
+ assert_equal('Fixnum#-', method.full_name)
183
+ assert_equal(2, method.called)
184
+ assert_in_delta(0, method.total_time, 0.01)
185
+ assert_in_delta(0, method.self_time, 0.01)
186
+ assert_in_delta(0, method.wait_time, 0.01)
187
+ assert_in_delta(0, method.children_time, 0.01)
188
+
189
+ assert_equal(2, method.call_infos.length)
190
+ call_info = method.call_infos[0]
191
+ assert_equal('RecursiveTest#test_cycle->Object#cycle->Object#sub_cycle->Fixnum#-', call_info.call_sequence)
192
+ assert_equal(0, call_info.children.length)
193
+
194
+ call_info = method.call_infos[1]
195
+ assert_equal('RecursiveTest#test_cycle->Object#cycle->Object#sub_cycle->Object#cycle->Object#sub_cycle->Fixnum#-', call_info.call_sequence)
196
+ assert_equal(0, call_info.children.length)
197
+
198
+ method = methods[5]
199
+ assert_equal('Fixnum#==', method.full_name)
200
+ assert_equal(2, method.called)
201
+ assert_in_delta(0, method.total_time, 0.01)
202
+ assert_in_delta(0, method.self_time, 0.01)
203
+ assert_in_delta(0, method.wait_time, 0.01)
204
+ assert_in_delta(0, method.children_time, 0.01)
205
+
206
+ assert_equal(2, method.call_infos.length)
207
+ call_info = method.call_infos[0]
208
+ assert_equal('RecursiveTest#test_cycle->Object#cycle->Object#sub_cycle->Fixnum#==', call_info.call_sequence)
209
+ assert_equal(0, call_info.children.length)
210
+
211
+ call_info = method.call_infos[1]
212
+ assert_equal('RecursiveTest#test_cycle->Object#cycle->Object#sub_cycle->Object#cycle->Object#sub_cycle->Fixnum#==', call_info.call_sequence)
213
+ assert_equal(0, call_info.children.length)
214
+ end
215
+ end
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'ruby-prof'
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 < Test::Unit::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_FILES'] == "1" ? STDOUT : ''
36
+ printer.print(output)
37
+ end
38
+ end
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'ruby-prof'
5
+ require 'tmpdir'
6
+
7
+ # Test data
8
+ # A
9
+ # / \
10
+ # B C
11
+ # \
12
+ # B
13
+
14
+ class STPT
15
+ def a
16
+ 100.times{b}
17
+ 300.times{c}
18
+ c;c;c
19
+ end
20
+
21
+ def b
22
+ sleep 0.0001
23
+ end
24
+
25
+ def c
26
+ 5.times{b}
27
+ end
28
+ end
29
+
30
+ class StackPrinterTest < Test::Unit::TestCase
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_stack_can_be_printed
37
+ start_time = Time.now
38
+ RubyProf.start
39
+ 5.times{STPT.new.a}
40
+ result = RubyProf.stop
41
+ end_time = Time.now
42
+ expected_time = end_time - start_time
43
+
44
+ file_contents = nil
45
+ assert_nothing_raised { file_contents = print(result) }
46
+ assert file_contents =~ /Thread: (\d+) \(100\.00% ~ ([.0-9]+) seconds\)/
47
+ actual_time = $2.to_f
48
+ difference = (expected_time-actual_time).abs
49
+ assert difference<0.001 # less than 1 ms
50
+ end
51
+
52
+ def test_method_elimination
53
+ RubyProf.start
54
+ 5.times{STPT.new.a}
55
+ result = RubyProf.stop
56
+ assert_nothing_raised {
57
+ # result.dump
58
+ result.eliminate_methods!([/Integer#times/])
59
+ # $stderr.puts "================================"
60
+ # result.dump
61
+ print(result)
62
+ }
63
+ end
64
+
65
+ private
66
+ def print(result)
67
+ test = caller.first =~ /in `(.*)'/ ? $1 : "test"
68
+ testfile_name = "#{Dir::tmpdir}/ruby_prof_#{test}.html"
69
+ printer = RubyProf::CallStackPrinter.new(result)
70
+ File.open(testfile_name, "w") {|f| printer.print(f, :threshold => 0, :min_percent => 0, :title => "ruby_prof #{test}")}
71
+ system("open #{testfile_name}") if RUBY_PLATFORM =~ /darwin/ && ENV['SHOW_FILES']=="1"
72
+ File.open(testfile_name, "r"){|f| f.read}
73
+ end
74
+ end