ruby-prof 0.18.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +44 -1
  3. data/LICENSE +2 -2
  4. data/README.rdoc +1 -483
  5. data/Rakefile +3 -6
  6. data/bin/ruby-prof +111 -128
  7. data/ext/ruby_prof/extconf.rb +6 -38
  8. data/ext/ruby_prof/rp_aggregate_call_tree.c +41 -0
  9. data/ext/ruby_prof/rp_aggregate_call_tree.h +13 -0
  10. data/ext/ruby_prof/rp_allocation.c +259 -0
  11. data/ext/ruby_prof/rp_allocation.h +31 -0
  12. data/ext/ruby_prof/rp_call_tree.c +353 -0
  13. data/ext/ruby_prof/rp_call_tree.h +43 -0
  14. data/ext/ruby_prof/rp_call_trees.c +266 -0
  15. data/ext/ruby_prof/rp_call_trees.h +29 -0
  16. data/ext/ruby_prof/rp_measure_allocations.c +25 -51
  17. data/ext/ruby_prof/rp_measure_memory.c +21 -56
  18. data/ext/ruby_prof/rp_measure_process_time.c +37 -43
  19. data/ext/ruby_prof/rp_measure_wall_time.c +40 -21
  20. data/ext/ruby_prof/rp_measurement.c +221 -0
  21. data/ext/ruby_prof/rp_measurement.h +50 -0
  22. data/ext/ruby_prof/rp_method.c +279 -439
  23. data/ext/ruby_prof/rp_method.h +33 -45
  24. data/ext/ruby_prof/rp_profile.c +902 -0
  25. data/ext/ruby_prof/rp_profile.h +36 -0
  26. data/ext/ruby_prof/rp_stack.c +163 -132
  27. data/ext/ruby_prof/rp_stack.h +18 -28
  28. data/ext/ruby_prof/rp_thread.c +192 -124
  29. data/ext/ruby_prof/rp_thread.h +18 -8
  30. data/ext/ruby_prof/ruby_prof.c +36 -778
  31. data/ext/ruby_prof/ruby_prof.h +11 -45
  32. data/ext/ruby_prof/vc/ruby_prof.vcxproj +18 -12
  33. data/lib/ruby-prof.rb +4 -21
  34. data/lib/ruby-prof/assets/call_stack_printer.html.erb +710 -0
  35. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  36. data/lib/ruby-prof/assets/graph_printer.html.erb +355 -0
  37. data/lib/ruby-prof/call_tree.rb +57 -0
  38. data/lib/ruby-prof/call_tree_visitor.rb +36 -0
  39. data/lib/ruby-prof/compatibility.rb +37 -107
  40. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  41. data/lib/ruby-prof/measurement.rb +17 -0
  42. data/lib/ruby-prof/method_info.rb +47 -90
  43. data/lib/ruby-prof/printers/abstract_printer.rb +73 -50
  44. data/lib/ruby-prof/printers/call_info_printer.rb +24 -12
  45. data/lib/ruby-prof/printers/call_stack_printer.rb +66 -152
  46. data/lib/ruby-prof/printers/call_tree_printer.rb +20 -12
  47. data/lib/ruby-prof/printers/dot_printer.rb +5 -5
  48. data/lib/ruby-prof/printers/flat_printer.rb +6 -24
  49. data/lib/ruby-prof/printers/graph_html_printer.rb +6 -192
  50. data/lib/ruby-prof/printers/graph_printer.rb +11 -14
  51. data/lib/ruby-prof/printers/multi_printer.rb +66 -23
  52. data/lib/ruby-prof/profile.rb +10 -3
  53. data/lib/ruby-prof/thread.rb +5 -20
  54. data/lib/ruby-prof/version.rb +1 -1
  55. data/ruby-prof.gemspec +9 -2
  56. data/test/abstract_printer_test.rb +0 -27
  57. data/test/alias_test.rb +126 -0
  58. data/test/basic_test.rb +1 -86
  59. data/test/call_tree_visitor_test.rb +32 -0
  60. data/test/call_trees_test.rb +66 -0
  61. data/test/dynamic_method_test.rb +0 -2
  62. data/test/exclude_methods_test.rb +17 -12
  63. data/test/fiber_test.rb +214 -23
  64. data/test/gc_test.rb +105 -0
  65. data/test/inverse_call_tree_test.rb +175 -0
  66. data/test/line_number_test.rb +118 -40
  67. data/test/marshal_test.rb +115 -0
  68. data/test/measure_allocations.rb +30 -0
  69. data/test/measure_allocations_test.rb +361 -12
  70. data/test/measure_allocations_trace_test.rb +375 -0
  71. data/test/measure_memory_trace_test.rb +1101 -0
  72. data/test/measure_process_time_test.rb +757 -33
  73. data/test/measure_times.rb +56 -0
  74. data/test/measure_wall_time_test.rb +329 -149
  75. data/test/multi_printer_test.rb +1 -34
  76. data/test/pause_resume_test.rb +24 -15
  77. data/test/prime.rb +1 -1
  78. data/test/prime_script.rb +6 -0
  79. data/test/printer_call_stack_test.rb +28 -0
  80. data/test/printer_call_tree_test.rb +31 -0
  81. data/test/printer_flat_test.rb +68 -0
  82. data/test/printer_graph_html_test.rb +60 -0
  83. data/test/printer_graph_test.rb +41 -0
  84. data/test/printers_test.rb +32 -166
  85. data/test/printing_recursive_graph_test.rb +26 -72
  86. data/test/recursive_test.rb +68 -77
  87. data/test/stack_printer_test.rb +2 -15
  88. data/test/start_stop_test.rb +22 -25
  89. data/test/test_helper.rb +6 -261
  90. data/test/thread_test.rb +11 -54
  91. data/test/unique_call_path_test.rb +25 -107
  92. data/test/yarv_test.rb +1 -0
  93. metadata +43 -41
  94. data/examples/flat.txt +0 -50
  95. data/examples/graph.dot +0 -84
  96. data/examples/graph.html +0 -823
  97. data/examples/graph.txt +0 -139
  98. data/examples/multi.flat.txt +0 -23
  99. data/examples/multi.graph.html +0 -760
  100. data/examples/multi.grind.dat +0 -114
  101. data/examples/multi.stack.html +0 -547
  102. data/examples/stack.html +0 -547
  103. data/ext/ruby_prof/rp_call_info.c +0 -425
  104. data/ext/ruby_prof/rp_call_info.h +0 -53
  105. data/ext/ruby_prof/rp_measure.c +0 -40
  106. data/ext/ruby_prof/rp_measure.h +0 -45
  107. data/ext/ruby_prof/rp_measure_cpu_time.c +0 -136
  108. data/ext/ruby_prof/rp_measure_gc_runs.c +0 -73
  109. data/ext/ruby_prof/rp_measure_gc_time.c +0 -60
  110. data/lib/ruby-prof/aggregate_call_info.rb +0 -76
  111. data/lib/ruby-prof/assets/call_stack_printer.css.html +0 -117
  112. data/lib/ruby-prof/assets/call_stack_printer.js.html +0 -385
  113. data/lib/ruby-prof/call_info.rb +0 -115
  114. data/lib/ruby-prof/call_info_visitor.rb +0 -40
  115. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +0 -83
  116. data/lib/ruby-prof/profile/exclude_common_methods.rb +0 -207
  117. data/lib/ruby-prof/profile/legacy_method_elimination.rb +0 -50
  118. data/test/aggregate_test.rb +0 -136
  119. data/test/block_test.rb +0 -74
  120. data/test/call_info_test.rb +0 -78
  121. data/test/call_info_visitor_test.rb +0 -31
  122. data/test/issue137_test.rb +0 -63
  123. data/test/measure_cpu_time_test.rb +0 -212
  124. data/test/measure_gc_runs_test.rb +0 -32
  125. data/test/measure_gc_time_test.rb +0 -36
  126. data/test/measure_memory_test.rb +0 -33
  127. data/test/method_elimination_test.rb +0 -84
  128. data/test/module_test.rb +0 -45
  129. data/test/stack_test.rb +0 -138
@@ -1,40 +0,0 @@
1
- # The call info visitor class does a depth-first traversal across a
2
- # list of method infos. At each call_info node, the visitor executes
3
- # the block provided in the #visit method. The block is passed two
4
- # parameters, the event and the call_info instance. Event will be
5
- # either :enter or :exit.
6
- #
7
- # visitor = RubyProf::CallInfoVisitor.new(result.threads.first.top_call_infos)
8
- #
9
- # method_names = Array.new
10
- #
11
- # visitor.visit do |call_info, event|
12
- # method_names << call_info.target.full_name if event == :enter
13
- # end
14
- #
15
- # puts method_names
16
-
17
- module RubyProf
18
- class CallInfoVisitor
19
-
20
- def initialize(call_infos)
21
- @call_infos = CallInfo.roots_of(call_infos)
22
- end
23
-
24
- def visit(&block)
25
- @call_infos.each do |call_info|
26
- visit_call_info(call_info, &block)
27
- end
28
- end
29
-
30
- private
31
- def visit_call_info(call_info, &block)
32
- yield call_info, :enter
33
- call_info.children.each do |child|
34
- visit_call_info(child, &block)
35
- end
36
- yield call_info, :exit
37
- end
38
- end
39
-
40
- end
@@ -1,83 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module RubyProf
4
- # Generates flat[link:files/examples/flat_txt.html] profile reports as text.
5
- # To use the flat printer with line numbers:
6
- #
7
- # result = RubyProf.profile do
8
- # [code to profile]
9
- # end
10
- #
11
- # printer = RubyProf::FlatPrinterWithLineNumbers.new(result)
12
- # printer.print(STDOUT, {})
13
- #
14
- class FlatPrinterWithLineNumbers < FlatPrinter
15
- def print_methods(thread)
16
- @editor = editor_uri
17
- total_time = thread.total_time
18
-
19
- methods = thread.methods.sort_by(&sort_method).reverse
20
- sum = 0
21
- methods.each do |method|
22
- self_percent = (method.self_time / total_time) * 100
23
- next if self_percent < min_percent
24
-
25
- sum += method.self_time
26
- #self_time_called = method.called > 0 ? method.self_time/method.called : 0
27
- #total_time_called = method.called > 0? method.total_time/method.called : 0
28
-
29
- @output << "%6.2f %9.3f %9.3f %9.3f %9.3f %8d %s%s" % [
30
- method.self_time / total_time * 100, # %self
31
- method.total_time, # total
32
- method.self_time, # self
33
- method.wait_time, # wait
34
- method.children_time, # children
35
- method.called, # calls
36
- method.recursive? ? "*" : " ", # cycle
37
- method_name(method) # name
38
- ]
39
- if method.source_file == 'ruby_runtime'
40
- @output << "\n"
41
- else
42
- @output << "\n defined at:\n"
43
- @output << defined_at_format % [File.expand_path(method.source_file), method.line]
44
- end
45
-
46
- callers = []
47
- method.call_infos.each do |ci|
48
- if ci.parent && ci.parent.target.source_file != 'ruby_runtime'
49
- callers << [method_name(ci.parent.target), File.expand_path(ci.parent.target.source_file), ci.parent.target.line]
50
- end
51
- end
52
- # make sure callers are unique
53
- callers.uniq!
54
-
55
- unless callers.empty?
56
- @output << " called from:\n"
57
- callers.each do |args|
58
- @output << called_from_format % args
59
- end
60
- end
61
- @output << "\n"
62
- end
63
- end
64
-
65
- private
66
-
67
- def defined_at_format
68
- if @editor
69
- " #{@editor}://open?url=file://%s&line=%s\n"
70
- else
71
- " %s:%s\n"
72
- end
73
- end
74
-
75
- def called_from_format
76
- if @editor
77
- " %s (#{@editor}://open?url=file://%s&line=%s)\n"
78
- else
79
- " %s (%s:%s)\n"
80
- end
81
- end
82
- end
83
- end
@@ -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