ruby-changes:62873
From: Jean <ko1@a...>
Date: Thu, 10 Sep 2020 00:05:32 +0900 (JST)
Subject: [ruby-changes:62873] b49a870414 (master): Add a :since option to dump_all
https://git.ruby-lang.org/ruby.git/commit/?id=b49a870414 From b49a8704143ce47de0472b6033fc5797aed21f52 Mon Sep 17 00:00:00 2001 From: Jean Boussier <jean.boussier@g...> Date: Tue, 28 Jul 2020 12:58:49 +0200 Subject: Add a :since option to dump_all This is useful to see what a block of code allocated, e.g. ``` GC.start GC.disable ObjectSpace.trace_object_allocations do # run some code end gc_gen = GC.count allocations = ObjectSpace.dump_all(output: :file, since: gc_gen) GC.enable GC.start retentions = ObjectSpace.dump_all(output: :file, since: gc_gen) ``` diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c index f7b9b0b..f4fb33e 100644 --- a/ext/objspace/objspace_dump.c +++ b/ext/objspace/objspace_dump.c @@ -23,7 +23,7 @@ https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace_dump.c#L23 #include "vm_core.h" static VALUE sym_output, sym_stdout, sym_string, sym_file; -static VALUE sym_full; +static VALUE sym_full, sym_since; struct dump_config { VALUE type; @@ -35,6 +35,8 @@ struct dump_config { https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace_dump.c#L35 size_t cur_obj_references; unsigned int roots: 1; unsigned int full_heap: 1; + unsigned int partial_dump; + size_t since; }; PRINTF_ARGS(static void dump_append(struct dump_config *, const char *, ...), 2, 3); @@ -202,7 +204,7 @@ static void https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace_dump.c#L204 dump_object(VALUE obj, struct dump_config *dc) { size_t memsize; - struct allocation_info *ainfo; + struct allocation_info *ainfo = objspace_lookup_allocation_info(obj); rb_io_t *fptr; ID flags[RB_OBJ_GC_FLAGS_MAX]; size_t n, i; @@ -216,6 +218,10 @@ dump_object(VALUE obj, struct dump_config *dc) https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace_dump.c#L218 dc->cur_obj_references = 0; dc->cur_obj_klass = BUILTIN_TYPE(obj) == T_NODE ? 0 : RBASIC_CLASS(obj); + if (dc->partial_dump && (!ainfo || ainfo->generation < dc->since)) { + return; + } + if (dc->cur_obj == dc->string) return; @@ -309,7 +315,7 @@ dump_object(VALUE obj, struct dump_config *dc) https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace_dump.c#L315 if (dc->cur_obj_references > 0) dump_append(dc, "]"); - if ((ainfo = objspace_lookup_allocation_info(obj))) { + if (ainfo) { dump_append(dc, ", \"file\":\"%s\", \"line\":%lu", ainfo->path, ainfo->line); if (RTEST(ainfo->mid)) { VALUE m = rb_sym2str(ainfo->mid); @@ -374,6 +380,14 @@ dump_output(struct dump_config *dc, VALUE opts, VALUE output, const char *filena https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace_dump.c#L380 if (Qtrue == rb_hash_lookup2(opts, sym_full, Qfalse)) dc->full_heap = 1; + + VALUE since = rb_hash_aref(opts, sym_since); + if (RTEST(since)) { + dc->partial_dump = 1; + dc->since = NUM2SIZET(since); + } else { + dc->partial_dump = 0; + } } if (output == sym_stdout) { @@ -456,9 +470,23 @@ objspace_dump(int argc, VALUE *argv, VALUE os) https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace_dump.c#L470 * ObjectSpace.dump_all(output: :string) # => "{...}\n{...}\n..." * ObjectSpace.dump_all(output: * File.open('heap.json','w')) # => #<File:heap.json> + * ObjectSpace.dump_all(output: :string, + * since: 42) # => "{...}\n{...}\n..." * * Dump the contents of the ruby heap as JSON. * + * _since_ must be a non-negative integer or +nil+. + * + * If _since_ is a positive integer, only objects of that generation and + * newer generations are dumped. The current generation can be accessed using + * GC::count. + * + * Objects that were allocated without object allocation tracing enabled + * are ignored. See ::trace_object_allocations for more information and + * examples. + * + * If _since_ is omitted or is +nil+, all objects are dumped. + * * This method is only expected to work with C Ruby. * This is an experimental method and is subject to change. * In particular, the function signature and output format are @@ -476,9 +504,11 @@ objspace_dump_all(int argc, VALUE *argv, VALUE os) https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace_dump.c#L504 output = dump_output(&dc, opts, sym_file, filename); - /* dump roots */ - rb_objspace_reachable_objects_from_root(root_obj_i, &dc); - if (dc.roots) dump_append(&dc, "]}\n"); + if (!dc.partial_dump || dc.since == 0) { + /* dump roots */ + rb_objspace_reachable_objects_from_root(root_obj_i, &dc); + if (dc.roots) dump_append(&dc, "]}\n"); + } /* dump all objects */ rb_objspace_each_objects(heap_i, &dc); @@ -500,6 +530,7 @@ Init_objspace_dump(VALUE rb_mObjSpace) https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace_dump.c#L530 sym_output = ID2SYM(rb_intern("output")); sym_stdout = ID2SYM(rb_intern("stdout")); sym_string = ID2SYM(rb_intern("string")); + sym_since = ID2SYM(rb_intern("since")); sym_file = ID2SYM(rb_intern("file")); sym_full = ID2SYM(rb_intern("full")); diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb index 40f1c73..7405b88 100644 --- a/test/objspace/test_objspace.rb +++ b/test/objspace/test_objspace.rb @@ -336,6 +336,29 @@ class TestObjSpace < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/objspace/test_objspace.rb#L336 end end + def test_dump_all_single_generation + assert_in_out_err(%w[-robjspace], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error| + begin; + def dump_my_heap_please + GC.start + ObjectSpace.trace_object_allocations_start + gc_gen = GC.count + puts gc_gen + @obj1 = Object.new + GC.start + @obj2 = Object.new + ObjectSpace.dump_all(output: :stdout, since: gc_gen) + end + + dump_my_heap_please + end; + since = output.shift.to_i + assert_operator output.size, :>, 0 + generations = output.map { |l| JSON.parse(l)["generation"] }.uniq.sort + assert_equal [since, since + 1], generations + end + end + def test_dump_addresses_match_dump_all_addresses assert_in_out_err(%w[-robjspace], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error| begin; -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/