ruby-prof 1.1.0-x64-mingw32 → 1.3.0-x64-mingw32
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 +19 -1
- data/bin/ruby-prof +100 -152
- data/ext/ruby_prof/rp_aggregate_call_tree.c +59 -0
- data/ext/ruby_prof/rp_aggregate_call_tree.h +13 -0
- data/ext/ruby_prof/rp_allocation.c +67 -59
- data/ext/ruby_prof/rp_allocation.h +3 -3
- data/ext/ruby_prof/rp_call_tree.c +369 -0
- data/ext/ruby_prof/rp_call_tree.h +43 -0
- data/ext/ruby_prof/rp_call_trees.c +288 -0
- data/ext/ruby_prof/rp_call_trees.h +28 -0
- data/ext/ruby_prof/rp_measure_allocations.c +11 -13
- data/ext/ruby_prof/rp_measure_process_time.c +11 -13
- data/ext/ruby_prof/rp_measure_wall_time.c +17 -15
- data/ext/ruby_prof/rp_measurement.c +47 -40
- data/ext/ruby_prof/rp_measurement.h +7 -7
- data/ext/ruby_prof/rp_method.c +116 -255
- data/ext/ruby_prof/rp_method.h +31 -39
- data/ext/ruby_prof/rp_profile.c +311 -281
- data/ext/ruby_prof/rp_profile.h +1 -2
- data/ext/ruby_prof/rp_stack.c +113 -105
- data/ext/ruby_prof/rp_stack.h +17 -20
- data/ext/ruby_prof/rp_thread.c +136 -111
- data/ext/ruby_prof/rp_thread.h +12 -9
- data/ext/ruby_prof/ruby_prof.c +27 -23
- data/ext/ruby_prof/ruby_prof.h +9 -0
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +11 -7
- data/lib/ruby-prof.rb +2 -3
- data/lib/ruby-prof/assets/call_stack_printer.html.erb +4 -7
- data/lib/ruby-prof/assets/graph_printer.html.erb +5 -6
- data/lib/ruby-prof/{call_info.rb → call_tree.rb} +6 -6
- data/lib/ruby-prof/call_tree_visitor.rb +36 -0
- data/lib/ruby-prof/measurement.rb +5 -2
- data/lib/ruby-prof/method_info.rb +3 -15
- data/lib/ruby-prof/printers/call_info_printer.rb +12 -10
- data/lib/ruby-prof/printers/call_stack_printer.rb +19 -22
- data/lib/ruby-prof/printers/call_tree_printer.rb +1 -1
- data/lib/ruby-prof/printers/dot_printer.rb +3 -3
- data/lib/ruby-prof/printers/graph_printer.rb +3 -4
- data/lib/ruby-prof/printers/multi_printer.rb +2 -2
- data/lib/ruby-prof/rack.rb +3 -0
- data/lib/ruby-prof/thread.rb +3 -18
- data/lib/ruby-prof/version.rb +1 -1
- data/ruby-prof.gemspec +7 -0
- data/test/alias_test.rb +42 -45
- data/test/basic_test.rb +0 -86
- data/test/{call_info_visitor_test.rb → call_tree_visitor_test.rb} +6 -5
- data/test/call_trees_test.rb +66 -0
- data/test/exclude_methods_test.rb +17 -12
- data/test/fiber_test.rb +197 -9
- data/test/gc_test.rb +36 -42
- data/test/inverse_call_tree_test.rb +175 -0
- data/test/line_number_test.rb +67 -70
- data/test/marshal_test.rb +7 -11
- data/test/measure_allocations_test.rb +224 -234
- data/test/measure_allocations_trace_test.rb +224 -234
- data/test/measure_memory_trace_test.rb +814 -469
- data/test/measure_process_time_test.rb +0 -64
- data/test/measure_times.rb +2 -0
- data/test/measure_wall_time_test.rb +34 -58
- data/test/pause_resume_test.rb +19 -10
- data/test/prime.rb +1 -3
- data/test/prime_script.rb +6 -0
- data/test/printers_test.rb +1 -1
- data/test/recursive_test.rb +50 -54
- data/test/start_stop_test.rb +19 -19
- data/test/test_helper.rb +3 -15
- data/test/thread_test.rb +11 -11
- data/test/unique_call_path_test.rb +25 -95
- metadata +19 -10
- data/ext/ruby_prof/rp_call_info.c +0 -271
- data/ext/ruby_prof/rp_call_info.h +0 -35
- data/lib/2.6.5/ruby_prof.so +0 -0
- data/lib/ruby-prof/call_info_visitor.rb +0 -38
- data/test/parser_timings.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e7a5ed3eff6d7d963f459a572dd63561423abb6d8911076e086e3588befb37b
|
4
|
+
data.tar.gz: b4bf7cc5ec23482ccbcb103b6c7ab87c8614da0076d6a43f4848d6cd8aee3178
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4797da262fc687b47bea5c33bdcfdd102197afb8a3ff441b00a5444bc06de4deb83421569b6e8f815381a385e79edc08c4339b2d3ab26f9f7c920a155c00f080
|
7
|
+
data.tar.gz: bc891673567736bef06b12eb72514425261a678ad9d33ad709835e1e1cffd265c4657ba436a2e28486a45fa35fd678117ac2a2882c564fbfb334eb1edcec3918
|
data/CHANGES
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
1.3.0 (2020-02-22)
|
2
|
+
=====================
|
3
|
+
* Update C code to use newer RTypedData API versus older RData API.
|
4
|
+
* Update C code to use rb_cObject versus the older, deprecated, rb_cData.
|
5
|
+
* Update memory management - CallInfo's now keep alive their owning Profile instances. Fixes crashes that
|
6
|
+
could happen in rare instances.
|
7
|
+
|
8
|
+
1.2.0 (2020-01-23)
|
9
|
+
=====================
|
10
|
+
* Fix call stack printer broken in version 1.0.0 (Charlie Savage)
|
11
|
+
* Ruby 2.7.0 support (Charlie Savage)
|
12
|
+
* Switch to Windows high precision timer for measuring wall time (Charlie Savage)
|
13
|
+
* Much better support for reverse call trees - if you start RubyProf at the bottom
|
14
|
+
of a call tree it will correctly calculate times as it ascends the tree (Charlie Savage)
|
15
|
+
* Port AggregateCallInfo from Ruby to C to increase performance
|
16
|
+
* API change - CallInfo has been renamed CallTree
|
17
|
+
* Fix crashes on Ruby 2.4.*
|
18
|
+
|
1
19
|
1.1.0 (2019-12-14)
|
2
20
|
=====================
|
3
21
|
Changes
|
@@ -342,7 +360,7 @@ Fixes
|
|
342
360
|
|
343
361
|
0.7.1 (2008-11-28)
|
344
362
|
========================
|
345
|
-
* Added new
|
363
|
+
* Added new AggregateCallTree class for printers to
|
346
364
|
make results easier to read. Take this call sequence
|
347
365
|
for example:
|
348
366
|
|
data/bin/ruby-prof
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
2
|
|
3
3
|
# First require ruby-prof
|
4
|
-
require 'rubygems'
|
5
4
|
require 'ruby-prof'
|
6
5
|
|
7
6
|
# Now setup option parser
|
@@ -14,64 +13,45 @@ module RubyProf
|
|
14
13
|
# Profiles a Ruby program.
|
15
14
|
#
|
16
15
|
# == Usage
|
17
|
-
#
|
18
|
-
# ruby_prof [options] <script.rb> [--] [script-options]
|
16
|
+
# ruby-prof [options] <script.rb> [--] [profiled-script-command-line-options]
|
19
17
|
#
|
20
18
|
# Options:
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
|
53
|
-
# -d Set $DEBUG to true
|
54
|
-
#
|
55
|
-
# -R, --require-noprof lib Require a specific library (not profiled)
|
56
|
-
#
|
57
|
-
# -E, --eval-noprof code Execute the ruby statements (not profiled)
|
58
|
-
#
|
59
|
-
# -x, --exclude regexp Exclude methods by regexp (see method elimination)
|
60
|
-
#
|
61
|
-
# -X, --exclude-file file Exclude methods by regexp listed in file (see method elimination)
|
62
|
-
#
|
63
|
-
# --exclude-common-cycles Make common iterators like Integer#times appear inlined
|
64
|
-
#
|
65
|
-
# --exclude-common-callbacks Make common callbacks invocations like Integer#times appear inlined so you can see call origins in graph
|
66
|
-
#
|
67
|
-
# -h, --help Show help message
|
68
|
-
#
|
69
|
-
# --version Show version
|
70
|
-
#
|
71
|
-
#
|
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
|
+
|
72
51
|
class Cmd
|
73
52
|
# :enddoc:
|
74
53
|
attr_accessor :options
|
54
|
+
attr_reader :profile
|
75
55
|
|
76
56
|
def initialize
|
77
57
|
setup_options
|
@@ -84,15 +64,52 @@ module RubyProf
|
|
84
64
|
def setup_options
|
85
65
|
@options = OpenStruct.new
|
86
66
|
options.printer = RubyProf::FlatPrinter
|
67
|
+
options.measure_mode = RubyProf::WALL_TIME
|
87
68
|
options.min_percent = 0
|
88
69
|
options.file = nil
|
89
|
-
options.
|
90
|
-
options.
|
91
|
-
|
70
|
+
options.allow_exceptions = false
|
71
|
+
options.exclude_common = false
|
72
|
+
options.exclude = Array.new
|
92
73
|
options.pre_libs = Array.new
|
93
74
|
options.pre_execs = Array.new
|
94
75
|
end
|
95
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
|
+
|
96
113
|
def option_parser
|
97
114
|
OptionParser.new do |opts|
|
98
115
|
opts.banner = "ruby_prof #{RubyProf::VERSION}\n" +
|
@@ -182,94 +199,45 @@ module RubyProf
|
|
182
199
|
end
|
183
200
|
end
|
184
201
|
|
185
|
-
opts.on("--replace-progname", "Replace $0 when loading the .rb files.") do
|
186
|
-
options.replace_prog_name = true
|
187
|
-
end
|
188
|
-
|
189
|
-
if defined?(RubyVM)
|
190
|
-
opts.on("--specialized-instruction", "Turn on specified instruction.") do
|
191
|
-
options.specialized_instruction = true
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
202
|
opts.on_tail("-h", "--help", "Show help message") do
|
196
203
|
puts opts
|
197
204
|
exit
|
198
205
|
end
|
199
206
|
|
200
|
-
opts.on_tail("--version", "Show version #{RubyProf::VERSION}") do
|
207
|
+
opts.on_tail("-v version", "--version", "Show version (#{RubyProf::VERSION})") do
|
201
208
|
puts "ruby_prof " + RubyProf::VERSION
|
202
209
|
exit
|
203
210
|
end
|
204
211
|
|
205
|
-
opts.on(
|
206
|
-
|
207
|
-
$VERBOSE = true
|
208
|
-
end
|
209
|
-
|
210
|
-
opts.on("-d", "Set $DEBUG to true") do
|
211
|
-
$DEBUG = true
|
212
|
+
opts.on('--allow_exceptions', 'Raise exceptions encountered during profiling (true) or suppress them (false)') do
|
213
|
+
options.allow_exceptions = true
|
212
214
|
end
|
213
215
|
|
214
|
-
opts.on('-R lib', '--require-noprof
|
216
|
+
opts.on('-R lib', '--require-noprof=lib', 'require a specific library (not profiled)') do |lib|
|
215
217
|
options.pre_libs << lib
|
216
218
|
end
|
217
219
|
|
218
|
-
opts.on('-E code', '--eval-noprof
|
220
|
+
opts.on('-E code', '--eval-noprof=code', 'execute the ruby statements (not profiled)') do |code|
|
219
221
|
options.pre_execs << code
|
220
222
|
end
|
221
223
|
|
222
|
-
opts.on('
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
Integer#times
|
236
|
-
Integer#upto
|
237
|
-
Integer#downto
|
238
|
-
Enumerator#each
|
239
|
-
Enumerator#each_with_index
|
240
|
-
Enumerator#each_with_object
|
241
|
-
|
242
|
-
Array#each
|
243
|
-
Array#each_index
|
244
|
-
Array#reverse_each
|
245
|
-
Array#map
|
246
|
-
|
247
|
-
Hash#each
|
248
|
-
Hash#each_pair
|
249
|
-
Hash#each_key
|
250
|
-
Hash#each_value
|
251
|
-
|
252
|
-
Range#each
|
253
|
-
Enumerable#each_cons
|
254
|
-
Enumerable#each_entry
|
255
|
-
Enumerable#each_slice
|
256
|
-
Enumerable#each_with_index
|
257
|
-
Enumerable#each_with_object
|
258
|
-
Enumerable#reverse_each
|
259
|
-
Enumerable#inject
|
260
|
-
Enumerable#collect
|
261
|
-
Enumerable#reduce
|
262
|
-
}
|
263
|
-
#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
|
264
237
|
end
|
265
238
|
|
266
|
-
opts.on('--exclude-common
|
267
|
-
options.
|
268
|
-
options.eliminate_methods += %w{
|
269
|
-
Method#call
|
270
|
-
Proc#call
|
271
|
-
ActiveSupport::Callbacks::ClassMethods#__run_callback
|
272
|
-
}
|
239
|
+
opts.on('--exclude-common', 'Remove common methods from the profile') do
|
240
|
+
options.exclude_common = true
|
273
241
|
end
|
274
242
|
end
|
275
243
|
end
|
@@ -313,23 +281,15 @@ module RubyProf
|
|
313
281
|
end
|
314
282
|
|
315
283
|
def run
|
316
|
-
# Get the script we will execute
|
317
284
|
script = ARGV.shift
|
318
|
-
|
319
|
-
|
285
|
+
@profile = Profile.new(options.to_h)
|
286
|
+
options.exclude.each do |klass, method|
|
287
|
+
@profile.exclude_method!(klass, method)
|
320
288
|
end
|
321
289
|
|
322
|
-
|
323
|
-
|
324
|
-
RubyVM::InstructionSequence.compile_option = {
|
325
|
-
:trace_instruction => true,
|
326
|
-
:specialized_instruction => options.specialized_instruction
|
327
|
-
}
|
290
|
+
profile.profile do
|
291
|
+
load script
|
328
292
|
end
|
329
|
-
|
330
|
-
# Set the measure mode
|
331
|
-
RubyProf.measure_mode = options.measure_mode if options.measure_mode
|
332
|
-
RubyProf.start_script(script)
|
333
293
|
end
|
334
294
|
end
|
335
295
|
end
|
@@ -342,20 +302,8 @@ cmd = RubyProf::Cmd.new
|
|
342
302
|
# *after* any other one that will be installed.
|
343
303
|
|
344
304
|
at_exit {
|
345
|
-
# Stop profiling
|
346
|
-
result = RubyProf.stop
|
347
|
-
|
348
|
-
# Eliminate unwanted methods from call graph
|
349
|
-
if cmd.options.eliminate_methods
|
350
|
-
result.eliminate_methods!(cmd.options.eliminate_methods)
|
351
|
-
end
|
352
|
-
|
353
|
-
if cmd.options.eliminate_methods_files
|
354
|
-
cmd.options.eliminate_methods_files.each {|f| result.eliminate_methods!(f)}
|
355
|
-
end
|
356
|
-
|
357
305
|
# Create a printer
|
358
|
-
printer = cmd.options.printer.new(
|
306
|
+
printer = cmd.options.printer.new(cmd.profile)
|
359
307
|
printer_options = {:min_percent => cmd.options.min_percent, :sort_method => cmd.options.sort_method}
|
360
308
|
|
361
309
|
# Get output
|
@@ -0,0 +1,59 @@
|
|
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
|
+
size_t prof_aggregate_call_tree_size(const void* data)
|
28
|
+
{
|
29
|
+
return sizeof(prof_call_tree_t);
|
30
|
+
}
|
31
|
+
|
32
|
+
static const rb_data_type_t aggregate_call_tree_type =
|
33
|
+
{
|
34
|
+
.wrap_struct_name = "Aggregate_CallTree",
|
35
|
+
.function =
|
36
|
+
{
|
37
|
+
.dmark = prof_aggregate_call_tree_mark,
|
38
|
+
.dfree = prof_aggregate_call_tree_ruby_gc_free,
|
39
|
+
.dsize = prof_aggregate_call_tree_size,
|
40
|
+
},
|
41
|
+
.data = NULL,
|
42
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
43
|
+
};
|
44
|
+
|
45
|
+
VALUE prof_aggregate_call_tree_wrap(prof_call_tree_t* call_tree)
|
46
|
+
{
|
47
|
+
if (call_tree->object == Qnil)
|
48
|
+
{
|
49
|
+
call_tree->object = TypedData_Wrap_Struct(cRpAggregateCallTree, &aggregate_call_tree_type, call_tree);
|
50
|
+
}
|
51
|
+
return call_tree->object;
|
52
|
+
}
|
53
|
+
|
54
|
+
void rp_init_aggregate_call_tree()
|
55
|
+
{
|
56
|
+
// AggregateCallTree
|
57
|
+
cRpAggregateCallTree = rb_define_class_under(mProf, "AggregateCallTree", cRpCallTree);
|
58
|
+
rb_undef_method(CLASS_OF(cRpAggregateCallTree), "new");
|
59
|
+
}
|
@@ -0,0 +1,13 @@
|
|
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
|
+
#ifndef __RP_AGGREGATE_CALL_TREE_H__
|
5
|
+
#define __RP_AGGREGATE_CALL_TREE_H__
|
6
|
+
|
7
|
+
#include "ruby_prof.h"
|
8
|
+
#include "rp_call_tree.h"
|
9
|
+
|
10
|
+
void rp_init_aggregate_call_tree(void);
|
11
|
+
VALUE prof_aggregate_call_tree_wrap(prof_call_tree_t* call_tree);
|
12
|
+
|
13
|
+
#endif //__RP_AGGREGATE_CALL_TREE_H__
|
@@ -5,12 +5,11 @@
|
|
5
5
|
|
6
6
|
VALUE cRpAllocation;
|
7
7
|
|
8
|
-
prof_allocation_t*
|
9
|
-
allocations_table_lookup(st_table *table, st_data_t key)
|
8
|
+
prof_allocation_t* allocations_table_lookup(st_table* table, st_data_t key)
|
10
9
|
{
|
11
10
|
prof_allocation_t* result = NULL;
|
12
11
|
st_data_t value;
|
13
|
-
if (
|
12
|
+
if (rb_st_lookup(table, key, &value))
|
14
13
|
{
|
15
14
|
result = (prof_allocation_t*)value;
|
16
15
|
}
|
@@ -18,23 +17,20 @@ allocations_table_lookup(st_table *table, st_data_t key)
|
|
18
17
|
return result;
|
19
18
|
}
|
20
19
|
|
21
|
-
void
|
22
|
-
allocations_table_insert(st_table *table, st_data_t key, prof_allocation_t * allocation)
|
20
|
+
void allocations_table_insert(st_table* table, st_data_t key, prof_allocation_t* allocation)
|
23
21
|
{
|
24
|
-
|
22
|
+
rb_st_insert(table, (st_data_t)key, (st_data_t)allocation);
|
25
23
|
}
|
26
24
|
|
27
|
-
st_data_t
|
28
|
-
allocations_key(VALUE klass, int source_line)
|
25
|
+
st_data_t allocations_key(VALUE klass, int source_line)
|
29
26
|
{
|
30
27
|
return (klass << 4) + source_line;
|
31
28
|
}
|
32
29
|
|
33
30
|
/* ====== prof_allocation_t ====== */
|
34
|
-
prof_allocation_t*
|
35
|
-
prof_allocation_create(void)
|
31
|
+
prof_allocation_t* prof_allocation_create(void)
|
36
32
|
{
|
37
|
-
prof_allocation_t
|
33
|
+
prof_allocation_t* result = ALLOC(prof_allocation_t);
|
38
34
|
result->count = 0;
|
39
35
|
result->klass = Qnil;
|
40
36
|
result->klass_name = Qnil;
|
@@ -47,8 +43,19 @@ prof_allocation_create(void)
|
|
47
43
|
return result;
|
48
44
|
}
|
49
45
|
|
50
|
-
prof_allocation_t*
|
51
|
-
|
46
|
+
prof_allocation_t* prof_get_allocation(VALUE self)
|
47
|
+
{
|
48
|
+
/* Can't use Data_Get_Struct because that triggers the event hook
|
49
|
+
ending up in endless recursion. */
|
50
|
+
prof_allocation_t* result = RTYPEDDATA_DATA(self);
|
51
|
+
|
52
|
+
if (!result)
|
53
|
+
rb_raise(rb_eRuntimeError, "This RubyProf::Allocation instance has already been freed, likely because its profile has been freed.");
|
54
|
+
|
55
|
+
return result;
|
56
|
+
}
|
57
|
+
|
58
|
+
prof_allocation_t* prof_allocate_increment(prof_method_t* method, rb_trace_arg_t* trace_arg)
|
52
59
|
{
|
53
60
|
VALUE object = rb_tracearg_object(trace_arg);
|
54
61
|
if (BUILTIN_TYPE(object) == T_IMEMO)
|
@@ -78,76 +85,85 @@ prof_allocate_increment(prof_method_t* method, rb_trace_arg_t* trace_arg)
|
|
78
85
|
return allocation;
|
79
86
|
}
|
80
87
|
|
81
|
-
static void
|
82
|
-
prof_allocation_ruby_gc_free(void *data)
|
88
|
+
static void prof_allocation_ruby_gc_free(void* data)
|
83
89
|
{
|
84
|
-
|
90
|
+
if (data)
|
91
|
+
{
|
92
|
+
prof_allocation_t* allocation = (prof_allocation_t*)data;
|
93
|
+
allocation->object = Qnil;
|
94
|
+
}
|
95
|
+
}
|
85
96
|
|
97
|
+
void prof_allocation_free(prof_allocation_t* allocation)
|
98
|
+
{
|
86
99
|
/* Has this allocation object been accessed by Ruby? If
|
87
100
|
yes clean it up so to avoid a segmentation fault. */
|
88
101
|
if (allocation->object != Qnil)
|
89
102
|
{
|
90
|
-
|
91
|
-
RDATA(allocation->object)->dfree = NULL;
|
92
|
-
RDATA(allocation->object)->data = NULL;
|
103
|
+
RTYPEDDATA(allocation->object)->data = NULL;
|
93
104
|
allocation->object = Qnil;
|
94
105
|
}
|
95
|
-
}
|
96
106
|
|
97
|
-
void
|
98
|
-
prof_allocation_free(prof_allocation_t* allocation)
|
99
|
-
{
|
100
|
-
prof_allocation_ruby_gc_free(allocation);
|
101
107
|
xfree(allocation);
|
102
108
|
}
|
103
109
|
|
104
|
-
size_t
|
105
|
-
prof_allocation_size(const void* data)
|
110
|
+
size_t prof_allocation_size(const void* data)
|
106
111
|
{
|
107
112
|
return sizeof(prof_allocation_t);
|
108
113
|
}
|
109
114
|
|
110
|
-
void
|
111
|
-
prof_allocation_mark(void *data)
|
115
|
+
void prof_allocation_mark(void* data)
|
112
116
|
{
|
117
|
+
if (!data) return;
|
118
|
+
|
113
119
|
prof_allocation_t* allocation = (prof_allocation_t*)data;
|
120
|
+
if (allocation->object != Qnil)
|
121
|
+
rb_gc_mark(allocation->object);
|
122
|
+
|
114
123
|
if (allocation->klass != Qnil)
|
115
124
|
rb_gc_mark(allocation->klass);
|
116
|
-
|
125
|
+
|
117
126
|
if (allocation->klass_name != Qnil)
|
118
127
|
rb_gc_mark(allocation->klass_name);
|
119
128
|
|
120
|
-
if (allocation->object != Qnil)
|
121
|
-
rb_gc_mark(allocation->object);
|
122
|
-
|
123
129
|
if (allocation->source_file != Qnil)
|
124
130
|
rb_gc_mark(allocation->source_file);
|
125
131
|
}
|
126
132
|
|
127
|
-
|
128
|
-
|
133
|
+
static const rb_data_type_t allocation_type =
|
134
|
+
{
|
135
|
+
.wrap_struct_name = "Allocation",
|
136
|
+
.function =
|
137
|
+
{
|
138
|
+
.dmark = prof_allocation_mark,
|
139
|
+
.dfree = prof_allocation_ruby_gc_free,
|
140
|
+
.dsize = prof_allocation_size,
|
141
|
+
},
|
142
|
+
.data = NULL,
|
143
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
144
|
+
};
|
145
|
+
|
146
|
+
VALUE prof_allocation_wrap(prof_allocation_t* allocation)
|
129
147
|
{
|
130
148
|
if (allocation->object == Qnil)
|
131
149
|
{
|
132
|
-
allocation->object =
|
150
|
+
allocation->object = TypedData_Wrap_Struct(cRpAllocation, &allocation_type, allocation);
|
133
151
|
}
|
134
152
|
return allocation->object;
|
135
153
|
}
|
136
154
|
|
137
|
-
static VALUE
|
138
|
-
prof_allocation_allocate(VALUE klass)
|
155
|
+
static VALUE prof_allocation_allocate(VALUE klass)
|
139
156
|
{
|
140
157
|
prof_allocation_t* allocation = prof_allocation_create();
|
141
158
|
allocation->object = prof_allocation_wrap(allocation);
|
142
159
|
return allocation->object;
|
143
160
|
}
|
144
161
|
|
145
|
-
prof_allocation_t*
|
146
|
-
prof_allocation_get(VALUE self)
|
162
|
+
prof_allocation_t* prof_allocation_get(VALUE self)
|
147
163
|
{
|
148
164
|
/* Can't use Data_Get_Struct because that triggers the event hook
|
149
165
|
ending up in endless recursion. */
|
150
|
-
prof_allocation_t* result =
|
166
|
+
prof_allocation_t* result = RTYPEDDATA_DATA(self);
|
151
167
|
if (!result)
|
152
168
|
rb_raise(rb_eRuntimeError, "This RubyProf::Allocation instance has already been freed, likely because its profile has been freed.");
|
153
169
|
|
@@ -158,8 +174,7 @@ prof_allocation_get(VALUE self)
|
|
158
174
|
klass -> Class
|
159
175
|
|
160
176
|
Returns the type of Class being allocated. */
|
161
|
-
static VALUE
|
162
|
-
prof_allocation_klass_name(VALUE self)
|
177
|
+
static VALUE prof_allocation_klass_name(VALUE self)
|
163
178
|
{
|
164
179
|
prof_allocation_t* allocation = prof_allocation_get(self);
|
165
180
|
|
@@ -174,8 +189,7 @@ prof_allocation_klass_name(VALUE self)
|
|
174
189
|
|
175
190
|
Returns the klass flags */
|
176
191
|
|
177
|
-
static VALUE
|
178
|
-
prof_allocation_klass_flags(VALUE self)
|
192
|
+
static VALUE prof_allocation_klass_flags(VALUE self)
|
179
193
|
{
|
180
194
|
prof_allocation_t* allocation = prof_allocation_get(self);
|
181
195
|
return INT2FIX(allocation->klass_flags);
|
@@ -185,8 +199,7 @@ prof_allocation_klass_flags(VALUE self)
|
|
185
199
|
source_file -> string
|
186
200
|
|
187
201
|
Returns the the line number where objects were allocated. */
|
188
|
-
static VALUE
|
189
|
-
prof_allocation_source_file(VALUE self)
|
202
|
+
static VALUE prof_allocation_source_file(VALUE self)
|
190
203
|
{
|
191
204
|
prof_allocation_t* allocation = prof_allocation_get(self);
|
192
205
|
return allocation->source_file;
|
@@ -196,8 +209,7 @@ prof_allocation_source_file(VALUE self)
|
|
196
209
|
line -> number
|
197
210
|
|
198
211
|
Returns the the line number where objects were allocated. */
|
199
|
-
static VALUE
|
200
|
-
prof_allocation_source_line(VALUE self)
|
212
|
+
static VALUE prof_allocation_source_line(VALUE self)
|
201
213
|
{
|
202
214
|
prof_allocation_t* allocation = prof_allocation_get(self);
|
203
215
|
return INT2FIX(allocation->source_line);
|
@@ -207,8 +219,7 @@ prof_allocation_source_line(VALUE self)
|
|
207
219
|
count -> number
|
208
220
|
|
209
221
|
Returns the number of times this class has been allocated. */
|
210
|
-
static VALUE
|
211
|
-
prof_allocation_count(VALUE self)
|
222
|
+
static VALUE prof_allocation_count(VALUE self)
|
212
223
|
{
|
213
224
|
prof_allocation_t* allocation = prof_allocation_get(self);
|
214
225
|
return INT2FIX(allocation->count);
|
@@ -218,18 +229,16 @@ prof_allocation_count(VALUE self)
|
|
218
229
|
memory -> number
|
219
230
|
|
220
231
|
Returns the amount of memory allocated. */
|
221
|
-
static VALUE
|
222
|
-
prof_allocation_memory(VALUE self)
|
232
|
+
static VALUE prof_allocation_memory(VALUE self)
|
223
233
|
{
|
224
234
|
prof_allocation_t* allocation = prof_allocation_get(self);
|
225
235
|
return ULL2NUM(allocation->memory);
|
226
236
|
}
|
227
237
|
|
228
238
|
/* :nodoc: */
|
229
|
-
static VALUE
|
230
|
-
prof_allocation_dump(VALUE self)
|
239
|
+
static VALUE prof_allocation_dump(VALUE self)
|
231
240
|
{
|
232
|
-
prof_allocation_t* allocation =
|
241
|
+
prof_allocation_t* allocation = prof_get_allocation(self);
|
233
242
|
|
234
243
|
VALUE result = rb_hash_new();
|
235
244
|
|
@@ -245,10 +254,9 @@ prof_allocation_dump(VALUE self)
|
|
245
254
|
}
|
246
255
|
|
247
256
|
/* :nodoc: */
|
248
|
-
static VALUE
|
249
|
-
prof_allocation_load(VALUE self, VALUE data)
|
257
|
+
static VALUE prof_allocation_load(VALUE self, VALUE data)
|
250
258
|
{
|
251
|
-
prof_allocation_t* allocation =
|
259
|
+
prof_allocation_t* allocation = prof_get_allocation(self);
|
252
260
|
allocation->object = self;
|
253
261
|
|
254
262
|
allocation->key = FIX2LONG(rb_hash_aref(data, ID2SYM(rb_intern("key"))));
|
@@ -264,7 +272,7 @@ prof_allocation_load(VALUE self, VALUE data)
|
|
264
272
|
|
265
273
|
void rp_init_allocation(void)
|
266
274
|
{
|
267
|
-
cRpAllocation = rb_define_class_under(mProf, "Allocation",
|
275
|
+
cRpAllocation = rb_define_class_under(mProf, "Allocation", rb_cObject);
|
268
276
|
rb_undef_method(CLASS_OF(cRpAllocation), "new");
|
269
277
|
rb_define_alloc_func(cRpAllocation, prof_allocation_allocate);
|
270
278
|
|