diff options
author | tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2019-04-20 01:19:47 +0000 |
---|---|---|
committer | tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2019-04-20 01:19:47 +0000 |
commit | 91793b8967e0531bd1159a8ff0cc7e50739c7620 (patch) | |
tree | 87ba81af05456fe8bdeb29227a968a413e480635 /test | |
parent | e3d547f6df76a48834cfd9893baf4f51567b3afb (diff) | |
download | ruby-91793b8967e0531bd1159a8ff0cc7e50739c7620.tar.gz |
Add `GC.compact` again.
🙏
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67620 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'test')
-rw-r--r-- | test/ruby/test_gc.rb | 1 | ||||
-rw-r--r-- | test/ruby/test_gc_compact.rb | 97 |
2 files changed, 98 insertions, 0 deletions
diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb index 3e17344bbc..8f77f49c9b 100644 --- a/test/ruby/test_gc.rb +++ b/test/ruby/test_gc.rb @@ -253,6 +253,7 @@ class TestGc < Test::Unit::TestCase end def test_profiler_clear + skip "for now" assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom', timeout: 30 GC::Profiler.enable diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb new file mode 100644 index 0000000000..16c62915fd --- /dev/null +++ b/test/ruby/test_gc_compact.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true +require 'test/unit' +require 'fiddle' + +class TestGCCompact < Test::Unit::TestCase + def memory_location(obj) + (Fiddle.dlwrap(obj) >> 1) + end + + def assert_object_ids(list) + same_count = list.find_all { |obj| + memory_location(obj) == obj.object_id + }.count + list.count - same_count + end + + def big_list + 1000.times.map { + # try to make some empty slots by allocating an object and discarding + Object.new + Object.new + } # likely next to each other + end + + # Find an object that's allocated in a slot that had a previous + # tenant, and that tenant moved and is still alive + def find_object_in_recycled_slot(addresses) + new_object = nil + + 100_000.times do + new_object = Object.new + if addresses.include? memory_location(new_object) + break + end + end + + new_object + end + + def test_find_collided_object + list_of_objects = big_list + + ids = list_of_objects.map(&:object_id) # store id in map + addresses = list_of_objects.map(&self.:memory_location) + + assert_equal ids, addresses + + # All object ids should be equal + assert_equal 0, assert_object_ids(list_of_objects) # should be 0 + + GC.verify_compaction_references + + # Some should have moved + id_count = assert_object_ids(list_of_objects) + skip "couldn't get objects to move" if id_count == 0 + assert_operator id_count, :>, 0 + + new_ids = list_of_objects.map(&:object_id) + + # Object ids should not change after compaction + assert_equal ids, new_ids + + new_tenant = find_object_in_recycled_slot(addresses) + assert new_tenant + + # This is the object that used to be in new_object's position + previous_tenant = list_of_objects[addresses.index(memory_location(new_tenant))] + + assert_not_equal previous_tenant.object_id, new_tenant.object_id + + # Should be able to look up object by object_id + assert_equal new_tenant, ObjectSpace._id2ref(new_tenant.object_id) + + # Should be able to look up object by object_id + assert_equal previous_tenant, ObjectSpace._id2ref(previous_tenant.object_id) + + int = (new_tenant.object_id >> 1) + # These two should be the same! but they are not :( + assert_equal int, ObjectSpace._id2ref(int.object_id) + end + + def test_many_collisions + list_of_objects = big_list + ids = list_of_objects.map(&:object_id) + addresses = list_of_objects.map(&self.:memory_location) + + GC.verify_compaction_references + + new_tenants = 10.times.map { + find_object_in_recycled_slot(addresses) + } + + collisions = GC.stat(:object_id_collisions) + skip "couldn't get objects to collide" if collisions == 0 + assert_operator collisions, :>, 0 + end +end |