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,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'ruby-prof'
5
+
6
+ class DuplicateNames < Test::Unit::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
+ DuplicateNames.class_eval {remove_const :Foo}
14
+
15
+ eval str
16
+ Foo::Bar.new.foo
17
+ DuplicateNames.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.values.first.sort.reverse
25
+
26
+ methods = methods.select do |method|
27
+ method.full_name == 'DuplicateNames::Foo::Bar#foo'
28
+ end
29
+
30
+ assert_equal(3, methods.length)
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'ruby-prof'
4
+
5
+ class ExceptionsTest < Test::Unit::TestCase
6
+ def test_profile
7
+ result = begin
8
+ RubyProf.profile do
9
+ raise(RuntimeError, 'Test error')
10
+ end
11
+ rescue => e
12
+ end
13
+ assert_not_nil(result)
14
+ end
15
+ end
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'ruby-prof'
5
+
6
+
7
+ # -- Tests ----
8
+ class ExcludeThreadsTest < Test::Unit::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
+ RubyProf::exclude_threads = [ thread2 ]
30
+
31
+ RubyProf.start
32
+
33
+ thread1.join
34
+ thread2.join
35
+
36
+ result = RubyProf.stop
37
+
38
+ RubyProf::exclude_threads = nil
39
+
40
+ assert_equal(2, result.threads.length)
41
+
42
+ output = Array.new
43
+ result.threads.each do | thread_id, methods |
44
+ methods.each do | m |
45
+ if m.full_name.index("ExcludeThreadsTest#thread") == 0
46
+ output.push(m.full_name)
47
+ end
48
+ end
49
+ end
50
+
51
+ assert_equal(1, output.length)
52
+ assert_equal("ExcludeThreadsTest#thread1_proc", output[0])
53
+ end
54
+ end
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'ruby-prof'
4
+ require 'prime'
5
+
6
+ class LineNumbers
7
+ def method1
8
+ a = 3
9
+ end
10
+
11
+ def method2
12
+ a = 3
13
+ method1
14
+ end
15
+
16
+ def method3
17
+ sleep(1)
18
+ end
19
+ end
20
+
21
+ # -- Tests ----
22
+ class LineNumbersTest < Test::Unit::TestCase
23
+ def test_function_line_no
24
+ numbers = LineNumbers.new
25
+
26
+ result = RubyProf.profile do
27
+ numbers.method2
28
+ end
29
+
30
+ methods = result.threads.values.first.sort.reverse
31
+ assert_equal(3, methods.length)
32
+
33
+ method = methods[0]
34
+ assert_equal('LineNumbersTest#test_function_line_no', method.full_name)
35
+ assert_equal(27, method.line)
36
+
37
+ method = methods[1]
38
+ assert_equal('LineNumbers#method2', method.full_name)
39
+ assert_equal(11, method.line)
40
+
41
+ method = methods[2]
42
+ assert_equal('LineNumbers#method1', method.full_name)
43
+ assert_equal(7, method.line)
44
+ end
45
+
46
+ def test_c_function
47
+ numbers = LineNumbers.new
48
+
49
+ result = RubyProf.profile do
50
+ numbers.method3
51
+ end
52
+
53
+ methods = result.threads.values.first.sort_by {|method| method.full_name}
54
+ assert_equal(3, methods.length)
55
+
56
+ # Methods:
57
+ # LineNumbers#method3
58
+ # LineNumbersTest#test_c_function
59
+ # Kernel#sleep
60
+
61
+ method = methods[0]
62
+ assert_equal('Kernel#sleep', method.full_name)
63
+ assert_equal(0, method.line)
64
+
65
+ method = methods[1]
66
+ assert_equal('LineNumbers#method3', method.full_name)
67
+ assert_equal(16, method.line)
68
+
69
+ method = methods[2]
70
+ assert_equal('LineNumbersTest#test_c_function', method.full_name)
71
+ assert_equal(50, method.line)
72
+ end
73
+ end
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'ruby-prof'
4
+
5
+ class MeasurementTest < Test::Unit::TestCase
6
+ def setup
7
+ GC.enable_stats if GC.respond_to?(:enable_stats)
8
+ end
9
+
10
+ def teardown
11
+ GC.disable_stats if GC.respond_to?(:disable_stats)
12
+ end
13
+
14
+ def test_process_time_mode
15
+ RubyProf::measure_mode = RubyProf::PROCESS_TIME
16
+ assert_equal(RubyProf::PROCESS_TIME, RubyProf::measure_mode)
17
+ end
18
+
19
+ def test_process_time
20
+ t = RubyProf.measure_process_time
21
+ assert_kind_of(Float, t)
22
+
23
+ u = RubyProf.measure_process_time
24
+ assert(u >= t, [t, u].inspect)
25
+ end
26
+
27
+ def test_wall_time_mode
28
+ RubyProf::measure_mode = RubyProf::WALL_TIME
29
+ assert_equal(RubyProf::WALL_TIME, RubyProf::measure_mode)
30
+ end
31
+
32
+ def test_wall_time
33
+ t = RubyProf.measure_wall_time
34
+ assert_kind_of Float, t
35
+
36
+ u = RubyProf.measure_wall_time
37
+ assert u >= t, [t, u].inspect
38
+ end
39
+
40
+ if RubyProf::CPU_TIME
41
+ def test_cpu_time_mode
42
+ RubyProf::measure_mode = RubyProf::CPU_TIME
43
+ assert_equal(RubyProf::CPU_TIME, RubyProf::measure_mode)
44
+ end
45
+
46
+ def test_cpu_time
47
+ RubyProf.cpu_frequency = 2.33e9
48
+
49
+ t = RubyProf.measure_cpu_time
50
+ assert_kind_of Float, t
51
+
52
+ u = RubyProf.measure_cpu_time
53
+ assert u > t, [t, u].inspect
54
+ end
55
+ end
56
+
57
+ if RubyProf::ALLOCATIONS
58
+ def test_allocations_mode
59
+ RubyProf::measure_mode = RubyProf::ALLOCATIONS
60
+ assert_equal(RubyProf::ALLOCATIONS, RubyProf::measure_mode)
61
+ end
62
+
63
+ def test_allocations
64
+ t = RubyProf.measure_allocations
65
+ assert_kind_of Integer, t
66
+
67
+ u = RubyProf.measure_allocations
68
+ assert u > t, [t, u].inspect
69
+ end
70
+ end
71
+
72
+ if RubyProf::MEMORY
73
+ def test_memory_mode
74
+ RubyProf::measure_mode = RubyProf::MEMORY
75
+ assert_equal(RubyProf::MEMORY, RubyProf::measure_mode)
76
+ end
77
+
78
+ def test_memory
79
+ t = RubyProf.measure_memory
80
+ assert_kind_of Integer, t
81
+
82
+ u = RubyProf.measure_memory
83
+ assert(u >= t, [t, u].inspect)
84
+
85
+ result = RubyProf.profile {Array.new}
86
+ total = result.threads.values.first.methods.inject(0) { |sum, m| sum + m.total_time }
87
+
88
+ assert(total > 0, 'Should measure more than zero kilobytes of memory usage')
89
+ assert_not_equal(0, total % 1, 'Should not truncate fractional kilobyte measurements')
90
+ end
91
+ end
92
+
93
+ if RubyProf::GC_RUNS
94
+ def test_gc_runs_mode
95
+ RubyProf::measure_mode = RubyProf::GC_RUNS
96
+ assert_equal(RubyProf::GC_RUNS, RubyProf::measure_mode)
97
+ end
98
+
99
+ def test_gc_runs
100
+ t = RubyProf.measure_gc_runs
101
+ assert_kind_of Integer, t
102
+
103
+ GC.start
104
+
105
+ u = RubyProf.measure_gc_runs
106
+ assert u > t, [t, u].inspect
107
+ end
108
+ end
109
+
110
+ if RubyProf::GC_TIME
111
+ def test_gc_time
112
+ t = RubyProf.measure_gc_time
113
+ assert_kind_of Integer, t
114
+
115
+ GC.start
116
+
117
+ u = RubyProf.measure_gc_time
118
+ assert u > t, [t, u].inspect
119
+ end
120
+ end
121
+ 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 ESTPT
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 MethodEliminationTest < 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_setting_parent
37
+ result = RubyProf.profile do
38
+ 1000.times { 1+1 }
39
+ end
40
+ method_infos = result.threads.values.first
41
+ assert(m1 = method_infos[0])
42
+ assert(c1 = m1.call_infos.first)
43
+ assert_equal(c1, c1.parent = c1)
44
+ assert_equal c1, c1.parent
45
+ end
46
+
47
+ def test_methods_can_be_eliminated
48
+ RubyProf.start
49
+ 5.times{ESTPT.new.a}
50
+ result = RubyProf.stop
51
+ # result.dump
52
+ eliminated = result.eliminate_methods!([/Integer#times/])
53
+ # puts eliminated.inspect
54
+ # result.dump
55
+ eliminated.each do |m|
56
+ assert_method_has_been_eliminated(result, m)
57
+ end
58
+ end
59
+
60
+ private
61
+ def assert_method_has_been_eliminated(result, eliminated_method)
62
+ result.threads.each do |thread_id, methods|
63
+ methods.each do |method|
64
+ method.call_infos.each do |ci|
65
+ assert(ci.target != eliminated_method, "broken self")
66
+ assert(ci.parent.target != eliminated_method, "broken parent") if ci.parent
67
+ ci.children.each do |callee|
68
+ assert(callee.target != eliminated_method, "broken kid")
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'ruby-prof'
4
+
5
+ # Need to use wall time for this test due to the sleep calls
6
+ RubyProf::measure_mode = RubyProf::WALL_TIME
7
+
8
+ module Foo
9
+ def Foo::hello
10
+ sleep(0.5)
11
+ end
12
+ end
13
+
14
+ module Bar
15
+ def Bar::hello
16
+ sleep(0.5)
17
+ Foo::hello
18
+ end
19
+
20
+ def hello
21
+ sleep(0.5)
22
+ Bar::hello
23
+ end
24
+ end
25
+
26
+ include Bar
27
+
28
+ class ModuleTest < Test::Unit::TestCase
29
+ def test_nested_modules
30
+ result = RubyProf.profile do
31
+ hello
32
+ end
33
+
34
+ methods = result.threads.values.first.sort.reverse
35
+
36
+ # Length should be 5
37
+ assert_equal(5, methods.length)
38
+
39
+ method = methods[0]
40
+ assert_equal('ModuleTest#test_nested_modules', method.full_name)
41
+
42
+ method = methods[1]
43
+ assert_equal('Bar#hello', method.full_name)
44
+
45
+ method = methods[2]
46
+ assert_equal('Kernel#sleep', method.full_name)
47
+
48
+ method = methods[3]
49
+ assert_equal('<Module::Bar>#hello', method.full_name)
50
+
51
+ method = methods[4]
52
+ assert_equal('<Module::Foo>#hello', method.full_name)
53
+ end
54
+ end
@@ -0,0 +1,81 @@
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 MSTPT
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 MultiPrinterTest < 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_all_profiles_can_be_created
37
+ start_time = Time.now
38
+ RubyProf.start
39
+ 5.times{MSTPT.new.a}
40
+ result = RubyProf.stop
41
+ end_time = Time.now
42
+ expected_time = end_time - start_time
43
+ stack = graph = nil
44
+ assert_nothing_raised { stack, graph = print(result) }
45
+ re = Regexp.new('
46
+ \s*<table>
47
+ \s*<tr>
48
+ \s*<th>Thread ID</th>
49
+ \s*<th>Total Time</th>
50
+ \s*</tr>
51
+ \s*
52
+ \s*<tr>
53
+ \s*<td><a href="#\d+">\d+</a></td>
54
+ \s*<td>([\.0-9]+)</td>
55
+ \s*</tr>
56
+ \s*
57
+ \s*</table>')
58
+ assert graph =~ re
59
+ display_time = $1.to_f
60
+ difference = (expected_time-display_time).abs
61
+ assert_in_delta expected_time, display_time, 0.001
62
+ end
63
+
64
+ private
65
+ def print(result)
66
+ test = caller.first =~ /in `(.*)'/ ? $1 : "test"
67
+ path = Dir::tmpdir
68
+ profile = "ruby_prof_#{test}"
69
+ printer = RubyProf::MultiPrinter.new(result)
70
+ printer.print(:path => path, :profile => profile,
71
+ :threshold => 0, :min_percent => 0, :title => "ruby_prof #{test}")
72
+ if RUBY_PLATFORM =~ /darwin/ && ENV['SHOW_FILES']=="1"
73
+ system("open #{printer.stack_profile}")
74
+ end
75
+ if GC.respond_to?(:dump_file_and_line_info)
76
+ GC.start
77
+ GC.dump_file_and_line_info("heap.dump")
78
+ end
79
+ [File.open(printer.stack_profile){|f|f.read}, File.open(printer.graph_profile){|f|f.read}]
80
+ end
81
+ end