diff options
author | Peter Zhu <peter@peterzhu.ca> | 2023-07-31 09:24:48 -0400 |
---|---|---|
committer | Peter Zhu <peter@peterzhu.ca> | 2023-07-31 11:46:53 -0400 |
commit | b98838b65cbf8fa2d228f9e0249414cba4e3197d (patch) | |
tree | 342e39f04c293d898f0d0e7d1d2997df30cb8fe7 /test/ruby | |
parent | 1bda22f5fedea5364c6df321a3004c47c732144e (diff) | |
download | ruby-b98838b65cbf8fa2d228f9e0249414cba4e3197d.tar.gz |
Store initial slots per size pool
This commit stores the initial slots per size pool, configured with
the environment variables `RUBY_GC_HEAP_INIT_SIZE_%d_SLOTS`. This
ensures that the configured initial slots remains a low bound for the
number of slots in the heap, which can prevent heaps from thrashing in
size.
Diffstat (limited to 'test/ruby')
-rw-r--r-- | test/ruby/test_gc.rb | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb index 640c5c6340..811ab3edad 100644 --- a/test/ruby/test_gc.rb +++ b/test/ruby/test_gc.rb @@ -399,6 +399,60 @@ class TestGc < Test::Unit::TestCase end end + def test_gc_parameter_init_slots + assert_separately(["--disable-gems"], __FILE__, __LINE__, <<~RUBY) + # Constant from gc.c. + GC_HEAP_INIT_SLOTS = 10_000 + GC.stat_heap.each do |_, s| + # Sometimes pages will have 1 less slot due to alignment, so always increase slots_per_page by 1. + slots_per_page = (s[:heap_eden_slots] / s[:heap_eden_pages]) + 1 + total_slots = s[:heap_eden_slots] + s[:heap_allocatable_pages] * slots_per_page + # Give a 0.9x delta because integer division in minimum_pages_for_size_pool can sometimes cause number to be + # less than GC_HEAP_INIT_SLOTS. + assert_operator(total_slots, :>=, GC_HEAP_INIT_SLOTS * 0.9, s) + end + RUBY + + env = {} + # Make the heap big enough to ensure the heap never needs to grow. + sizes = GC.stat_heap.keys.reverse.map { |i| (i + 1) * 100_000 } + GC.stat_heap.each do |i, s| + env["RUBY_GC_HEAP_INIT_SIZE_#{s[:slot_size]}_SLOTS"] = sizes[i].to_s + end + assert_separately([env, "-W0", "--disable-gems"], __FILE__, __LINE__, <<~RUBY) + SIZES = #{sizes} + GC.stat_heap.each do |i, s| + # Sometimes pages will have 1 less slot due to alignment, so always increase slots_per_page by 1. + slots_per_page = (s[:heap_eden_slots] / s[:heap_eden_pages]) + 1 + total_slots = s[:heap_eden_slots] + s[:heap_allocatable_pages] * slots_per_page + assert_in_epsilon(SIZES[i], total_slots, 0.01, s) + end + RUBY + + # Check that the configured sizes are "remembered" across GC invocations. + assert_separately([env, "-W0", "--disable-gems"], __FILE__, __LINE__, <<~RUBY) + SIZES = #{sizes} + + # Fill size pool 0 with transient objects. + ary = [] + while GC.stat_heap(0, :heap_allocatable_pages) != 0 + ary << Object.new + end + ary = nil + + # Clear all the objects that were allocated. + GC.start + + # Check that we still have the same number of slots as initially configured. + GC.stat_heap.each do |i, s| + # Sometimes pages will have 1 less slot due to alignment, so always increase slots_per_page by 1. + slots_per_page = (s[:heap_eden_slots] / s[:heap_eden_pages]) + 1 + total_slots = s[:heap_eden_slots] + s[:heap_allocatable_pages] * slots_per_page + assert_in_epsilon(SIZES[i], total_slots, 0.01, s) + end + RUBY + end + def test_profiler_enabled GC::Profiler.enable assert_equal(true, GC::Profiler.enabled?) |