Skip to content

ObjectSpace.dump_all: dump shapes as well #6868

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 8, 2022

Conversation

casperisfine
Copy link
Contributor

@casperisfine casperisfine commented Dec 6, 2022

I see several arguments in doing so.

First they use a non trivial amount of memory, so for various memory profiling/mapping tools it is relevant to have visibility of the space occupied by shapes.

Then, some pathological code can create a tons of shape, so it is valuable have a way to observe shapes without having to compile Ruby with SHAPE_DEBUG=1.

And additionally it's likely much faster to dump them this way than to use RubyVM::Shape.

There are however a few open questions:

  • Shapes can't respect the since: argument. Not sure what to do when it is provided. Would probably make sense to not dump them.
  • If RubyVM::Shape.next_shape_id was available on all builds, we could use that as a cursor for differential dumps.
  • Maybe it would make more sense to have a separate ObjectSpace.dump_shapes?
  • Maybe instead dump_all should take a shapes: false argument?

Additionally, ObjectSpace.dump_shapes is added for the use case of debugging the evolution of the shape tree.

@casperisfine
Copy link
Contributor Author

I'm using this script to test this feature for now:

require 'objspace'

ObjectSpace.trace_object_allocations_start

class Foo
  def initialize
    @a = 1
    @b = 2
    @c = 3
  end

  def foo
    @foo ||= 1
  end

  def bar
    @bar ||= 1
  end
end

GC.start
gen = GC.count

f1 = Foo.new
f1.foo
f1.bar

f2 = Foo.new
f2.bar
f2.foo

ObjectSpace.dump_all(output: STDOUT, since: gen)


puts '-' * 40
puts "f1: #{ObjectSpace.dump(f1)}"
puts "f2: #{ObjectSpace.dump(f2)}"

s =  RubyVM::Shape.of(f1)
p [s, s.id, s.type, s.depth, s.edges]

The output looks like this:

{"address":"0x104fe0000", "type":"SHAPE", "id":0, "parent_id":4294967295, edges:6, "shape_type":"ROOT", "memsize":184}
{"address":"0x104fe0020", "type":"SHAPE", "id":1, "parent_id":0, edges:3, "shape_type":"INITIAL_CAPACITY", "memsize":120}
{"address":"0x104fe0040", "type":"SHAPE", "id":2, "parent_id":0, edges:6, "shape_type":"INITIAL_CAPACITY", "memsize":184}
{"address":"0x104fe0060", "type":"SHAPE", "id":3, "parent_id":0, edges:2, "shape_type":"INITIAL_CAPACITY", "memsize":120}
{"address":"0x104fe0080", "type":"SHAPE", "id":4, "parent_id":0, edges:2, "shape_type":"INITIAL_CAPACITY", "memsize":120}
{"address":"0x104fe00a0", "type":"SHAPE", "id":5, "parent_id":0, edges:6, "shape_type":"T_OBJECT", "memsize":184}
{"address":"0x104fe00c0", "type":"SHAPE", "id":6, "parent_id":1, edges:5, "shape_type":"T_OBJECT", "memsize":184}
{"address":"0x104fe00e0", "type":"SHAPE", "id":7, "parent_id":2, edges:0, "shape_type":"T_OBJECT", "memsize":32}
{"address":"0x104fe0100", "type":"SHAPE", "id":8, "parent_id":3, edges:0, "shape_type":"T_OBJECT", "memsize":32}
{"address":"0x104fe0120", "type":"SHAPE", "id":9, "parent_id":4, edges:1, "shape_type":"T_OBJECT", "memsize":120}
{"address":"0x104fe0140", "type":"SHAPE", "id":10, "parent_id":0, edges:0, "shape_type":"FROZEN", "memsize":32}
{"address":"0x104fe0160", "type":"SHAPE", "id":11, "parent_id":1, edges:0, "shape_type":"FROZEN", "memsize":32}
{"address":"0x104fe0180", "type":"SHAPE", "id":12, "parent_id":2, edges:7, "shape_type":"IVAR","edge_name":"__classpath__", "memsize":312}
{"address":"0x104fe01a0", "type":"SHAPE", "id":13, "parent_id":2, edges:0, "shape_type":"IVAR","edge_name":"__attached__", "memsize":32}
{"address":"0x104fe01c0", "type":"SHAPE", "id":14, "parent_id":5, edges:1, "shape_type":"IVAR","edge_name":"mesg", "memsize":120}
{"address":"0x104fe01e0", "type":"SHAPE", "id":15, "parent_id":14, edges:2, "shape_type":"IVAR","edge_name":"bt", "memsize":120}
{"address":"0x104fe0200", "type":"SHAPE", "id":16, "parent_id":15, edges:0, "shape_type":"FROZEN", "memsize":32}
{"address":"0x104fe0220", "type":"SHAPE", "id":17, "parent_id":12, edges:1, "shape_type":"IVAR","edge_name":"__members__", "memsize":120}
{"address":"0x104fe0240", "type":"SHAPE", "id":18, "parent_id":17, edges:0, "shape_type":"IVAR","edge_name":"__members_back__", "memsize":32}
{"address":"0x104fe0260", "type":"SHAPE", "id":19, "parent_id":5, edges:0, "shape_type":"FROZEN", "memsize":32}
{"address":"0x104fe0280", "type":"SHAPE", "id":20, "parent_id":1, edges:1, "shape_type":"IVAR","edge_name":"@gem_prelude_index", "memsize":120}
{"address":"0x104fe02a0", "type":"SHAPE", "id":21, "parent_id":2, edges:1, "shape_type":"IVAR","edge_name":"@gem_prelude_index", "memsize":120}
{"address":"0x104fe02c0", "type":"SHAPE", "id":22, "parent_id":2, edges:0, "shape_type":"FROZEN", "memsize":32}
{"address":"0x104fe02e0", "type":"SHAPE", "id":23, "parent_id":20, edges:0, "shape_type":"FROZEN", "memsize":32}
{"address":"0x104fe0300", "type":"SHAPE", "id":24, "parent_id":21, edges:0, "shape_type":"FROZEN", "memsize":32}
{"address":"0x104fe0320", "type":"SHAPE", "id":25, "parent_id":12, edges:0, "shape_type":"IVAR","edge_name":"__autoload__", "memsize":32}
{"address":"0x104fe0340", "type":"SHAPE", "id":26, "parent_id":3, edges:0, "shape_type":"FROZEN", "memsize":32}
{"address":"0x104fe0360", "type":"SHAPE", "id":27, "parent_id":4, edges:0, "shape_type":"FROZEN", "memsize":32}
{"address":"0x104fe0380", "type":"SHAPE", "id":28, "parent_id":12, edges:1, "shape_type":"IVAR","edge_name":"@post_install_hooks", "memsize":120}
{"address":"0x104fe03a0", "type":"SHAPE", "id":29, "parent_id":28, edges:1, "shape_type":"IVAR","edge_name":"@done_installing_hooks", "memsize":120}
{"address":"0x104fe03c0", "type":"SHAPE", "id":30, "parent_id":29, edges:1, "shape_type":"IVAR","edge_name":"@post_uninstall_hooks", "memsize":120}
{"address":"0x104fe03e0", "type":"SHAPE", "id":31, "parent_id":30, edges:1, "shape_type":"IVAR","edge_name":"@pre_uninstall_hooks", "memsize":120}
{"address":"0x104fe0400", "type":"SHAPE", "id":32, "parent_id":31, edges:1, "shape_type":"IVAR","edge_name":"@pre_install_hooks", "memsize":120}
{"address":"0x104fe0420", "type":"SHAPE", "id":33, "parent_id":32, edges:1, "shape_type":"IVAR","edge_name":"@@win_platform", "memsize":120}
{"address":"0x104fe0440", "type":"SHAPE", "id":34, "parent_id":33, edges:1, "shape_type":"IVAR","edge_name":"@configuration", "memsize":120}
{"address":"0x104fe0460", "type":"SHAPE", "id":35, "parent_id":34, edges:1, "shape_type":"IVAR","edge_name":"@gemdeps", "memsize":120}
{"address":"0x104fe0480", "type":"SHAPE", "id":36, "parent_id":35, edges:1, "shape_type":"IVAR","edge_name":"@loaded_specs", "memsize":120}
{"address":"0x104fe04a0", "type":"SHAPE", "id":37, "parent_id":36, edges:1, "shape_type":"IVAR","edge_name":"@path_to_default_spec_map", "memsize":120}
{"address":"0x104fe04c0", "type":"SHAPE", "id":38, "parent_id":37, edges:1, "shape_type":"IVAR","edge_name":"@platforms", "memsize":120}
{"address":"0x104fe04e0", "type":"SHAPE", "id":39, "parent_id":38, edges:1, "shape_type":"IVAR","edge_name":"@ruby", "memsize":120}
{"address":"0x104fe0500", "type":"SHAPE", "id":40, "parent_id":39, edges:1, "shape_type":"IVAR","edge_name":"@ruby_api_version", "memsize":120}
{"address":"0x104fe0520", "type":"SHAPE", "id":41, "parent_id":40, edges:1, "shape_type":"IVAR","edge_name":"@sources", "memsize":120}
{"address":"0x104fe0540", "type":"SHAPE", "id":42, "parent_id":41, edges:1, "shape_type":"IVAR","edge_name":"@post_build_hooks", "memsize":120}
{"address":"0x104fe0560", "type":"SHAPE", "id":43, "parent_id":42, edges:1, "shape_type":"IVAR","edge_name":"@pre_reset_hooks", "memsize":120}
{"address":"0x104fe0580", "type":"SHAPE", "id":44, "parent_id":43, edges:1, "shape_type":"IVAR","edge_name":"@post_reset_hooks", "memsize":120}
{"address":"0x104fe05a0", "type":"SHAPE", "id":45, "parent_id":44, edges:1, "shape_type":"IVAR","edge_name":"@default_source_date_epoch", "memsize":120}
{"address":"0x104fe05c0", "type":"SHAPE", "id":46, "parent_id":45, edges:1, "shape_type":"IVAR","edge_name":"@yaml_loaded", "memsize":120}
{"address":"0x104fe05e0", "type":"SHAPE", "id":47, "parent_id":46, edges:1, "shape_type":"IVAR","edge_name":"__autoload__", "memsize":120}
{"address":"0x104fe0600", "type":"SHAPE", "id":48, "parent_id":12, edges:0, "shape_type":"IVAR","edge_name":"@local", "memsize":32}
{"address":"0x104fe0620", "type":"SHAPE", "id":49, "parent_id":12, edges:1, "shape_type":"IVAR","edge_name":"@load_cache", "memsize":120}
{"address":"0x104fe0640", "type":"SHAPE", "id":50, "parent_id":49, edges:1, "shape_type":"IVAR","edge_name":"@load_cache_mutex", "memsize":120}
{"address":"0x104fe0660", "type":"SHAPE", "id":51, "parent_id":50, edges:1, "shape_type":"IVAR","edge_name":"@@required_attributes", "memsize":120}
{"address":"0x104fe0680", "type":"SHAPE", "id":52, "parent_id":12, edges:1, "shape_type":"IVAR","edge_name":"@@all", "memsize":120}
{"address":"0x104fe06a0", "type":"SHAPE", "id":53, "parent_id":52, edges:1, "shape_type":"IVAR","edge_name":"@@bump", "memsize":120}
{"address":"0x104fe06c0", "type":"SHAPE", "id":54, "parent_id":53, edges:0, "shape_type":"IVAR","edge_name":"@@release", "memsize":32}
{"address":"0x104fe06e0", "type":"SHAPE", "id":55, "parent_id":2, edges:1, "shape_type":"IVAR","edge_name":"__members__", "memsize":120}
{"address":"0x104fe0700", "type":"SHAPE", "id":56, "parent_id":55, edges:1, "shape_type":"IVAR","edge_name":"__members_back__", "memsize":120}
{"address":"0x104fe0720", "type":"SHAPE", "id":57, "parent_id":56, edges:0, "shape_type":"IVAR","edge_name":"__keyword_init__", "memsize":32}
{"address":"0x104fe0740", "type":"SHAPE", "id":58, "parent_id":5, edges:1, "shape_type":"IVAR","edge_name":"@version", "memsize":120}
{"address":"0x104fe0760", "type":"SHAPE", "id":59, "parent_id":58, edges:2, "shape_type":"IVAR","edge_name":"@segments", "memsize":120}
{"address":"0x104fe0780", "type":"SHAPE", "id":60, "parent_id":5, edges:0, "shape_type":"IVAR","edge_name":"@requirements", "memsize":32}
{"address":"0x104fe07a0", "type":"SHAPE", "id":61, "parent_id":51, edges:1, "shape_type":"IVAR","edge_name":"@@default_value", "memsize":120}
{"address":"0x104fe07c0", "type":"SHAPE", "id":62, "parent_id":61, edges:1, "shape_type":"IVAR","edge_name":"@@attributes", "memsize":120}
{"address":"0x104fe07e0", "type":"SHAPE", "id":63, "parent_id":62, edges:1, "shape_type":"IVAR","edge_name":"@@array_attributes", "memsize":120}
{"address":"0x104fe0800", "type":"SHAPE", "id":64, "parent_id":63, edges:1, "shape_type":"IVAR","edge_name":"@@nil_attributes", "memsize":120}
{"address":"0x104fe0820", "type":"SHAPE", "id":65, "parent_id":64, edges:1, "shape_type":"IVAR","edge_name":"@@non_nil_attributes", "memsize":120}
{"address":"0x104fe0840", "type":"SHAPE", "id":66, "parent_id":65, edges:1, "shape_type":"IVAR","edge_name":"@@all", "memsize":120}
{"address":"0x104fe0860", "type":"SHAPE", "id":67, "parent_id":66, edges:1, "shape_type":"IVAR","edge_name":"@@stubs", "memsize":120}
{"address":"0x104fe0880", "type":"SHAPE", "id":68, "parent_id":67, edges:1, "shape_type":"IVAR","edge_name":"@@stubs_by_name", "memsize":120}
{"address":"0x104fe08a0", "type":"SHAPE", "id":69, "parent_id":68, edges:1, "shape_type":"IVAR","edge_name":"@@spec_with_requirable_file", "memsize":120}
{"address":"0x104fe08c0", "type":"SHAPE", "id":70, "parent_id":69, edges:1, "shape_type":"IVAR","edge_name":"@@active_stub_with_requirable_file", "memsize":120}
{"address":"0x104fe08e0", "type":"SHAPE", "id":71, "parent_id":15, edges:1, "shape_type":"IVAR","edge_name":"@path", "memsize":120}
{"address":"0x104fe0900", "type":"SHAPE", "id":72, "parent_id":71, edges:1, "shape_type":"CAPACITY_CHANGE", "memsize":120}
{"address":"0x104fe0920", "type":"SHAPE", "id":73, "parent_id":72, edges:0, "shape_type":"IVAR","edge_name":"bt_locations", "memsize":32}
{"address":"0x104fe0940", "type":"SHAPE", "id":74, "parent_id":6, edges:1, "shape_type":"IVAR","edge_name":"mesg", "memsize":120}
{"address":"0x104fe0960", "type":"SHAPE", "id":75, "parent_id":74, edges:1, "shape_type":"IVAR","edge_name":"bt", "memsize":120}
{"address":"0x104fe0980", "type":"SHAPE", "id":76, "parent_id":75, edges:1, "shape_type":"IVAR","edge_name":"@path", "memsize":120}
{"address":"0x104fe09a0", "type":"SHAPE", "id":77, "parent_id":76, edges:0, "shape_type":"IVAR","edge_name":"bt_locations", "memsize":32}
{"address":"0x104fe09c0", "type":"SHAPE", "id":78, "parent_id":47, edges:1, "shape_type":"IVAR","edge_name":"@default_dir", "memsize":120}
{"address":"0x104fe09e0", "type":"SHAPE", "id":79, "parent_id":78, edges:1, "shape_type":"IVAR","edge_name":"@default_specifications_dir", "memsize":120}
{"address":"0x104fe0a00", "type":"SHAPE", "id":80, "parent_id":6, edges:1, "shape_type":"IVAR","edge_name":"@extension_dir", "memsize":120}
{"address":"0x104fe0a20", "type":"SHAPE", "id":81, "parent_id":80, edges:1, "shape_type":"IVAR","edge_name":"@full_gem_path", "memsize":120}
{"address":"0x104fe0a40", "type":"SHAPE", "id":82, "parent_id":81, edges:1, "shape_type":"IVAR","edge_name":"@gem_dir", "memsize":120}
{"address":"0x104fe0a60", "type":"SHAPE", "id":83, "parent_id":82, edges:1, "shape_type":"IVAR","edge_name":"@ignored", "memsize":120}
{"address":"0x104fe0a80", "type":"SHAPE", "id":84, "parent_id":83, edges:1, "shape_type":"IVAR","edge_name":"@bin_dir", "memsize":120}
{"address":"0x104fe0aa0", "type":"SHAPE", "id":85, "parent_id":84, edges:1, "shape_type":"IVAR","edge_name":"@cache_dir", "memsize":120}
{"address":"0x104fe0ac0", "type":"SHAPE", "id":86, "parent_id":85, edges:1, "shape_type":"IVAR","edge_name":"@cache_file", "memsize":120}
{"address":"0x104fe0ae0", "type":"SHAPE", "id":87, "parent_id":86, edges:1, "shape_type":"IVAR","edge_name":"@doc_dir", "memsize":120}
{"address":"0x104fe0b00", "type":"SHAPE", "id":88, "parent_id":87, edges:1, "shape_type":"CAPACITY_CHANGE", "memsize":120}
{"address":"0x104fe0b20", "type":"SHAPE", "id":89, "parent_id":88, edges:1, "shape_type":"IVAR","edge_name":"@ri_dir", "memsize":120}
{"address":"0x104fe0b40", "type":"SHAPE", "id":90, "parent_id":89, edges:1, "shape_type":"IVAR","edge_name":"@spec_dir", "memsize":120}
{"address":"0x104fe0b60", "type":"SHAPE", "id":91, "parent_id":90, edges:1, "shape_type":"IVAR","edge_name":"@spec_file", "memsize":120}
{"address":"0x104fe0b80", "type":"SHAPE", "id":92, "parent_id":91, edges:1, "shape_type":"IVAR","edge_name":"@gems_dir", "memsize":120}
{"address":"0x104fe0ba0", "type":"SHAPE", "id":93, "parent_id":92, edges:1, "shape_type":"IVAR","edge_name":"@base_dir", "memsize":120}
{"address":"0x104fe0bc0", "type":"SHAPE", "id":94, "parent_id":93, edges:1, "shape_type":"IVAR","edge_name":"@loaded", "memsize":120}
{"address":"0x104fe0be0", "type":"SHAPE", "id":95, "parent_id":94, edges:1, "shape_type":"IVAR","edge_name":"@activated", "memsize":120}
{"address":"0x104fe0c00", "type":"SHAPE", "id":96, "parent_id":95, edges:1, "shape_type":"IVAR","edge_name":"@loaded_from", "memsize":120}
{"address":"0x104fe0c20", "type":"SHAPE", "id":97, "parent_id":96, edges:1, "shape_type":"CAPACITY_CHANGE", "memsize":120}
{"address":"0x104fe0c40", "type":"SHAPE", "id":98, "parent_id":97, edges:1, "shape_type":"IVAR","edge_name":"@original_platform", "memsize":120}
{"address":"0x104fe0c60", "type":"SHAPE", "id":99, "parent_id":98, edges:1, "shape_type":"IVAR","edge_name":"@installed_by_version", "memsize":120}
{"address":"0x104fe0c80", "type":"SHAPE", "id":100, "parent_id":99, edges:1, "shape_type":"IVAR","edge_name":"@autorequire", "memsize":120}
{"address":"0x104fe0ca0", "type":"SHAPE", "id":101, "parent_id":100, edges:1, "shape_type":"IVAR","edge_name":"@date", "memsize":120}
{"address":"0x104fe0cc0", "type":"SHAPE", "id":102, "parent_id":101, edges:1, "shape_type":"IVAR","edge_name":"@description", "memsize":120}
{"address":"0x104fe0ce0", "type":"SHAPE", "id":103, "parent_id":102, edges:1, "shape_type":"IVAR","edge_name":"@email", "memsize":120}
{"address":"0x104fe0d00", "type":"SHAPE", "id":104, "parent_id":103, edges:1, "shape_type":"IVAR","edge_name":"@homepage", "memsize":120}
{"address":"0x104fe0d20", "type":"SHAPE", "id":105, "parent_id":104, edges:1, "shape_type":"IVAR","edge_name":"@name", "memsize":120}
{"address":"0x104fe0d40", "type":"SHAPE", "id":106, "parent_id":105, edges:1, "shape_type":"IVAR","edge_name":"@post_install_message", "memsize":120}
{"address":"0x104fe0d60", "type":"SHAPE", "id":107, "parent_id":106, edges:1, "shape_type":"IVAR","edge_name":"@signing_key", "memsize":120}
{"address":"0x104fe0d80", "type":"SHAPE", "id":108, "parent_id":107, edges:1, "shape_type":"IVAR","edge_name":"@summary", "memsize":120}
{"address":"0x104fe0da0", "type":"SHAPE", "id":109, "parent_id":108, edges:1, "shape_type":"IVAR","edge_name":"@version", "memsize":120}
{"address":"0x104fe0dc0", "type":"SHAPE", "id":110, "parent_id":109, edges:1, "shape_type":"IVAR","edge_name":"@authors", "memsize":120}
{"address":"0x104fe0de0", "type":"SHAPE", "id":111, "parent_id":110, edges:1, "shape_type":"IVAR","edge_name":"@bindir", "memsize":120}
{"address":"0x104fe0e00", "type":"SHAPE", "id":112, "parent_id":111, edges:1, "shape_type":"IVAR","edge_name":"@cert_chain", "memsize":120}
{"address":"0x104fe0e20", "type":"SHAPE", "id":113, "parent_id":112, edges:1, "shape_type":"IVAR","edge_name":"@dependencies", "memsize":120}
{"address":"0x104fe0e40", "type":"SHAPE", "id":114, "parent_id":113, edges:1, "shape_type":"CAPACITY_CHANGE", "memsize":120}
{"address":"0x104fe0e60", "type":"SHAPE", "id":115, "parent_id":114, edges:1, "shape_type":"IVAR","edge_name":"@executables", "memsize":120}
{"address":"0x104fe0e80", "type":"SHAPE", "id":116, "parent_id":115, edges:1, "shape_type":"IVAR","edge_name":"@extensions", "memsize":120}
{"address":"0x104fe0ea0", "type":"SHAPE", "id":117, "parent_id":116, edges:1, "shape_type":"IVAR","edge_name":"@extra_rdoc_files", "memsize":120}
{"address":"0x104fe0ec0", "type":"SHAPE", "id":118, "parent_id":117, edges:1, "shape_type":"IVAR","edge_name":"@files", "memsize":120}
{"address":"0x104fe0ee0", "type":"SHAPE", "id":119, "parent_id":118, edges:1, "shape_type":"IVAR","edge_name":"@licenses", "memsize":120}
{"address":"0x104fe0f00", "type":"SHAPE", "id":120, "parent_id":119, edges:1, "shape_type":"IVAR","edge_name":"@metadata", "memsize":120}
{"address":"0x104fe0f20", "type":"SHAPE", "id":121, "parent_id":120, edges:1, "shape_type":"IVAR","edge_name":"@platform", "memsize":120}
{"address":"0x104fe0f40", "type":"SHAPE", "id":122, "parent_id":121, edges:1, "shape_type":"IVAR","edge_name":"@rdoc_options", "memsize":120}
{"address":"0x104fe0f60", "type":"SHAPE", "id":123, "parent_id":122, edges:1, "shape_type":"IVAR","edge_name":"@require_paths", "memsize":120}
{"address":"0x104fe0f80", "type":"SHAPE", "id":124, "parent_id":123, edges:1, "shape_type":"IVAR","edge_name":"@required_ruby_version", "memsize":120}
{"address":"0x104fe0fa0", "type":"SHAPE", "id":125, "parent_id":124, edges:1, "shape_type":"IVAR","edge_name":"@required_rubygems_version", "memsize":120}
{"address":"0x104fe0fc0", "type":"SHAPE", "id":126, "parent_id":125, edges:1, "shape_type":"IVAR","edge_name":"@requirements", "memsize":120}
{"address":"0x104fe0fe0", "type":"SHAPE", "id":127, "parent_id":126, edges:1, "shape_type":"IVAR","edge_name":"@rubygems_version", "memsize":120}
{"address":"0x104fe1000", "type":"SHAPE", "id":128, "parent_id":127, edges:1, "shape_type":"IVAR","edge_name":"@specification_version", "memsize":120}
{"address":"0x104fe1020", "type":"SHAPE", "id":129, "parent_id":128, edges:1, "shape_type":"IVAR","edge_name":"@test_files", "memsize":120}
{"address":"0x104fe1040", "type":"SHAPE", "id":130, "parent_id":129, edges:1, "shape_type":"IVAR","edge_name":"@new_platform", "memsize":120}
{"address":"0x104fe1060", "type":"SHAPE", "id":131, "parent_id":5, edges:1, "shape_type":"IVAR","edge_name":"@cpu", "memsize":120}
{"address":"0x104fe1080", "type":"SHAPE", "id":132, "parent_id":131, edges:1, "shape_type":"IVAR","edge_name":"@os", "memsize":120}
{"address":"0x104fe10a0", "type":"SHAPE", "id":133, "parent_id":132, edges:0, "shape_type":"IVAR","edge_name":"@version", "memsize":32}
{"address":"0x104fe10c0", "type":"SHAPE", "id":134, "parent_id":59, edges:0, "shape_type":"IVAR","edge_name":"@prerelease", "memsize":32}
{"address":"0x104fe10e0", "type":"SHAPE", "id":135, "parent_id":130, edges:0, "shape_type":"IVAR","edge_name":"@full_name", "memsize":32}
{"address":"0x104fe1100", "type":"SHAPE", "id":136, "parent_id":59, edges:1, "shape_type":"IVAR","edge_name":"@canonical_segments", "memsize":120}
{"address":"0x104fe1120", "type":"SHAPE", "id":137, "parent_id":136, edges:1, "shape_type":"CAPACITY_CHANGE", "memsize":120}
{"address":"0x104fe1140", "type":"SHAPE", "id":138, "parent_id":137, edges:0, "shape_type":"IVAR","edge_name":"@prerelease", "memsize":32}
{"address":"0x104fe1160", "type":"SHAPE", "id":139, "parent_id":79, edges:1, "shape_type":"IVAR","edge_name":"@suffixes", "memsize":120}
{"address":"0x104fe1180", "type":"SHAPE", "id":140, "parent_id":139, edges:1, "shape_type":"IVAR","edge_name":"@suffix_regexp", "memsize":120}
{"address":"0x104fe11a0", "type":"SHAPE", "id":141, "parent_id":9, edges:1, "shape_type":"IVAR","edge_name":"@extension_dir", "memsize":120}
{"address":"0x104fe11c0", "type":"SHAPE", "id":142, "parent_id":141, edges:1, "shape_type":"IVAR","edge_name":"@full_gem_path", "memsize":120}
{"address":"0x104fe11e0", "type":"SHAPE", "id":143, "parent_id":142, edges:1, "shape_type":"IVAR","edge_name":"@gem_dir", "memsize":120}
{"address":"0x104fe1200", "type":"SHAPE", "id":144, "parent_id":143, edges:1, "shape_type":"IVAR","edge_name":"@ignored", "memsize":120}
{"address":"0x104fe1220", "type":"SHAPE", "id":145, "parent_id":144, edges:1, "shape_type":"IVAR","edge_name":"@bin_dir", "memsize":120}
{"address":"0x104fe1240", "type":"SHAPE", "id":146, "parent_id":145, edges:1, "shape_type":"IVAR","edge_name":"@cache_dir", "memsize":120}
{"address":"0x104fe1260", "type":"SHAPE", "id":147, "parent_id":146, edges:1, "shape_type":"IVAR","edge_name":"@cache_file", "memsize":120}
{"address":"0x104fe1280", "type":"SHAPE", "id":148, "parent_id":147, edges:1, "shape_type":"IVAR","edge_name":"@doc_dir", "memsize":120}
{"address":"0x104fe12a0", "type":"SHAPE", "id":149, "parent_id":148, edges:1, "shape_type":"IVAR","edge_name":"@ri_dir", "memsize":120}
{"address":"0x104fe12c0", "type":"SHAPE", "id":150, "parent_id":149, edges:1, "shape_type":"IVAR","edge_name":"@spec_dir", "memsize":120}
{"address":"0x104fe12e0", "type":"SHAPE", "id":151, "parent_id":150, edges:1, "shape_type":"IVAR","edge_name":"@spec_file", "memsize":120}
{"address":"0x104fe1300", "type":"SHAPE", "id":152, "parent_id":151, edges:1, "shape_type":"IVAR","edge_name":"@gems_dir", "memsize":120}
{"address":"0x104fe1320", "type":"SHAPE", "id":153, "parent_id":152, edges:1, "shape_type":"IVAR","edge_name":"@base_dir", "memsize":120}
{"address":"0x104fe1340", "type":"SHAPE", "id":154, "parent_id":153, edges:1, "shape_type":"IVAR","edge_name":"@loaded", "memsize":120}
{"address":"0x104fe1360", "type":"SHAPE", "id":155, "parent_id":154, edges:1, "shape_type":"IVAR","edge_name":"@activated", "memsize":120}
{"address":"0x104fe1380", "type":"SHAPE", "id":156, "parent_id":155, edges:1, "shape_type":"IVAR","edge_name":"@loaded_from", "memsize":120}
{"address":"0x104fe13a0", "type":"SHAPE", "id":157, "parent_id":156, edges:1, "shape_type":"IVAR","edge_name":"@original_platform", "memsize":120}
{"address":"0x104fe13c0", "type":"SHAPE", "id":158, "parent_id":157, edges:1, "shape_type":"IVAR","edge_name":"@installed_by_version", "memsize":120}
{"address":"0x104fe13e0", "type":"SHAPE", "id":159, "parent_id":158, edges:1, "shape_type":"IVAR","edge_name":"@autorequire", "memsize":120}
{"address":"0x104fe1400", "type":"SHAPE", "id":160, "parent_id":159, edges:1, "shape_type":"IVAR","edge_name":"@date", "memsize":120}
{"address":"0x104fe1420", "type":"SHAPE", "id":161, "parent_id":160, edges:1, "shape_type":"IVAR","edge_name":"@description", "memsize":120}
{"address":"0x104fe1440", "type":"SHAPE", "id":162, "parent_id":161, edges:1, "shape_type":"IVAR","edge_name":"@email", "memsize":120}
{"address":"0x104fe1460", "type":"SHAPE", "id":163, "parent_id":162, edges:1, "shape_type":"IVAR","edge_name":"@homepage", "memsize":120}
{"address":"0x104fe1480", "type":"SHAPE", "id":164, "parent_id":163, edges:1, "shape_type":"IVAR","edge_name":"@name", "memsize":120}
{"address":"0x104fe14a0", "type":"SHAPE", "id":165, "parent_id":164, edges:1, "shape_type":"IVAR","edge_name":"@post_install_message", "memsize":120}
{"address":"0x104fe14c0", "type":"SHAPE", "id":166, "parent_id":165, edges:1, "shape_type":"IVAR","edge_name":"@signing_key", "memsize":120}
{"address":"0x104fe14e0", "type":"SHAPE", "id":167, "parent_id":166, edges:1, "shape_type":"IVAR","edge_name":"@summary", "memsize":120}
{"address":"0x104fe1500", "type":"SHAPE", "id":168, "parent_id":167, edges:1, "shape_type":"IVAR","edge_name":"@version", "memsize":120}
{"address":"0x104fe1520", "type":"SHAPE", "id":169, "parent_id":168, edges:1, "shape_type":"IVAR","edge_name":"@authors", "memsize":120}
{"address":"0x104fe1540", "type":"SHAPE", "id":170, "parent_id":169, edges:1, "shape_type":"IVAR","edge_name":"@bindir", "memsize":120}
{"address":"0x104fe1560", "type":"SHAPE", "id":171, "parent_id":170, edges:1, "shape_type":"IVAR","edge_name":"@cert_chain", "memsize":120}
{"address":"0x104fe1580", "type":"SHAPE", "id":172, "parent_id":171, edges:1, "shape_type":"IVAR","edge_name":"@dependencies", "memsize":120}
{"address":"0x104fe15a0", "type":"SHAPE", "id":173, "parent_id":172, edges:1, "shape_type":"IVAR","edge_name":"@executables", "memsize":120}
{"address":"0x104fe15c0", "type":"SHAPE", "id":174, "parent_id":173, edges:1, "shape_type":"IVAR","edge_name":"@extensions", "memsize":120}
{"address":"0x104fe15e0", "type":"SHAPE", "id":175, "parent_id":174, edges:1, "shape_type":"IVAR","edge_name":"@extra_rdoc_files", "memsize":120}
{"address":"0x104fe1600", "type":"SHAPE", "id":176, "parent_id":175, edges:1, "shape_type":"IVAR","edge_name":"@files", "memsize":120}
{"address":"0x104fe1620", "type":"SHAPE", "id":177, "parent_id":176, edges:1, "shape_type":"IVAR","edge_name":"@licenses", "memsize":120}
{"address":"0x104fe1640", "type":"SHAPE", "id":178, "parent_id":177, edges:1, "shape_type":"IVAR","edge_name":"@metadata", "memsize":120}
{"address":"0x104fe1660", "type":"SHAPE", "id":179, "parent_id":178, edges:1, "shape_type":"IVAR","edge_name":"@platform", "memsize":120}
{"address":"0x104fe1680", "type":"SHAPE", "id":180, "parent_id":179, edges:1, "shape_type":"IVAR","edge_name":"@rdoc_options", "memsize":120}
{"address":"0x104fe16a0", "type":"SHAPE", "id":181, "parent_id":180, edges:1, "shape_type":"IVAR","edge_name":"@require_paths", "memsize":120}
{"address":"0x104fe16c0", "type":"SHAPE", "id":182, "parent_id":181, edges:1, "shape_type":"IVAR","edge_name":"@required_ruby_version", "memsize":120}
{"address":"0x104fe16e0", "type":"SHAPE", "id":183, "parent_id":182, edges:1, "shape_type":"IVAR","edge_name":"@required_rubygems_version", "memsize":120}
{"address":"0x104fe1700", "type":"SHAPE", "id":184, "parent_id":183, edges:1, "shape_type":"IVAR","edge_name":"@requirements", "memsize":120}
{"address":"0x104fe1720", "type":"SHAPE", "id":185, "parent_id":184, edges:1, "shape_type":"IVAR","edge_name":"@rubygems_version", "memsize":120}
{"address":"0x104fe1740", "type":"SHAPE", "id":186, "parent_id":185, edges:1, "shape_type":"IVAR","edge_name":"@specification_version", "memsize":120}
{"address":"0x104fe1760", "type":"SHAPE", "id":187, "parent_id":186, edges:1, "shape_type":"IVAR","edge_name":"@test_files", "memsize":120}
{"address":"0x104fe1780", "type":"SHAPE", "id":188, "parent_id":187, edges:1, "shape_type":"IVAR","edge_name":"@new_platform", "memsize":120}
{"address":"0x104fe17a0", "type":"SHAPE", "id":189, "parent_id":6, edges:1, "shape_type":"IVAR","edge_name":"@version", "memsize":120}
{"address":"0x104fe17c0", "type":"SHAPE", "id":190, "parent_id":189, edges:2, "shape_type":"IVAR","edge_name":"@segments", "memsize":120}
{"address":"0x104fe17e0", "type":"SHAPE", "id":191, "parent_id":190, edges:0, "shape_type":"IVAR","edge_name":"@prerelease", "memsize":32}
{"address":"0x104fe1800", "type":"SHAPE", "id":192, "parent_id":188, edges:0, "shape_type":"IVAR","edge_name":"@full_name", "memsize":32}
{"address":"0x104fe1820", "type":"SHAPE", "id":193, "parent_id":190, edges:1, "shape_type":"IVAR","edge_name":"@canonical_segments", "memsize":120}
{"address":"0x104fe1840", "type":"SHAPE", "id":194, "parent_id":193, edges:0, "shape_type":"IVAR","edge_name":"@prerelease", "memsize":32}
{"address":"0x104fe1860", "type":"SHAPE", "id":195, "parent_id":6, edges:1, "shape_type":"IVAR","edge_name":"@name", "memsize":120}
{"address":"0x104fe1880", "type":"SHAPE", "id":196, "parent_id":195, edges:1, "shape_type":"IVAR","edge_name":"@requirement", "memsize":120}
{"address":"0x104fe18a0", "type":"SHAPE", "id":197, "parent_id":196, edges:1, "shape_type":"IVAR","edge_name":"@type", "memsize":120}
{"address":"0x104fe18c0", "type":"SHAPE", "id":198, "parent_id":197, edges:1, "shape_type":"IVAR","edge_name":"@prerelease", "memsize":120}
{"address":"0x104fe18e0", "type":"SHAPE", "id":199, "parent_id":198, edges:0, "shape_type":"IVAR","edge_name":"@version_requirements", "memsize":32}
{"address":"0x104fe1900", "type":"SHAPE", "id":200, "parent_id":140, edges:1, "shape_type":"IVAR","edge_name":"@default_gem_load_paths", "memsize":120}
{"address":"0x104fe1920", "type":"SHAPE", "id":201, "parent_id":200, edges:0, "shape_type":"IVAR","edge_name":"@activated_gem_paths", "memsize":32}
{"address":"0x104fe1940", "type":"SHAPE", "id":202, "parent_id":70, edges:0, "shape_type":"IVAR","edge_name":"@unresolved_deps", "memsize":32}
{"address":"0x104fe1960", "type":"SHAPE", "id":203, "parent_id":12, edges:0, "shape_type":"IVAR","edge_name":"@spell_checkers", "memsize":32}
{"address":"0x104fe1980", "type":"SHAPE", "id":204, "parent_id":5, edges:1, "shape_type":"IVAR","edge_name":"@a", "memsize":120}
{"address":"0x104fe19a0", "type":"SHAPE", "id":205, "parent_id":204, edges:1, "shape_type":"IVAR","edge_name":"@b", "memsize":120}
{"address":"0x104fe19c0", "type":"SHAPE", "id":206, "parent_id":205, edges:1, "shape_type":"IVAR","edge_name":"@c", "memsize":120}
{"address":"0x104fe19e0", "type":"SHAPE", "id":207, "parent_id":206, edges:1, "shape_type":"CAPACITY_CHANGE", "memsize":120}
{"address":"0x104fe1a00", "type":"SHAPE", "id":208, "parent_id":207, edges:1, "shape_type":"IVAR","edge_name":"@foo", "memsize":120}
{"address":"0x104fe1a20", "type":"SHAPE", "id":209, "parent_id":208, edges:0, "shape_type":"IVAR","edge_name":"@bar", "memsize":32}
{"address":"0x104fe1a40", "type":"SHAPE", "id":210, "parent_id":6, edges:1, "shape_type":"IVAR","edge_name":"@a", "memsize":120}
{"address":"0x104fe1a60", "type":"SHAPE", "id":211, "parent_id":210, edges:1, "shape_type":"IVAR","edge_name":"@b", "memsize":120}
{"address":"0x104fe1a80", "type":"SHAPE", "id":212, "parent_id":211, edges:1, "shape_type":"IVAR","edge_name":"@c", "memsize":120}
{"address":"0x104fe1aa0", "type":"SHAPE", "id":213, "parent_id":212, edges:1, "shape_type":"IVAR","edge_name":"@bar", "memsize":120}
{"address":"0x104fe1ac0", "type":"SHAPE", "id":214, "parent_id":213, edges:0, "shape_type":"IVAR","edge_name":"@foo", "memsize":32}
{"address":"0x106b90120", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x10603e880", "imemo_type":"callcache", "references":["0x106a31bd0"], "file":"/tmp/dump-shapes.rb", "line":32, "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b920b0", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x10603eb00", "imemo_type":"constcache", "file":"/tmp/dump-shapes.rb", "line":22, "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b950d0", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x10603e600", "imemo_type":"callcache", "references":["0x104f7e900"], "file":"/tmp/dump-shapes.rb", "line":22, "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b96908", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x106b76040", "imemo_type":"constcache", "file":"/tmp/dump-shapes.rb", "line":24, "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b971c8", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x106b75fa0", "imemo_type":"callcache", "references":["0x104fdd220"], "file":"/tmp/dump-shapes.rb", "line":24, "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b98ac8", "type":"OBJECT", "shape_id":209, "slot_size":40, "class":"0x106b76040", "ivars":6, "file":"/tmp/dump-shapes.rb", "line":24, "method":"new", "generation":9, "memsize":88, "flags":{"wb_protected":true}}
{"address":"0x106b999c8", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x106b76040", "imemo_type":"callcache", "references":["0x106a31338"], "file":"/tmp/dump-shapes.rb", "line":24, "method":"new", "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b9aaa8", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x106b76040", "imemo_type":"callcache", "references":["0x106a31248"], "file":"/tmp/dump-shapes.rb", "line":25, "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b9bf70", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x106b76040", "imemo_type":"callcache", "references":["0x106a31220"], "file":"/tmp/dump-shapes.rb", "line":26, "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b9c290", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x106b76040", "imemo_type":"constcache", "file":"/tmp/dump-shapes.rb", "line":28, "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b9dff0", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x10603e920", "imemo_type":"constcache", "file":"/tmp/dump-shapes.rb", "line":32, "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b9e040", "type":"DATA", "shape_id":0, "slot_size":40, "class":"0x10603c440", "struct":"mutex", "file":"/Users/byroot/src/github.com/Shopify/ruby/.ext/common/objspace.rb", "line":87, "method":"_dump_all", "generation":9, "memsize":72, "flags":{"wb_protected":true}}
{"address":"0x106b9e068", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x10603e880", "imemo_type":"callcache", "references":["0x106a341f0"], "file":"/Users/byroot/src/github.com/Shopify/ruby/.ext/common/objspace.rb", "line":87, "method":"dump_all", "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b9e090", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x106011c40", "imemo_type":"callcache", "references":["0x104fddb30"], "file":"/Users/byroot/src/github.com/Shopify/ruby/.ext/common/objspace.rb", "line":81, "method":"dump_all", "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b9e108", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x106011ce0", "imemo_type":"constcache", "file":"/Users/byroot/src/github.com/Shopify/ruby/.ext/common/objspace.rb", "line":81, "method":"dump_all", "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b9e158", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x10601eb20", "imemo_type":"callcache", "references":["0x104fd8ce8"], "file":"/Users/byroot/src/github.com/Shopify/ruby/.ext/common/objspace.rb", "line":74, "method":"dump_all", "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b9f7d8", "type":"IMEMO", "shape_id":0, "slot_size":40, "class":"0x104fb98c0", "imemo_type":"constcache", "file":"/tmp/dump-shapes.rb", "line":32, "generation":9, "memsize":40, "flags":{"wb_protected":true}}
{"address":"0x106b5ff20", "type":"OBJECT", "shape_id":214, "slot_size":80, "class":"0x106b76040", "ivars":8, "file":"/tmp/dump-shapes.rb", "line":28, "method":"new", "generation":9, "memsize":80, "flags":{"wb_protected":true}}
----------------------------------------
f1: {"address":"0x106b98ac8", "type":"OBJECT", "shape_id":209, "slot_size":40, "class":"0x106b76040", "ivars":6, "file":"/tmp/dump-shapes.rb", "line":24, "method":"new", "generation":9, "memsize":88, "flags":{"wb_protected":true}}
f2: {"address":"0x106b5ff20", "type":"OBJECT", "shape_id":214, "slot_size":80, "class":"0x106b76040", "ivars":8, "file":"/tmp/dump-shapes.rb", "line":28, "method":"new", "generation":9, "memsize":80, "flags":{"wb_protected":true}}
[#<RubyVM::Shape:0x0000000106b90990>, 209, 1, 7, {}]

@jemmaissroff @tenderlove @k0kubun I'd love to hear your opinion on this.

@casperisfine casperisfine force-pushed the objspace-dump-all-shapes branch from 2221805 to 072c353 Compare December 6, 2022 12:18
@casperisfine
Copy link
Contributor Author

I ran heap-profiler again a full dump of that test script. It just needed a small fix to handle shapes:

memory by class
-----------------------------------
   1.01 MB  <iseq> (IMEMO)
 561.94 kB  String
 552.23 kB  RubyVM
 327.22 kB  Class
 166.66 kB  <ment> (IMEMO)
 154.51 kB  Array
 101.22 kB  Hash
  49.52 kB  Regexp
  45.39 kB  Gem::Specification
  31.09 kB  Module
  27.00 kB  <callcache> (IMEMO)
  23.34 kB  SHAPE
  17.38 kB  File
   8.23 kB  ICLASS
   7.20 kB  <cref> (IMEMO)
...

casperisfine pushed a commit to Shopify/heap-profiler that referenced this pull request Dec 6, 2022
@casperisfine casperisfine force-pushed the objspace-dump-all-shapes branch 2 times, most recently from 40edcdd to 32579f4 Compare December 6, 2022 12:53
@tenderlove
Copy link
Member

@byroot @jemmaissroff and I were working on the same thing (but you beat us to opening a PR). I think this is a good idea.

If RubyVM::Shape.next_shape_id was available on all builds, we could use that as a cursor for differential dumps.

I added RubyVM.stat(:next_shape_id) in all builds, so I think we're good here.

Maybe it would make more sense to have a separate ObjectSpace.dump_shapes?

We had this considered this too, but since the JSON is basically backwards compatible, I figured it's fine to add to the normal dump. Jemma and I added the shape id for each object in #6864, so I think it makes sense to combine the normal heap dump with shape information.

Maybe instead dump_all should take a shapes: false argument?

Seems fine to me.

@byroot
Copy link
Member

byroot commented Dec 6, 2022

Sounds good, then I guess I only need to add an argument for partial dump of shapes, I can do that tomorrow.

@byroot
Copy link
Member

byroot commented Dec 6, 2022

I just realized we shouldn't dump the parent_id on the root shape:

"id":0, "parent_id":4294967295, edges:6, "shape_type":"ROOT"

Copy link
Contributor

@jemmaissroff jemmaissroff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this!

@jemmaissroff
Copy link
Contributor

jemmaissroff commented Dec 6, 2022

Thanks for this! Incidentally, we started working on this exact same idea EOD yesterday.

To answer your questions:

  • Shapes can't respect the since: argument. Not sure what to do when it is provided. Would probably make sense to not dump them.

Agreed.

  • If RubyVM::Shape.next_shape_id was available on all builds, we could use that as a cursor for differential dumps.

@tenderlove added it to vm stats in #6798!

  • Maybe it would make more sense to have a separate ObjectSpace.dump_shapes?

We thought about this question yesterday too. It seems like because ROOT is in ObjectSpace.dump_all, there's a bit of a precedent set already to include shapes in ObjectSpace.dump_all too. That said, I think extracting an ObjectSpace.dump_shapes is also fine.

  • Maybe instead dump_all should take a shapes: false argument?

If we don't go with the ObjectSpace.dump_shapes solution, I agree this would make sense.

@byroot
Copy link
Member

byroot commented Dec 6, 2022

we started working on this exact same idea EOD yesterday.

Sorry for the duplicated work, I guess we got startled by the same growing shape count report 😄.

BTW I think this PR is already in a good enough state to debug that issue @k0kubun, if you wanna try it?

@k0kubun
Copy link
Member

k0kubun commented Dec 6, 2022

BTW I think this PR is already in a good enough state to debug that issue @k0kubun, if you wanna try it?

Ah yes, I'd love to try it. How do you intend to use this on our app? Just sending an entire dump to the log storage on the Rack middleware?

@casperisfine casperisfine force-pushed the objspace-dump-all-shapes branch from 32579f4 to 64a8ce0 Compare December 6, 2022 18:43
@jemmaissroff
Copy link
Contributor

Sorry for the duplicated work, I guess we got startled by the same growing shape count report 😄.

No worries at all! And I didn't notice Aaron had already commented above too so more duplication 🤦‍♀️

@casperisfine
Copy link
Contributor Author

So after experimenting with this, I think one interesting field missing is depth, I'll add it tomorrow.

@casperisfine casperisfine force-pushed the objspace-dump-all-shapes branch 9 times, most recently from 6a0dc17 to f169ea9 Compare December 7, 2022 12:42
@@ -44,6 +44,8 @@ enum ruby_id_types {
#define ID_JUNK RUBY_ID_JUNK
#define ID_INTERNAL RUBY_ID_INTERNAL

#define ID_INTERNAL_P(id) ((id & RUBY_ID_SCOPE_MASK) == RUBY_ID_INTERNAL)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I extracted this so at least it feels a bit less dirty to check for internal ids.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it already exists in symbol.h as is_junk_id().

@casperisfine casperisfine force-pushed the objspace-dump-all-shapes branch from f169ea9 to 0159e1e Compare December 7, 2022 13:27
@casperisfine
Copy link
Contributor Author

Hum, I still have a segfault when printing edge_name, but only in the suite that run tests twice. So I assume there is some other edge case we haven't figured that is triggered by another test in the suite.

I don't think I'll have much more time to debug this tonight.

@casperisfine casperisfine force-pushed the objspace-dump-all-shapes branch from 0159e1e to 0ca146a Compare December 7, 2022 17:15
@casperisfine casperisfine force-pushed the objspace-dump-all-shapes branch from 0ca146a to 49b634f Compare December 7, 2022 17:21
shape.c Outdated
@@ -196,6 +209,7 @@ rb_shape_transition_shape_frozen(VALUE obj)
rb_shape_t *
rb_shape_get_next_iv_shape(rb_shape_t* shape, ID id)
{
RUBY_ASSERT(is_junk_id(id) || RTEST(rb_sym2str(ID2SYM(id))));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this helped crash when the unexpected IDs are set:

  -- C level backtrace information -------------------------------------------
  /home/runner/work/ruby/ruby/build/ruby(rb_print_backtrace+0x818) [0x55e04d7b1eb8] ../src/vm_dump.c:770
  /home/runner/work/ruby/ruby/build/ruby(rb_vm_bugreport) ../src/vm_dump.c:1065
  /home/runner/work/ruby/ruby/src/tool/lib/test/unit/parallel.rb: TestRubyLiteral#test_debug_frozen_string_in_array_literal(rb_assert_failure+0x77) [0x55e04d5bb0b2]
  /home/runner/work/ruby/ruby/build/ruby(rb_shape_get_next_iv_shape+0x1f) [0x55e04d5a50e8] ../src/shape.c:212
  /home/runner/work/ruby/ruby/build/ruby(rb_multi_ractor_p) ../src/shape.c:210
  /home/runner/work/ruby/ruby/build/ruby(rb_vm_lock_enter) ../src/vm_sync.h:74
  /home/runner/work/ruby/ruby/build/ruby(get_next_shape_internal) ../src/shape.c:122
  /home/runner/work/ruby/ruby/build/ruby(rb_shape_get_next_iv_shape) ../src/shape.c:213
  /home/runner/work/ruby/ruby/build/ruby(rb_shape_get_next) ../src/shape.c:219
  /home/runner/work/ruby/ruby/build/ruby(generic_ivar_set+0x1ae) [0x55e04d77ab0e] ../src/variable.c:1286
  /home/runner/work/ruby/ruby/build/ruby(ivar_set) ../src/variable.c:1547
  /home/runner/work/ruby/ruby/build/ruby(rb_ivar_set) ../src/variable.c:1556
  /home/runner/work/ruby/ruby/build/ruby(compile_array+0x531) [0x55e04d90e101]
  /home/runner/work/ruby/ruby/build/ruby(iseq_compile_each0+0x261e) [0x55e04d9099ae]

The ID in question seem to be id_debug_created_info, which I can't really figure out what type it is.

I could use some help, but I think RUBY_ID_INTERNAL is far from covering all ids we shouldn't try to map to a string.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id_debug_created_info looks like one of those special ids that is < tLAST_OP_ID, if that helps at all. is_notop_id checks for those.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just some value in an enum. There is no associated string for that particular ID. Not all IDs have string representations, so we need to dump something else as the edge name.

It's defined in id.h. Unfortunately that file is generated, but you can find the source for it here.

When we derive the key name, we should probably look at the shape type. Only IVAR shapes will have an edge name that may have a string representation, but it's not guaranteed. As @composerinteralia, I think is_notop_id is the right check.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We looked through id.def and id.c.tmpl and it looks like id_debug_created_info is the only id that works like this 😓. It's defined in id.def to be -, which carries the special meaning that it has no defined string which looks like it was done to hide them from marshal, which skips them by just checking if there is a string associated.

The easiest path forward is probably to duplicate that check and skip any id where !rb_id2str(id);

In the future we might consider having a different way for marshal to skip undesirable ivars (I'd be interested in looking into this, but not so close to release 😅).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, if we wanted to be conservative we could print out only ids where is_instance_id(x) (only the ones which start with an @), we might miss some internal things, but that should be really safe to do (and since this is for debugging we may not need it perfect)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I tried a few more things, but ultimately ended up using is_instance_id like you suggested. Thanks for the help!

@casperisfine casperisfine force-pushed the objspace-dump-all-shapes branch 3 times, most recently from 60b750f to 436e025 Compare December 8, 2022 08:52
I see several arguments in doing so.

First they use a non trivial amount of memory, so for various memory
profiling/mapping tools it is relevant to have visibility of the space
occupied by shapes.

Then, some pathological code can create a tons of shape, so it is
valuable to have a way to have a way to observe shapes without having
to compile Ruby with `SHAPE_DEBUG=1`.

And additionally it's likely much faster to dump then this way than
to use `RubyVM::Shape`.

There are however a few open questions:

- Shapes can't respect the `since:` argument. Not sure what to do when
  it is provided. Would probably make sense to not dump them.
- Maybe it would make more sense to have a separate `ObjectSpace.dump_shapes`?
- Maybe instead `dump_all` should take a `shapes: false` argument?

Additionally, `ObjectSpace.dump_shapes` is added for the use case of
debugging the evolution of the shape tree.
@casperisfine casperisfine force-pushed the objspace-dump-all-shapes branch from 436e025 to a986aa5 Compare December 8, 2022 09:06
@casperisfine
Copy link
Contributor Author

I think this is good to go now. Anyone wants to review?

Copy link
Contributor

@jemmaissroff jemmaissroff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM, thanks for writing! (I don't have approve permissions)

@byroot byroot merged commit 73771e4 into ruby:master Dec 8, 2022
@jhawthorn
Copy link
Member

Tested and working in our app 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants