From 9fab2c1a1a5f5e429eb88eac29d250685dcc4354 Mon Sep 17 00:00:00 2001 From: Matt Valentine-House Date: Tue, 1 Feb 2022 21:36:29 +0000 Subject: [PATCH] Add the size pool slot size to the output of ObjectSpace.dump/dump_all --- ext/objspace/objspace_dump.c | 9 +++++++++ gc.h | 2 ++ test/objspace/test_objspace.rb | 28 ++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c index cf7acb5c6f9597..e958a831c56cc8 100644 --- a/ext/objspace/objspace_dump.c +++ b/ext/objspace/objspace_dump.c @@ -35,6 +35,7 @@ struct dump_config { const char *root_category; VALUE cur_obj; VALUE cur_obj_klass; + size_t cur_page_slot_size; size_t cur_obj_references; unsigned int roots: 1; unsigned int full_heap: 1; @@ -360,6 +361,9 @@ dump_object(VALUE obj, struct dump_config *dc) dump_append(dc, obj_type(obj)); dump_append(dc, "\""); + dump_append(dc, ", \"slot_size\":"); + dump_append_sizet(dc, dc->cur_page_slot_size); + if (dc->cur_obj_klass) { dump_append(dc, ", \"class\":"); dump_append_ref(dc, dc->cur_obj_klass); @@ -539,6 +543,7 @@ heap_i(void *vstart, void *vend, size_t stride, void *data) for (; v != (VALUE)vend; v += stride) { void *ptr = asan_poisoned_object_p(v); asan_unpoison_object(v, false); + dc->cur_page_slot_size = stride; if (dc->full_heap || RBASIC(v)->flags) dump_object(v, dc); @@ -616,6 +621,10 @@ static VALUE objspace_dump(VALUE os, VALUE obj, VALUE output) { struct dump_config dc = {0,}; + if (!RB_SPECIAL_CONST_P(obj)) { + dc.cur_page_slot_size = rb_gc_obj_slot_size(obj); + } + dump_output(&dc, output, Qnil, Qnil); dump_object(obj, &dc); diff --git a/gc.h b/gc.h index 91d6e5787df37c..84c8eade6368d8 100644 --- a/gc.h +++ b/gc.h @@ -136,6 +136,8 @@ void rb_objspace_each_objects_without_setup( int (*callback)(void *, void *, size_t, void *), void *data); +size_t rb_gc_obj_slot_size(VALUE obj); + RUBY_SYMBOL_EXPORT_END #endif /* RUBY_GC_H */ diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb index b7342e899bf027..34d9dd76ecdd8c 100644 --- a/test/objspace/test_objspace.rb +++ b/test/objspace/test_objspace.rb @@ -431,6 +431,27 @@ def dump_my_heap_please end end + def test_dump_objects_dumps_page_slot_sizes + assert_in_out_err(%w[-robjspace], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error| + begin; + def dump_my_heap_please + ObjectSpace.dump_all(output: $stdout) + end + + p $stdout == dump_my_heap_please + end; + assert_equal 'true', output.pop + assert(output.count > 1) + output.each { |l| + obj = JSON.parse(l) + next if obj["type"] == "ROOT" + + assert(obj["slot_size"] != nil) + assert(obj["slot_size"] % GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] == 0) + } + end + end + def test_dump_escapes_method_name method_name = "foo\"bar" klass = Class.new do @@ -449,6 +470,13 @@ def test_dump_escapes_method_name ObjectSpace.trace_object_allocations_stop end + def test_dump_includes_slot_size + str = "TEST" + dump = ObjectSpace.dump(str) + + assert_includes dump, "\"slot_size\":#{GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]}" + end + def test_dump_reference_addresses_match_dump_all_addresses assert_in_out_err(%w[-robjspace], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error| begin;