ruby-prof 0.18.0 → 1.2.0
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.
- checksums.yaml +4 -4
- data/CHANGES +44 -1
- data/LICENSE +2 -2
- data/README.rdoc +1 -483
- data/Rakefile +3 -6
- data/bin/ruby-prof +111 -128
- data/ext/ruby_prof/extconf.rb +6 -38
- data/ext/ruby_prof/rp_aggregate_call_tree.c +41 -0
- data/ext/ruby_prof/rp_aggregate_call_tree.h +13 -0
- data/ext/ruby_prof/rp_allocation.c +259 -0
- data/ext/ruby_prof/rp_allocation.h +31 -0
- data/ext/ruby_prof/rp_call_tree.c +353 -0
- data/ext/ruby_prof/rp_call_tree.h +43 -0
- data/ext/ruby_prof/rp_call_trees.c +266 -0
- data/ext/ruby_prof/rp_call_trees.h +29 -0
- data/ext/ruby_prof/rp_measure_allocations.c +25 -51
- data/ext/ruby_prof/rp_measure_memory.c +21 -56
- data/ext/ruby_prof/rp_measure_process_time.c +37 -43
- data/ext/ruby_prof/rp_measure_wall_time.c +40 -21
- data/ext/ruby_prof/rp_measurement.c +221 -0
- data/ext/ruby_prof/rp_measurement.h +50 -0
- data/ext/ruby_prof/rp_method.c +279 -439
- data/ext/ruby_prof/rp_method.h +33 -45
- data/ext/ruby_prof/rp_profile.c +902 -0
- data/ext/ruby_prof/rp_profile.h +36 -0
- data/ext/ruby_prof/rp_stack.c +163 -132
- data/ext/ruby_prof/rp_stack.h +18 -28
- data/ext/ruby_prof/rp_thread.c +192 -124
- data/ext/ruby_prof/rp_thread.h +18 -8
- data/ext/ruby_prof/ruby_prof.c +36 -778
- data/ext/ruby_prof/ruby_prof.h +11 -45
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +18 -12
- data/lib/ruby-prof.rb +4 -21
- data/lib/ruby-prof/assets/call_stack_printer.html.erb +710 -0
- data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
- data/lib/ruby-prof/assets/graph_printer.html.erb +355 -0
- data/lib/ruby-prof/call_tree.rb +57 -0
- data/lib/ruby-prof/call_tree_visitor.rb +36 -0
- data/lib/ruby-prof/compatibility.rb +37 -107
- data/lib/ruby-prof/exclude_common_methods.rb +198 -0
- data/lib/ruby-prof/measurement.rb +17 -0
- data/lib/ruby-prof/method_info.rb +47 -90
- data/lib/ruby-prof/printers/abstract_printer.rb +73 -50
- data/lib/ruby-prof/printers/call_info_printer.rb +24 -12
- data/lib/ruby-prof/printers/call_stack_printer.rb +66 -152
- data/lib/ruby-prof/printers/call_tree_printer.rb +20 -12
- data/lib/ruby-prof/printers/dot_printer.rb +5 -5
- data/lib/ruby-prof/printers/flat_printer.rb +6 -24
- data/lib/ruby-prof/printers/graph_html_printer.rb +6 -192
- data/lib/ruby-prof/printers/graph_printer.rb +11 -14
- data/lib/ruby-prof/printers/multi_printer.rb +66 -23
- data/lib/ruby-prof/profile.rb +10 -3
- data/lib/ruby-prof/thread.rb +5 -20
- data/lib/ruby-prof/version.rb +1 -1
- data/ruby-prof.gemspec +9 -2
- data/test/abstract_printer_test.rb +0 -27
- data/test/alias_test.rb +126 -0
- data/test/basic_test.rb +1 -86
- data/test/call_tree_visitor_test.rb +32 -0
- data/test/call_trees_test.rb +66 -0
- data/test/dynamic_method_test.rb +0 -2
- data/test/exclude_methods_test.rb +17 -12
- data/test/fiber_test.rb +214 -23
- data/test/gc_test.rb +105 -0
- data/test/inverse_call_tree_test.rb +175 -0
- data/test/line_number_test.rb +118 -40
- data/test/marshal_test.rb +115 -0
- data/test/measure_allocations.rb +30 -0
- data/test/measure_allocations_test.rb +361 -12
- data/test/measure_allocations_trace_test.rb +375 -0
- data/test/measure_memory_trace_test.rb +1101 -0
- data/test/measure_process_time_test.rb +757 -33
- data/test/measure_times.rb +56 -0
- data/test/measure_wall_time_test.rb +329 -149
- data/test/multi_printer_test.rb +1 -34
- data/test/pause_resume_test.rb +24 -15
- data/test/prime.rb +1 -1
- data/test/prime_script.rb +6 -0
- data/test/printer_call_stack_test.rb +28 -0
- data/test/printer_call_tree_test.rb +31 -0
- data/test/printer_flat_test.rb +68 -0
- data/test/printer_graph_html_test.rb +60 -0
- data/test/printer_graph_test.rb +41 -0
- data/test/printers_test.rb +32 -166
- data/test/printing_recursive_graph_test.rb +26 -72
- data/test/recursive_test.rb +68 -77
- data/test/stack_printer_test.rb +2 -15
- data/test/start_stop_test.rb +22 -25
- data/test/test_helper.rb +6 -261
- data/test/thread_test.rb +11 -54
- data/test/unique_call_path_test.rb +25 -107
- data/test/yarv_test.rb +1 -0
- metadata +43 -41
- data/examples/flat.txt +0 -50
- data/examples/graph.dot +0 -84
- data/examples/graph.html +0 -823
- data/examples/graph.txt +0 -139
- data/examples/multi.flat.txt +0 -23
- data/examples/multi.graph.html +0 -760
- data/examples/multi.grind.dat +0 -114
- data/examples/multi.stack.html +0 -547
- data/examples/stack.html +0 -547
- data/ext/ruby_prof/rp_call_info.c +0 -425
- data/ext/ruby_prof/rp_call_info.h +0 -53
- data/ext/ruby_prof/rp_measure.c +0 -40
- data/ext/ruby_prof/rp_measure.h +0 -45
- data/ext/ruby_prof/rp_measure_cpu_time.c +0 -136
- data/ext/ruby_prof/rp_measure_gc_runs.c +0 -73
- data/ext/ruby_prof/rp_measure_gc_time.c +0 -60
- data/lib/ruby-prof/aggregate_call_info.rb +0 -76
- data/lib/ruby-prof/assets/call_stack_printer.css.html +0 -117
- data/lib/ruby-prof/assets/call_stack_printer.js.html +0 -385
- data/lib/ruby-prof/call_info.rb +0 -115
- data/lib/ruby-prof/call_info_visitor.rb +0 -40
- data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +0 -83
- data/lib/ruby-prof/profile/exclude_common_methods.rb +0 -207
- data/lib/ruby-prof/profile/legacy_method_elimination.rb +0 -50
- data/test/aggregate_test.rb +0 -136
- data/test/block_test.rb +0 -74
- data/test/call_info_test.rb +0 -78
- data/test/call_info_visitor_test.rb +0 -31
- data/test/issue137_test.rb +0 -63
- data/test/measure_cpu_time_test.rb +0 -212
- data/test/measure_gc_runs_test.rb +0 -32
- data/test/measure_gc_time_test.rb +0 -36
- data/test/measure_memory_test.rb +0 -33
- data/test/method_elimination_test.rb +0 -84
- data/test/module_test.rb +0 -45
- data/test/stack_test.rb +0 -138
data/Rakefile
CHANGED
@@ -40,7 +40,7 @@ Rake::ExtensionTask.new do |ext|
|
|
40
40
|
ext.ext_dir = "ext/#{SO_NAME}"
|
41
41
|
ext.lib_dir = "lib/#{RUBY_VERSION}"
|
42
42
|
ext.cross_compile = true
|
43
|
-
ext.cross_platform = ['x86-
|
43
|
+
ext.cross_platform = ['x86-mingw32', 'x64-mingw32']
|
44
44
|
end
|
45
45
|
|
46
46
|
# Rake task to build the default package
|
@@ -80,12 +80,9 @@ RDoc::Task.new("rdoc") do |rdoc|
|
|
80
80
|
rdoc.options << '--main' << 'README.rdoc'
|
81
81
|
rdoc.rdoc_files.include('bin/*',
|
82
82
|
'doc/*.rdoc',
|
83
|
-
'examples/flat.txt',
|
84
|
-
'examples/graph.txt',
|
85
|
-
'examples/graph.html',
|
86
83
|
'lib/**/*.rb',
|
87
|
-
'ext/ruby_prof
|
88
|
-
'ext/ruby_prof
|
84
|
+
'ext/ruby_prof/*.c',
|
85
|
+
'ext/ruby_prof/*.h',
|
89
86
|
'README.rdoc',
|
90
87
|
'LICENSE')
|
91
88
|
end
|
data/bin/ruby-prof
CHANGED
@@ -1,20 +1,6 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
2
|
|
3
|
-
# == Synopsis
|
4
|
-
#
|
5
|
-
# Profiles a Ruby program.
|
6
|
-
#
|
7
|
-
# == Usage
|
8
|
-
#
|
9
|
-
# ruby_prof [options] <script.rb> [--] [script-options]"
|
10
|
-
#
|
11
|
-
# Various options:
|
12
|
-
# run "$ ruby-prof --help" to see them
|
13
|
-
#
|
14
|
-
# See also the readme "reports" section for the various outputs
|
15
|
-
|
16
3
|
# First require ruby-prof
|
17
|
-
require 'rubygems'
|
18
4
|
require 'ruby-prof'
|
19
5
|
|
20
6
|
# Now setup option parser
|
@@ -22,8 +8,50 @@ require 'ostruct'
|
|
22
8
|
require 'optparse'
|
23
9
|
|
24
10
|
module RubyProf
|
11
|
+
# == Synopsis
|
12
|
+
#
|
13
|
+
# Profiles a Ruby program.
|
14
|
+
#
|
15
|
+
# == Usage
|
16
|
+
# ruby-prof [options] <script.rb> [--] [profiled-script-command-line-options]
|
17
|
+
#
|
18
|
+
# Options:
|
19
|
+
# -p, --printer=printer Select a printer:
|
20
|
+
# flat - Prints a flat profile as text (default).
|
21
|
+
# graph - Prints a graph profile as text.
|
22
|
+
# graph_html - Prints a graph profile as html.
|
23
|
+
# call_tree - format for KCacheGrind
|
24
|
+
# call_stack - prints a HTML visualization of the call tree
|
25
|
+
# dot - Prints a graph profile as a dot file
|
26
|
+
# multi - Creates several reports in output directory
|
27
|
+
# -m, --min_percent=min_percent The minimum percent a method must take before
|
28
|
+
# being included in output reports.
|
29
|
+
# This option is not supported for call tree.
|
30
|
+
# -f, --file=path Output results to a file instead of standard out.
|
31
|
+
# --mode=measure_mode Select what ruby-prof should measure:
|
32
|
+
# wall - Wall time (default).
|
33
|
+
# process - Process time.
|
34
|
+
# allocations - Object allocations (requires patched Ruby interpreter).
|
35
|
+
# memory - Allocated memory in KB (requires patched Ruby interpreter).
|
36
|
+
# -s, --sort=sort_mode Select how ruby-prof results should be sorted:
|
37
|
+
# total - Total time
|
38
|
+
# self - Self time
|
39
|
+
# wait - Wait time
|
40
|
+
# child - Child time
|
41
|
+
# --allow_exceptions Raise exceptions encountered during profiling (true) or suppress them (false)
|
42
|
+
# -R, --require-noprof=lib require a specific library (not profiled)
|
43
|
+
# -E, --eval-noprof=code execute the ruby statements (not profiled)
|
44
|
+
# --exclude=methods A comma separated list of methods to exclude.
|
45
|
+
# Specify instance methods via # (Integer#times)
|
46
|
+
# Specify class methods via . (Integer.superclass)
|
47
|
+
# --exclude-common Remove common methods from the profile
|
48
|
+
# -h, --help Show help message
|
49
|
+
# -v, --version version Show version (1.1.0)
|
50
|
+
|
25
51
|
class Cmd
|
52
|
+
# :enddoc:
|
26
53
|
attr_accessor :options
|
54
|
+
attr_reader :profile
|
27
55
|
|
28
56
|
def initialize
|
29
57
|
setup_options
|
@@ -36,15 +64,52 @@ module RubyProf
|
|
36
64
|
def setup_options
|
37
65
|
@options = OpenStruct.new
|
38
66
|
options.printer = RubyProf::FlatPrinter
|
67
|
+
options.measure_mode = RubyProf::WALL_TIME
|
39
68
|
options.min_percent = 0
|
40
69
|
options.file = nil
|
41
|
-
options.
|
42
|
-
options.
|
43
|
-
|
70
|
+
options.allow_exceptions = false
|
71
|
+
options.exclude_common = false
|
72
|
+
options.exclude = Array.new
|
44
73
|
options.pre_libs = Array.new
|
45
74
|
options.pre_execs = Array.new
|
46
75
|
end
|
47
76
|
|
77
|
+
# This is copied from ActiveSupport:
|
78
|
+
def constantize(camel_cased_word)
|
79
|
+
if !camel_cased_word.include?("::")
|
80
|
+
Object.const_get(camel_cased_word)
|
81
|
+
else
|
82
|
+
names = camel_cased_word.split("::")
|
83
|
+
|
84
|
+
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
85
|
+
Object.const_get(camel_cased_word) if names.empty?
|
86
|
+
|
87
|
+
# Remove the first blank element in case of '::ClassName' notation.
|
88
|
+
names.shift if names.size > 1 && names.first.empty?
|
89
|
+
|
90
|
+
names.inject(Object) do |constant, name|
|
91
|
+
if constant == Object
|
92
|
+
constant.const_get(name)
|
93
|
+
else
|
94
|
+
candidate = constant.const_get(name)
|
95
|
+
next candidate if constant.const_defined?(name, false)
|
96
|
+
next candidate unless Object.const_defined?(name)
|
97
|
+
|
98
|
+
# Go down the ancestors to check if it is owned directly. The check
|
99
|
+
# stops when we reach Object or the end of ancestors tree.
|
100
|
+
constant = constant.ancestors.inject(constant) do |const, ancestor|
|
101
|
+
break const if ancestor == Object
|
102
|
+
break ancestor if ancestor.const_defined?(name, false)
|
103
|
+
const
|
104
|
+
end
|
105
|
+
|
106
|
+
# owner is in Object, so raise
|
107
|
+
constant.const_get(name, false)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
48
113
|
def option_parser
|
49
114
|
OptionParser.new do |opts|
|
50
115
|
opts.banner = "ruby_prof #{RubyProf::VERSION}\n" +
|
@@ -56,7 +121,6 @@ module RubyProf
|
|
56
121
|
opts.on('-p printer', '--printer=printer', [:flat, :flat_with_line_numbers, :graph, :graph_html, :call_tree, :call_stack, :dot, :multi],
|
57
122
|
'Select a printer:',
|
58
123
|
' flat - Prints a flat profile as text (default).',
|
59
|
-
' flat_with_line_numbers - same as flat, with line numbers.',
|
60
124
|
' graph - Prints a graph profile as text.',
|
61
125
|
' graph_html - Prints a graph profile as html.',
|
62
126
|
' call_tree - format for KCacheGrind',
|
@@ -65,12 +129,9 @@ module RubyProf
|
|
65
129
|
' multi - Creates several reports in output directory'
|
66
130
|
) do |printer|
|
67
131
|
|
68
|
-
|
69
132
|
case printer
|
70
133
|
when :flat
|
71
134
|
options.printer = RubyProf::FlatPrinter
|
72
|
-
when :flat_with_line_numbers
|
73
|
-
options.printer = RubyProf::FlatPrinterWithLineNumbers
|
74
135
|
when :graph
|
75
136
|
options.printer = RubyProf::GraphPrinter
|
76
137
|
when :graph_html
|
@@ -89,7 +150,7 @@ module RubyProf
|
|
89
150
|
opts.on('-m min_percent', '--min_percent=min_percent', Float,
|
90
151
|
'The minimum percent a method must take before ',
|
91
152
|
' being included in output reports.',
|
92
|
-
'
|
153
|
+
' This option is not supported for call tree.') do |min_percent|
|
93
154
|
options.min_percent = min_percent
|
94
155
|
end
|
95
156
|
|
@@ -100,31 +161,22 @@ module RubyProf
|
|
100
161
|
end
|
101
162
|
|
102
163
|
opts.on('--mode=measure_mode',
|
103
|
-
[:process, :wall, :
|
164
|
+
[:process, :wall, :allocations, :memory],
|
104
165
|
'Select what ruby-prof should measure:',
|
105
166
|
' wall - Wall time (default).',
|
106
167
|
' process - Process time.',
|
107
|
-
' cpu - CPU time (Pentium and PowerPCs only).',
|
108
168
|
' allocations - Object allocations (requires patched Ruby interpreter).',
|
109
|
-
' memory - Allocated memory in KB (requires patched Ruby interpreter).'
|
110
|
-
' gc_runs - Number of garbage collections (requires patched Ruby interpreter).',
|
111
|
-
' gc_time - Time spent in garbage collection (requires patched Ruby interpreter).') do |measure_mode|
|
169
|
+
' memory - Allocated memory in KB (requires patched Ruby interpreter).') do |measure_mode|
|
112
170
|
|
113
171
|
case measure_mode
|
114
172
|
when :wall
|
115
173
|
options.measure_mode = RubyProf::WALL_TIME
|
116
174
|
when :process
|
117
175
|
options.measure_mode = RubyProf::PROCESS_TIME
|
118
|
-
when :cpu
|
119
|
-
options.measure_mode = RubyProf::CPU_TIME
|
120
176
|
when :allocations
|
121
177
|
options.measure_mode = RubyProf::ALLOCATIONS
|
122
178
|
when :memory
|
123
179
|
options.measure_mode = RubyProf::MEMORY
|
124
|
-
when :gc_runs
|
125
|
-
options.measure_mode = RubyProf::GC_RUNS
|
126
|
-
when :gc_time
|
127
|
-
options.measure_mode = RubyProf::GC_TIME
|
128
180
|
end
|
129
181
|
end
|
130
182
|
|
@@ -147,94 +199,45 @@ module RubyProf
|
|
147
199
|
end
|
148
200
|
end
|
149
201
|
|
150
|
-
opts.on("--replace-progname", "Replace $0 when loading the .rb files.") do
|
151
|
-
options.replace_prog_name = true
|
152
|
-
end
|
153
|
-
|
154
|
-
if defined?(RubyVM)
|
155
|
-
opts.on("--specialized-instruction", "Turn on specified instruction.") do
|
156
|
-
options.specialized_instruction = true
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
202
|
opts.on_tail("-h", "--help", "Show help message") do
|
161
203
|
puts opts
|
162
204
|
exit
|
163
205
|
end
|
164
206
|
|
165
|
-
opts.on_tail("--version", "Show version #{RubyProf::VERSION}") do
|
207
|
+
opts.on_tail("-v version", "--version", "Show version (#{RubyProf::VERSION})") do
|
166
208
|
puts "ruby_prof " + RubyProf::VERSION
|
167
209
|
exit
|
168
210
|
end
|
169
211
|
|
170
|
-
opts.on(
|
171
|
-
|
172
|
-
$VERBOSE = true
|
173
|
-
end
|
174
|
-
|
175
|
-
opts.on("-d", "Set $DEBUG to true") do
|
176
|
-
$DEBUG = true
|
212
|
+
opts.on('--allow_exceptions', 'Raise exceptions encountered during profiling (true) or suppress them (false)') do
|
213
|
+
options.allow_exceptions = true
|
177
214
|
end
|
178
215
|
|
179
|
-
opts.on('-R lib', '--require-noprof
|
216
|
+
opts.on('-R lib', '--require-noprof=lib', 'require a specific library (not profiled)') do |lib|
|
180
217
|
options.pre_libs << lib
|
181
218
|
end
|
182
219
|
|
183
|
-
opts.on('-E code', '--eval-noprof
|
220
|
+
opts.on('-E code', '--eval-noprof=code', 'execute the ruby statements (not profiled)') do |code|
|
184
221
|
options.pre_execs << code
|
185
222
|
end
|
186
223
|
|
187
|
-
opts.on('
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
Integer#times
|
201
|
-
Integer#upto
|
202
|
-
Integer#downto
|
203
|
-
Enumerator#each
|
204
|
-
Enumerator#each_with_index
|
205
|
-
Enumerator#each_with_object
|
206
|
-
|
207
|
-
Array#each
|
208
|
-
Array#each_index
|
209
|
-
Array#reverse_each
|
210
|
-
Array#map
|
211
|
-
|
212
|
-
Hash#each
|
213
|
-
Hash#each_pair
|
214
|
-
Hash#each_key
|
215
|
-
Hash#each_value
|
216
|
-
|
217
|
-
Range#each
|
218
|
-
Enumerable#each_cons
|
219
|
-
Enumerable#each_entry
|
220
|
-
Enumerable#each_slice
|
221
|
-
Enumerable#each_with_index
|
222
|
-
Enumerable#each_with_object
|
223
|
-
Enumerable#reverse_each
|
224
|
-
Enumerable#inject
|
225
|
-
Enumerable#collect
|
226
|
-
Enumerable#reduce
|
227
|
-
}
|
228
|
-
#TODO: may be the whole Enumerable module should be excluded via 'Enumerable#.*', we need feedback on use cases.
|
224
|
+
opts.on('--exclude=methods', String,
|
225
|
+
'A comma separated list of methods to exclude.',
|
226
|
+
' Specify instance methods via # (Integer#times)',
|
227
|
+
' Specify class methods via . (Integer.superclass)') do |exclude_string|
|
228
|
+
exclude_string.split(',').each do |string|
|
229
|
+
match = string.strip.match(/(.*)(#|\.)(.*)/)
|
230
|
+
klass = constantize(match[1])
|
231
|
+
if match[2] == '.'
|
232
|
+
klass = klass.singleton_class
|
233
|
+
end
|
234
|
+
method = match[3].to_sym
|
235
|
+
options.exclude << [klass, method]
|
236
|
+
end
|
229
237
|
end
|
230
238
|
|
231
|
-
opts.on('--exclude-common
|
232
|
-
options.
|
233
|
-
options.eliminate_methods += %w{
|
234
|
-
Method#call
|
235
|
-
Proc#call
|
236
|
-
ActiveSupport::Callbacks::ClassMethods#__run_callback
|
237
|
-
}
|
239
|
+
opts.on('--exclude-common', 'Remove common methods from the profile') do
|
240
|
+
options.exclude_common = true
|
238
241
|
end
|
239
242
|
end
|
240
243
|
end
|
@@ -278,23 +281,15 @@ module RubyProf
|
|
278
281
|
end
|
279
282
|
|
280
283
|
def run
|
281
|
-
# Get the script we will execute
|
282
284
|
script = ARGV.shift
|
283
|
-
|
284
|
-
|
285
|
+
@profile = Profile.new(options.to_h)
|
286
|
+
options.exclude.each do |klass, method|
|
287
|
+
@profile.exclude_method!(klass, method)
|
285
288
|
end
|
286
289
|
|
287
|
-
|
288
|
-
|
289
|
-
RubyVM::InstructionSequence.compile_option = {
|
290
|
-
:trace_instruction => true,
|
291
|
-
:specialized_instruction => options.specialized_instruction
|
292
|
-
}
|
290
|
+
profile.profile do
|
291
|
+
load script
|
293
292
|
end
|
294
|
-
|
295
|
-
# Set the measure mode
|
296
|
-
RubyProf.measure_mode = options.measure_mode if options.measure_mode
|
297
|
-
RubyProf.start_script(script)
|
298
293
|
end
|
299
294
|
end
|
300
295
|
end
|
@@ -307,20 +302,8 @@ cmd = RubyProf::Cmd.new
|
|
307
302
|
# *after* any other one that will be installed.
|
308
303
|
|
309
304
|
at_exit {
|
310
|
-
# Stop profiling
|
311
|
-
result = RubyProf.stop
|
312
|
-
|
313
|
-
# Eliminate unwanted methods from call graph
|
314
|
-
if cmd.options.eliminate_methods
|
315
|
-
result.eliminate_methods!(cmd.options.eliminate_methods)
|
316
|
-
end
|
317
|
-
|
318
|
-
if cmd.options.eliminate_methods_files
|
319
|
-
cmd.options.eliminate_methods_files.each {|f| result.eliminate_methods!(f)}
|
320
|
-
end
|
321
|
-
|
322
305
|
# Create a printer
|
323
|
-
printer = cmd.options.printer.new(
|
306
|
+
printer = cmd.options.printer.new(cmd.profile)
|
324
307
|
printer_options = {:min_percent => cmd.options.min_percent, :sort_method => cmd.options.sort_method}
|
325
308
|
|
326
309
|
# Get output
|
data/ext/ruby_prof/extconf.rb
CHANGED
@@ -5,34 +5,16 @@ if RUBY_ENGINE != "ruby"
|
|
5
5
|
exit(1)
|
6
6
|
end
|
7
7
|
|
8
|
-
if RUBY_VERSION <
|
9
|
-
STDERR.puts("\n\n***** Ruby version #{RUBY_VERSION} is no longer supported. Please upgrade to
|
8
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4.0')
|
9
|
+
STDERR.puts("\n\n***** Ruby version #{RUBY_VERSION} is no longer supported. Please upgrade to 2.3 or higher. *****\n\n")
|
10
10
|
exit(1)
|
11
11
|
end
|
12
12
|
|
13
13
|
# For the love of bitfields...
|
14
14
|
$CFLAGS += ' -std=c99'
|
15
15
|
|
16
|
-
#
|
17
|
-
|
18
|
-
have_func("rb_gc_count")
|
19
|
-
have_func("rb_remove_event_hook_with_data")
|
20
|
-
|
21
|
-
# Alexander Dymo GC patch
|
22
|
-
have_func("rb_os_allocated_objects")
|
23
|
-
have_func("rb_gc_allocated_size")
|
24
|
-
|
25
|
-
# Stefan Kaes GC patches
|
26
|
-
have_func("rb_gc_collections")
|
27
|
-
have_func("rb_gc_time")
|
28
|
-
# for ruby 2.1
|
29
|
-
have_func("rb_gc_total_time")
|
30
|
-
have_func("rb_gc_total_mallocs")
|
31
|
-
have_func("rb_gc_total_malloced_bytes")
|
32
|
-
|
33
|
-
# Lloyd Hilaiel's heap info patch
|
34
|
-
have_func("rb_heap_total_mem")
|
35
|
-
have_func("rb_gc_heap_info")
|
16
|
+
# And since we are using C99
|
17
|
+
CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
|
36
18
|
|
37
19
|
def add_define(name, value = nil)
|
38
20
|
if value
|
@@ -46,23 +28,9 @@ def windows?
|
|
46
28
|
RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
|
47
29
|
end
|
48
30
|
|
49
|
-
if !windows? && RUBY_PLATFORM !~ /(darwin|openbsd)/
|
50
|
-
$LDFLAGS += " -lrt" # for clock_gettime
|
51
|
-
end
|
52
31
|
add_define("RUBY_PROF_RUBY_VERSION", RUBY_VERSION.split('.')[0..2].inject(0){|v,d| v*100+d.to_i})
|
53
32
|
|
54
|
-
#
|
55
|
-
|
56
|
-
require 'set'
|
57
|
-
threads = Set.new
|
58
|
-
set_trace_func lambda { |*args| threads << Thread.current.object_id }
|
59
|
-
Thread.new{1}.join
|
60
|
-
set_trace_func nil
|
61
|
-
if threads.size < 2
|
62
|
-
# if we end up here, ruby does not automatically activate tracing in spawned threads
|
63
|
-
STDERR.puts("Ruby #{RUBY_VERSION} does not activate tracing in spawned threads. Consider upgrading.")
|
64
|
-
exit(1)
|
65
|
-
end
|
66
|
-
end
|
33
|
+
# This function was added in Ruby 2.5, so once Ruby 2.4 is no longer supported this can be removed
|
34
|
+
have_func('rb_tracearg_callee_id', ["ruby.h"])
|
67
35
|
|
68
36
|
create_makefile("ruby_prof")
|
@@ -0,0 +1,41 @@
|
|
1
|
+
/* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
|
2
|
+
Please see the LICENSE file for copyright and distribution information */
|
3
|
+
|
4
|
+
#include "rp_aggregate_call_tree.h"
|
5
|
+
|
6
|
+
VALUE cRpAggregateCallTree;
|
7
|
+
|
8
|
+
void prof_aggregate_call_tree_mark(void* data)
|
9
|
+
{
|
10
|
+
prof_call_tree_t* call_tree = (prof_call_tree_t*)data;
|
11
|
+
|
12
|
+
if (call_tree->object != Qnil)
|
13
|
+
rb_gc_mark(call_tree->object);
|
14
|
+
|
15
|
+
if (call_tree->source_file != Qnil)
|
16
|
+
rb_gc_mark(call_tree->source_file);
|
17
|
+
|
18
|
+
prof_measurement_mark(call_tree->measurement);
|
19
|
+
}
|
20
|
+
|
21
|
+
static void prof_aggregate_call_tree_ruby_gc_free(void* data)
|
22
|
+
{
|
23
|
+
prof_call_tree_t* call_tree = (prof_call_tree_t*)data;
|
24
|
+
prof_call_tree_free(call_tree);
|
25
|
+
}
|
26
|
+
|
27
|
+
VALUE prof_aggregate_call_tree_wrap(prof_call_tree_t* call_tree)
|
28
|
+
{
|
29
|
+
if (call_tree->object == Qnil)
|
30
|
+
{
|
31
|
+
call_tree->object = Data_Wrap_Struct(cRpAggregateCallTree, prof_aggregate_call_tree_mark, prof_aggregate_call_tree_ruby_gc_free, call_tree);
|
32
|
+
}
|
33
|
+
return call_tree->object;
|
34
|
+
}
|
35
|
+
|
36
|
+
void rp_init_aggregate_call_tree()
|
37
|
+
{
|
38
|
+
// AggregateCallTree
|
39
|
+
cRpAggregateCallTree = rb_define_class_under(mProf, "AggregateCallTree", cRpCallTree);
|
40
|
+
rb_undef_method(CLASS_OF(cRpAggregateCallTree), "new");
|
41
|
+
}
|