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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +19 -1
  3. data/bin/ruby-prof +100 -152
  4. data/ext/ruby_prof/rp_aggregate_call_tree.c +59 -0
  5. data/ext/ruby_prof/rp_aggregate_call_tree.h +13 -0
  6. data/ext/ruby_prof/rp_allocation.c +67 -59
  7. data/ext/ruby_prof/rp_allocation.h +3 -3
  8. data/ext/ruby_prof/rp_call_tree.c +369 -0
  9. data/ext/ruby_prof/rp_call_tree.h +43 -0
  10. data/ext/ruby_prof/rp_call_trees.c +288 -0
  11. data/ext/ruby_prof/rp_call_trees.h +28 -0
  12. data/ext/ruby_prof/rp_measure_allocations.c +11 -13
  13. data/ext/ruby_prof/rp_measure_process_time.c +11 -13
  14. data/ext/ruby_prof/rp_measure_wall_time.c +17 -15
  15. data/ext/ruby_prof/rp_measurement.c +47 -40
  16. data/ext/ruby_prof/rp_measurement.h +7 -7
  17. data/ext/ruby_prof/rp_method.c +116 -255
  18. data/ext/ruby_prof/rp_method.h +31 -39
  19. data/ext/ruby_prof/rp_profile.c +311 -281
  20. data/ext/ruby_prof/rp_profile.h +1 -2
  21. data/ext/ruby_prof/rp_stack.c +113 -105
  22. data/ext/ruby_prof/rp_stack.h +17 -20
  23. data/ext/ruby_prof/rp_thread.c +136 -111
  24. data/ext/ruby_prof/rp_thread.h +12 -9
  25. data/ext/ruby_prof/ruby_prof.c +27 -23
  26. data/ext/ruby_prof/ruby_prof.h +9 -0
  27. data/ext/ruby_prof/vc/ruby_prof.vcxproj +11 -7
  28. data/lib/ruby-prof.rb +2 -3
  29. data/lib/ruby-prof/assets/call_stack_printer.html.erb +4 -7
  30. data/lib/ruby-prof/assets/graph_printer.html.erb +5 -6
  31. data/lib/ruby-prof/{call_info.rb → call_tree.rb} +6 -6
  32. data/lib/ruby-prof/call_tree_visitor.rb +36 -0
  33. data/lib/ruby-prof/measurement.rb +5 -2
  34. data/lib/ruby-prof/method_info.rb +3 -15
  35. data/lib/ruby-prof/printers/call_info_printer.rb +12 -10
  36. data/lib/ruby-prof/printers/call_stack_printer.rb +19 -22
  37. data/lib/ruby-prof/printers/call_tree_printer.rb +1 -1
  38. data/lib/ruby-prof/printers/dot_printer.rb +3 -3
  39. data/lib/ruby-prof/printers/graph_printer.rb +3 -4
  40. data/lib/ruby-prof/printers/multi_printer.rb +2 -2
  41. data/lib/ruby-prof/rack.rb +3 -0
  42. data/lib/ruby-prof/thread.rb +3 -18
  43. data/lib/ruby-prof/version.rb +1 -1
  44. data/ruby-prof.gemspec +7 -0
  45. data/test/alias_test.rb +42 -45
  46. data/test/basic_test.rb +0 -86
  47. data/test/{call_info_visitor_test.rb → call_tree_visitor_test.rb} +6 -5
  48. data/test/call_trees_test.rb +66 -0
  49. data/test/exclude_methods_test.rb +17 -12
  50. data/test/fiber_test.rb +197 -9
  51. data/test/gc_test.rb +36 -42
  52. data/test/inverse_call_tree_test.rb +175 -0
  53. data/test/line_number_test.rb +67 -70
  54. data/test/marshal_test.rb +7 -11
  55. data/test/measure_allocations_test.rb +224 -234
  56. data/test/measure_allocations_trace_test.rb +224 -234
  57. data/test/measure_memory_trace_test.rb +814 -469
  58. data/test/measure_process_time_test.rb +0 -64
  59. data/test/measure_times.rb +2 -0
  60. data/test/measure_wall_time_test.rb +34 -58
  61. data/test/pause_resume_test.rb +19 -10
  62. data/test/prime.rb +1 -3
  63. data/test/prime_script.rb +6 -0
  64. data/test/printers_test.rb +1 -1
  65. data/test/recursive_test.rb +50 -54
  66. data/test/start_stop_test.rb +19 -19
  67. data/test/test_helper.rb +3 -15
  68. data/test/thread_test.rb +11 -11
  69. data/test/unique_call_path_test.rb +25 -95
  70. metadata +19 -10
  71. data/ext/ruby_prof/rp_call_info.c +0 -271
  72. data/ext/ruby_prof/rp_call_info.h +0 -35
  73. data/lib/2.6.5/ruby_prof.so +0 -0
  74. data/lib/ruby-prof/call_info_visitor.rb +0 -38
  75. data/test/parser_timings.rb +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92a058890ba891a0ccc0d5ef289dd4a5e0067359592ed04f95047a3bf30d0839
4
- data.tar.gz: 833c854ce3e2790ea696f411f5b3c8fd1fd9827e9eca4ffa0d2e3bb21871dd60
3
+ metadata.gz: 0e7a5ed3eff6d7d963f459a572dd63561423abb6d8911076e086e3588befb37b
4
+ data.tar.gz: b4bf7cc5ec23482ccbcb103b6c7ab87c8614da0076d6a43f4848d6cd8aee3178
5
5
  SHA512:
6
- metadata.gz: e9c9c5e882ecd371ceb24365d46446e863fbcfaac365dbd84c1aed3ffd24fafe2d7b8e7bc7d09babe07fc8e0d8877fb5c112917b6c1915305cb881dc34f8d49c
7
- data.tar.gz: 3206613c98c989672a6d329280c3076efb173e4fea0828b09f57ef4698f546aab8ec8cda04e6ef6ccd9d35101f8b2ae5af0a36b04f5c04fca6afa59543e34706
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 AggregateCallInfo class for printers to
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
 
@@ -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
- # -p, --printer=printer Select a printer:
22
- # flat - Prints a flat profile as text (default).
23
- # graph - Prints a graph profile as text.
24
- # graph_html - Prints a graph profile as html.
25
- # call_tree - format for KCacheGrind
26
- # call_stack - prints a HTML visualization of the call tree
27
- # dot - Prints a graph profile as a dot file
28
- # multi - Creates several reports in output directory
29
- #
30
- # -m, --min_percent=min_percent The minimum percent a method must take before
31
- # being included in output reports. This option is not supported for call tree reports.
32
- #
33
- # -f, --file=path Output results to a file instead of standard out.
34
- #
35
- # --mode=measure_mode Select what ruby-prof should measure:
36
- # wall - Wall time (default)
37
- # process - Process time
38
- # allocations - Object allocations
39
- # memory - Allocated memory
40
- #
41
- # -s, --sort=sort_mode Select how ruby-prof results should be sorted:
42
- # total - Total time
43
- # self - Self time
44
- # wait - Wait time
45
- # child - Child time
46
- #
47
- # --replace-progname Replace $0 when loading the .rb files.
48
- #
49
- # --specialized-instruction Turn on specified instruction.
50
- #
51
- # -v Show version, set $VERBOSE to true, profile script if option given
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.replace_prog_name = false
90
- options.specialized_instruction = false
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("-v","Show version, set $VERBOSE to true, profile script if option given") do
206
- puts "ruby version: " + [RUBY_PATCHLEVEL, RUBY_PLATFORM, RUBY_VERSION].join(' ')
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 lib', 'require a specific library (not profiled)') do |lib|
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 code', 'execute the ruby statements (not profiled)') do |code|
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('-x regexp', '--exclude regexp', 'exclude methods by regexp (see method elimination)') do |meth|
223
- options.eliminate_methods ||= []
224
- options.eliminate_methods << Regexp.new(meth)
225
- end
226
-
227
- opts.on('-X file', '--exclude-file file', 'exclude methods by regexp listed in file (see method elimination)') do|file|
228
- options.eliminate_methods_files ||= []
229
- options.eliminate_methods_files << file
230
- end
231
-
232
- opts.on('--exclude-common-cycles', 'make common iterators like Integer#times appear inlined') do |meth|
233
- options.eliminate_methods ||= []
234
- options.eliminate_methods += %w{
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-callbacks', 'make common callbacks invocations like Integer#times appear inlined so you can see call origins in graph') do|meth|
267
- options.eliminate_methods ||= []
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
- if options.replace_prog_name
319
- $0 = File.expand_path(script)
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
- # Set VM compile option
323
- if defined?(RubyVM)
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(result)
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 (st_lookup(table, key, &value))
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
- st_insert(table, (st_data_t)key, (st_data_t)allocation);
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 *result = ALLOC(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
- prof_allocate_increment(prof_method_t* method, rb_trace_arg_t* trace_arg)
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
- prof_allocation_t* allocation = (prof_allocation_t*)data;
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
- RDATA(allocation->object)->dmark = NULL;
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
- VALUE
128
- prof_allocation_wrap(prof_allocation_t *allocation)
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 = Data_Wrap_Struct(cRpAllocation, prof_allocation_mark , prof_allocation_ruby_gc_free, allocation);
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 = DATA_PTR(self);
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 = DATA_PTR(self);
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 = DATA_PTR(self);
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", rb_cData);
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