[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]