ruby-prof 0.18.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +23 -0
  3. data/LICENSE +2 -2
  4. data/README.rdoc +1 -483
  5. data/Rakefile +3 -6
  6. data/bin/ruby-prof +65 -30
  7. data/ext/ruby_prof/extconf.rb +6 -38
  8. data/ext/ruby_prof/rp_allocation.c +292 -0
  9. data/ext/ruby_prof/rp_allocation.h +31 -0
  10. data/ext/ruby_prof/rp_call_info.c +137 -279
  11. data/ext/ruby_prof/rp_call_info.h +16 -34
  12. data/ext/ruby_prof/rp_measure_allocations.c +25 -49
  13. data/ext/ruby_prof/rp_measure_memory.c +21 -56
  14. data/ext/ruby_prof/rp_measure_process_time.c +28 -36
  15. data/ext/ruby_prof/rp_measure_wall_time.c +36 -19
  16. data/ext/ruby_prof/rp_measurement.c +236 -0
  17. data/ext/ruby_prof/rp_measurement.h +49 -0
  18. data/ext/ruby_prof/rp_method.c +395 -383
  19. data/ext/ruby_prof/rp_method.h +34 -39
  20. data/ext/ruby_prof/rp_profile.c +881 -0
  21. data/ext/ruby_prof/rp_profile.h +36 -0
  22. data/ext/ruby_prof/rp_stack.c +103 -80
  23. data/ext/ruby_prof/rp_stack.h +5 -12
  24. data/ext/ruby_prof/rp_thread.c +149 -88
  25. data/ext/ruby_prof/rp_thread.h +15 -6
  26. data/ext/ruby_prof/ruby_prof.c +11 -757
  27. data/ext/ruby_prof/ruby_prof.h +4 -47
  28. data/ext/ruby_prof/vc/ruby_prof.vcxproj +10 -8
  29. data/lib/ruby-prof.rb +2 -17
  30. data/lib/ruby-prof/assets/graph_printer.html.erb +356 -0
  31. data/lib/ruby-prof/call_info.rb +35 -93
  32. data/lib/ruby-prof/call_info_visitor.rb +19 -21
  33. data/lib/ruby-prof/compatibility.rb +37 -107
  34. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  35. data/lib/ruby-prof/measurement.rb +14 -0
  36. data/lib/ruby-prof/method_info.rb +52 -83
  37. data/lib/ruby-prof/printers/abstract_printer.rb +66 -52
  38. data/lib/ruby-prof/printers/call_info_printer.rb +13 -3
  39. data/lib/ruby-prof/printers/call_stack_printer.rb +32 -28
  40. data/lib/ruby-prof/printers/call_tree_printer.rb +20 -12
  41. data/lib/ruby-prof/printers/dot_printer.rb +5 -5
  42. data/lib/ruby-prof/printers/flat_printer.rb +6 -24
  43. data/lib/ruby-prof/printers/graph_html_printer.rb +7 -192
  44. data/lib/ruby-prof/printers/graph_printer.rb +13 -15
  45. data/lib/ruby-prof/printers/multi_printer.rb +66 -23
  46. data/lib/ruby-prof/profile.rb +10 -3
  47. data/lib/ruby-prof/rack.rb +0 -3
  48. data/lib/ruby-prof/thread.rb +12 -12
  49. data/lib/ruby-prof/version.rb +1 -1
  50. data/ruby-prof.gemspec +2 -2
  51. data/test/abstract_printer_test.rb +0 -27
  52. data/test/alias_test.rb +129 -0
  53. data/test/basic_test.rb +41 -40
  54. data/test/call_info_visitor_test.rb +3 -3
  55. data/test/dynamic_method_test.rb +0 -2
  56. data/test/line_number_test.rb +120 -39
  57. data/test/marshal_test.rb +119 -0
  58. data/test/measure_allocations.rb +30 -0
  59. data/test/measure_allocations_test.rb +371 -12
  60. data/test/measure_allocations_trace_test.rb +385 -0
  61. data/test/measure_memory_trace_test.rb +756 -0
  62. data/test/measure_process_time_test.rb +821 -33
  63. data/test/measure_times.rb +54 -0
  64. data/test/measure_wall_time_test.rb +349 -145
  65. data/test/multi_printer_test.rb +1 -34
  66. data/test/parser_timings.rb +24 -0
  67. data/test/pause_resume_test.rb +5 -5
  68. data/test/prime.rb +2 -0
  69. data/test/printer_call_tree_test.rb +31 -0
  70. data/test/printer_flat_test.rb +68 -0
  71. data/test/printer_graph_html_test.rb +60 -0
  72. data/test/printer_graph_test.rb +41 -0
  73. data/test/printers_test.rb +32 -166
  74. data/test/printing_recursive_graph_test.rb +26 -72
  75. data/test/recursive_test.rb +72 -77
  76. data/test/stack_printer_test.rb +2 -15
  77. data/test/start_stop_test.rb +22 -25
  78. data/test/test_helper.rb +5 -248
  79. data/test/thread_test.rb +11 -54
  80. data/test/unique_call_path_test.rb +16 -28
  81. data/test/yarv_test.rb +1 -0
  82. metadata +24 -34
  83. data/examples/flat.txt +0 -50
  84. data/examples/graph.dot +0 -84
  85. data/examples/graph.html +0 -823
  86. data/examples/graph.txt +0 -139
  87. data/examples/multi.flat.txt +0 -23
  88. data/examples/multi.graph.html +0 -760
  89. data/examples/multi.grind.dat +0 -114
  90. data/examples/multi.stack.html +0 -547
  91. data/examples/stack.html +0 -547
  92. data/ext/ruby_prof/rp_measure.c +0 -40
  93. data/ext/ruby_prof/rp_measure.h +0 -45
  94. data/ext/ruby_prof/rp_measure_cpu_time.c +0 -136
  95. data/ext/ruby_prof/rp_measure_gc_runs.c +0 -73
  96. data/ext/ruby_prof/rp_measure_gc_time.c +0 -60
  97. data/lib/ruby-prof/aggregate_call_info.rb +0 -76
  98. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +0 -83
  99. data/lib/ruby-prof/profile/exclude_common_methods.rb +0 -207
  100. data/lib/ruby-prof/profile/legacy_method_elimination.rb +0 -50
  101. data/test/aggregate_test.rb +0 -136
  102. data/test/block_test.rb +0 -74
  103. data/test/call_info_test.rb +0 -78
  104. data/test/fiber_test.rb +0 -79
  105. data/test/issue137_test.rb +0 -63
  106. data/test/measure_cpu_time_test.rb +0 -212
  107. data/test/measure_gc_runs_test.rb +0 -32
  108. data/test/measure_gc_time_test.rb +0 -36
  109. data/test/measure_memory_test.rb +0 -33
  110. data/test/method_elimination_test.rb +0 -84
  111. data/test/module_test.rb +0 -45
  112. data/test/stack_test.rb +0 -138
@@ -1,207 +0,0 @@
1
- require 'set'
2
-
3
- module RubyProf
4
- class Profile
5
- class ExcludeCommonMethods
6
- ENUMERABLE_NAMES = Enumerable.instance_methods(false)
7
-
8
- def self.apply!(profile)
9
- new(profile).apply!
10
- end
11
-
12
- def initialize(profile)
13
- @profile = profile
14
- end
15
-
16
- def apply!
17
- ##
18
- # Kernel Methods
19
- ##
20
-
21
- exclude_methods Kernel, [
22
- :dup,
23
- :initialize_dup,
24
- :tap,
25
- :send,
26
- :public_send,
27
- ]
28
-
29
- ##
30
- # Fundamental Types
31
- ##
32
-
33
- exclude_methods BasicObject, :"!="
34
- exclude_methods Method, :"[]"
35
- exclude_methods Module, :new
36
- exclude_methods Class, :new
37
- exclude_methods Proc, :call, :yield
38
- exclude_methods Range, :each
39
- exclude_methods Integer, :times
40
-
41
- ##
42
- # Value Types
43
- ##
44
-
45
- exclude_methods String, [
46
- :sub,
47
- :sub!,
48
- :gsub,
49
- :gsub!,
50
- ]
51
-
52
- ##
53
- # Emumerables
54
- ##
55
-
56
- exclude_enumerable Enumerable
57
- exclude_enumerable Enumerator
58
-
59
- ##
60
- # Collections
61
- ##
62
-
63
- exclude_enumerable Array, [
64
- :each_index,
65
- :map!,
66
- :select!,
67
- :reject!,
68
- :collect!,
69
- :sort!,
70
- :sort_by!,
71
- :index,
72
- :delete_if,
73
- :keep_if,
74
- :drop_while,
75
- :uniq,
76
- :uniq!,
77
- :"==",
78
- :eql?,
79
- :hash,
80
- :to_json,
81
- :as_json,
82
- :encode_json,
83
- ]
84
-
85
- exclude_enumerable Hash, [
86
- :dup,
87
- :initialize_dup,
88
- :fetch,
89
- :"[]",
90
- :"[]=",
91
- :each_key,
92
- :each_value,
93
- :each_pair,
94
- :map!,
95
- :select!,
96
- :reject!,
97
- :collect!,
98
- :delete_if,
99
- :keep_if,
100
- :slice,
101
- :slice!,
102
- :except,
103
- :except!,
104
- :"==",
105
- :eql?,
106
- :hash,
107
- :to_json,
108
- :as_json,
109
- :encode_json,
110
- ]
111
-
112
- exclude_enumerable Set, [
113
- :map!,
114
- :select!,
115
- :reject!,
116
- :collect!,
117
- :classify,
118
- :delete_if,
119
- :keep_if,
120
- :divide,
121
- :"==",
122
- :eql?,
123
- :hash,
124
- :to_json,
125
- :as_json,
126
- :encode_json,
127
- ]
128
-
129
- ##
130
- # Garbage Collection
131
- ##
132
-
133
- exclude_singleton_methods GC, [
134
- :start
135
- ]
136
-
137
- ##
138
- # Unicorn
139
- ##
140
-
141
- if defined?(Unicorn)
142
- exclude_methods Unicorn::HttpServer, :process_client
143
- end
144
-
145
- if defined?(Unicorn::OobGC)
146
- exclude_methods Unicorn::OobGC, :process_client
147
- end
148
-
149
- ##
150
- # New Relic
151
- ##
152
-
153
- if defined?(NewRelic::Agent)
154
- if defined?(NewRelic::Agent::Instrumentation::MiddlewareTracing)
155
- exclude_methods NewRelic::Agent::Instrumentation::MiddlewareTracing, [
156
- :call
157
- ]
158
- end
159
-
160
- if defined?(NewRelic::Agent::MethodTracerHelpers)
161
- exclude_methods NewRelic::Agent::MethodTracerHelpers, [
162
- :trace_execution_scoped,
163
- :log_errors,
164
- ]
165
-
166
- exclude_singleton_methods NewRelic::Agent::MethodTracerHelpers, [
167
- :trace_execution_scoped,
168
- :log_errors,
169
- ]
170
- end
171
-
172
- if defined?(NewRelic::Agent::MethodTracer)
173
- exclude_methods NewRelic::Agent::MethodTracer, [
174
- :trace_execution_scoped,
175
- :trace_execution_unscoped,
176
- ]
177
- end
178
- end
179
-
180
- ##
181
- # Miscellaneous Methods
182
- ##
183
-
184
- if defined?(Mustache)
185
- exclude_methods Mustache::Context, [
186
- :fetch
187
- ]
188
- end
189
- end
190
-
191
- private
192
-
193
- def exclude_methods(mod, *method_or_methods)
194
- @profile.exclude_methods!(mod, method_or_methods)
195
- end
196
-
197
- def exclude_singleton_methods(mod, *method_or_methods)
198
- @profile.exclude_singleton_methods!(mod, method_or_methods)
199
- end
200
-
201
- def exclude_enumerable(mod, *method_or_methods)
202
- exclude_methods(mod, [:each, *method_or_methods])
203
- exclude_methods(mod, ENUMERABLE_NAMES)
204
- end
205
- end
206
- end
207
- end
@@ -1,50 +0,0 @@
1
- module RubyProf
2
- class Profile
3
- module LegacyMethodElimination
4
- # eliminate some calls from the graph by merging the information into callers.
5
- # matchers can be a list of strings or regular expressions or the name of a file containing regexps.
6
- def eliminate_methods!(matchers)
7
- RubyProf.deprecation_warning(
8
- "Method 'eliminate_methods!' is deprecated",
9
- "Please call 'exclude_methods!' before starting the profile run instead."
10
- )
11
- matchers = read_regexps_from_file(matchers) if matchers.is_a?(String)
12
- eliminated = []
13
- threads.each do |thread|
14
- matchers.each{ |matcher| eliminated.concat(eliminate_methods(thread.methods, matcher)) }
15
- end
16
- eliminated
17
- end
18
-
19
- private
20
-
21
- # read regexps from file
22
- def read_regexps_from_file(file_name)
23
- matchers = []
24
- File.open(file_name).each_line do |l|
25
- next if (l =~ /^(#.*|\s*)$/) # emtpy lines and lines starting with #
26
- matchers << Regexp.new(l.strip)
27
- end
28
- matchers
29
- end
30
-
31
- # eliminate methods matching matcher
32
- def eliminate_methods(methods, matcher)
33
- eliminated = []
34
- i = 0
35
- while i < methods.size
36
- method_info = methods[i]
37
- method_name = method_info.full_name
38
- if matcher === method_name
39
- raise "can't eliminate root method" if method_info.root?
40
- eliminated << methods.delete_at(i)
41
- method_info.eliminate!
42
- else
43
- i += 1
44
- end
45
- end
46
- eliminated
47
- end
48
- end
49
- end
50
- end
@@ -1,136 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- require File.expand_path('../test_helper', __FILE__)
5
-
6
- # Test data
7
- # A B C
8
- # | | |
9
- # Z A A
10
- # | |
11
- # Z Z
12
-
13
- class AggClass
14
- def z
15
- sleep 1
16
- end
17
-
18
- def a
19
- z
20
- end
21
-
22
- def b
23
- a
24
- end
25
-
26
- def c
27
- a
28
- end
29
- end
30
-
31
- class AggregateTest < TestCase
32
- def setup
33
- # Need to use wall time for this test due to the sleep calls
34
- RubyProf::measure_mode = RubyProf::WALL_TIME
35
- end
36
-
37
- def test_all_call_infos_are_not_recursive
38
- c1 = AggClass.new
39
- result = RubyProf.profile do
40
- c1.a
41
- c1.b
42
- c1.c
43
- end
44
- methods = result.threads.first.methods.sort.reverse
45
- methods.each do |m|
46
- m.call_infos.each do |ci|
47
- assert(!ci.recursive?)
48
- end
49
- end
50
- end
51
-
52
- def test_call_infos
53
- c1 = AggClass.new
54
- result = RubyProf.profile do
55
- c1.a
56
- c1.b
57
- c1.c
58
- end
59
-
60
- methods = result.threads.first.methods.sort.reverse
61
- method = methods.find {|meth| meth.full_name == 'AggClass#z'}
62
-
63
- # Check AggClass#z
64
- assert_equal('AggClass#z', method.full_name)
65
- assert_equal(3, method.called)
66
- assert_in_delta(3, method.total_time, 0.05)
67
- assert_in_delta(0, method.wait_time, 0.05)
68
- assert_in_delta(0, method.self_time, 0.05)
69
- assert_in_delta(3, method.children_time, 0.05)
70
- assert_equal(3, method.call_infos.length)
71
-
72
- call_info = method.call_infos[0]
73
- assert_equal('AggregateTest#test_call_infos->AggClass#a->AggClass#z', call_info.call_sequence)
74
- assert_equal(1, call_info.children.length)
75
-
76
- call_info = method.call_infos[1]
77
- assert_equal('AggregateTest#test_call_infos->AggClass#b->AggClass#a->AggClass#z', call_info.call_sequence)
78
- assert_equal(1, call_info.children.length)
79
-
80
- call_info = method.call_infos[2]
81
- assert_equal('AggregateTest#test_call_infos->AggClass#c->AggClass#a->AggClass#z', call_info.call_sequence)
82
- assert_equal(1, call_info.children.length)
83
- end
84
-
85
- def test_aggregates_parents
86
- c1 = AggClass.new
87
- result = RubyProf.profile do
88
- c1.a
89
- c1.b
90
- c1.c
91
- end
92
-
93
- methods = result.threads.first.methods.sort.reverse
94
- method = methods.find {|meth| meth.full_name == 'AggClass#z'}
95
-
96
- # Check AggClass#z
97
- assert_equal('AggClass#z', method.full_name)
98
-
99
- call_infos = method.aggregate_parents
100
- assert_equal(1, call_infos.length)
101
-
102
- call_info = call_infos.first
103
- assert_equal('AggClass#a', call_info.parent.target.full_name)
104
- assert_in_delta(3, call_info.total_time, 0.05)
105
- assert_in_delta(0, call_info.wait_time, 0.05)
106
- assert_in_delta(0, call_info.self_time, 0.05)
107
- assert_in_delta(3, call_info.children_time, 0.05)
108
- assert_equal(3, call_info.called)
109
- end
110
-
111
- def test_aggregates_children
112
- c1 = AggClass.new
113
- result = RubyProf.profile do
114
- c1.a
115
- c1.b
116
- c1.c
117
- end
118
-
119
- methods = result.threads.first.methods.sort.reverse
120
- method = methods.find {|meth| meth.full_name == 'AggClass#a'}
121
-
122
- # Check AggClass#a
123
- assert_equal('AggClass#a', method.full_name)
124
-
125
- call_infos = method.aggregate_children
126
- assert_equal(1, call_infos.length)
127
-
128
- call_info = call_infos.first
129
- assert_equal('AggClass#z', call_info.target.full_name)
130
- assert_in_delta(3, call_info.total_time, 0.05)
131
- assert_in_delta(0, call_info.wait_time, 0.05)
132
- assert_in_delta(0, call_info.self_time, 0.05)
133
- assert_in_delta(3, call_info.children_time, 0.05)
134
- assert_equal(3, call_info.called)
135
- end
136
- end
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- require File.expand_path("../test_helper", __FILE__)
5
-
6
- class BlockMethodTest < 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 test_block
13
- result = RubyProf.profile do
14
- 1.times { RubyProf::C1.new.hello }
15
- end
16
-
17
- # Methods called
18
- # Kernel#sleep
19
- # <Class::BasicObject>#allocate
20
- # #{RubyProf.parent_object}#inizialize
21
- # RubyProf::C1#hello
22
- # Class#new
23
- # Integer#times
24
- # BlockMethodTest#test_block
25
-
26
- methods = result.threads.first.methods.sort.reverse
27
- assert_equal(RubyProf.ruby_2? ? 6 : 7, methods.length)
28
-
29
- # Check times
30
- assert_equal("BlockMethodTest#test_block", methods[0].full_name)
31
- assert_in_delta(0.2, methods[0].total_time, 0.02)
32
- assert_in_delta(0.0, methods[0].wait_time, 0.02)
33
- assert_in_delta(0.0, methods[0].self_time, 0.02)
34
-
35
- assert_equal("Integer#times", methods[1].full_name)
36
- assert_in_delta(0.2, methods[1].total_time, 0.02)
37
- assert_in_delta(0.0, methods[1].wait_time, 0.02)
38
- assert_in_delta(0.0, methods[1].self_time, 0.02)
39
-
40
- assert_equal("RubyProf::C1#hello", methods[2].full_name)
41
- assert_in_delta(0.2, methods[2].total_time, 0.02)
42
- assert_in_delta(0.0, methods[2].wait_time, 0.02)
43
- assert_in_delta(0.0, methods[2].self_time, 0.02)
44
-
45
- assert_equal("Kernel#sleep", methods[3].full_name)
46
- assert_in_delta(0.2, methods[3].total_time, 0.01)
47
- assert_in_delta(0.0, methods[3].wait_time, 0.01)
48
- assert_in_delta(0.2, methods[3].self_time, 0.01)
49
-
50
- assert_equal("Class#new", methods[4].full_name)
51
- assert_in_delta(0.0, methods[4].total_time, 0.01)
52
- assert_in_delta(0.0, methods[4].wait_time, 0.01)
53
- assert_in_delta(0.0, methods[4].self_time, 0.01)
54
-
55
- # the timing difference between #initialize and #allocate is so small
56
- # that we cannot rely on #initialize appearing first.
57
- # so switch them, if necessary
58
- if methods[5].full_name =~ /#allocate/
59
- methods[5], methods[6] = methods[6], methods[5]
60
- end
61
-
62
- assert_equal("#{RubyProf.parent_object}#initialize", methods[5].full_name)
63
- assert_in_delta(0.0, methods[5].total_time, 0.01)
64
- assert_in_delta(0.0, methods[5].wait_time, 0.01)
65
- assert_in_delta(0.0, methods[5].self_time, 0.01)
66
-
67
- unless RubyProf.ruby_2?
68
- assert_equal("<Class::#{RubyProf.parent_object}>#allocate", methods[6].full_name)
69
- assert_in_delta(0.0, methods[6].total_time, 0.01)
70
- assert_in_delta(0.0, methods[6].wait_time, 0.01)
71
- assert_in_delta(0.0, methods[6].self_time, 0.01)
72
- end
73
- end
74
- end