diff options
author | Jean Boussier <byroot@ruby-lang.org> | 2023-02-03 09:46:14 +0100 |
---|---|---|
committer | Jean Boussier <jean.boussier@gmail.com> | 2023-02-08 09:26:07 +0100 |
commit | 3ab34551450c7a3a3e1ae0b24bf6b78d26129dfa (patch) | |
tree | 274efe5d1465b8d65866002f1c74f7cb59a08b04 | |
parent | 6e7990144f37850b9b3ec871956890e2aa29ad6d (diff) |
Add RUBY_GC_HEAP_INIT_SIZE_%d_SLOTS to pre-init pools granularly
The old RUBY_GC_HEAP_INIT_SLOTS isn't really usable anymore as
it initalize all the pools by the same factor, but it's unlikely
that pools will need similar sizes.
In production our 40B pool is 5 to 6 times bigger than our 80B pool.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/7235
-rw-r--r-- | gc.c | 24 | ||||
-rw-r--r-- | man/ruby.1 | 7 | ||||
-rw-r--r-- | test/ruby/test_gc.rb | 15 |
3 files changed, 41 insertions, 5 deletions
@@ -11749,15 +11749,28 @@ get_envparam_double(const char *name, double *default_value, double lower_bound, } static void -gc_set_initial_pages(rb_objspace_t *objspace) +gc_set_initial_pages(rb_objspace_t *objspace, int global_heap_init_slots) { gc_rest(objspace); for (int i = 0; i < SIZE_POOL_COUNT; i++) { rb_size_pool_t *size_pool = &size_pools[i]; + char env_key[sizeof("RUBY_GC_HEAP_INIT_SIZE_" "_SLOTS") + DECIMAL_SIZE_OF_BITS(sizeof(size_pool->slot_size) * CHAR_BIT)]; + snprintf(env_key, sizeof(env_key), "RUBY_GC_HEAP_INIT_SIZE_%d_SLOTS", size_pool->slot_size); - if (gc_params.heap_init_slots > size_pool->eden_heap.total_slots) { - size_t slots = gc_params.heap_init_slots - size_pool->eden_heap.total_slots; + size_t pool_init_slots = 0; + if (!get_envparam_size(env_key, &pool_init_slots, 0)) { + if (global_heap_init_slots) { + // If we use the global init slot we ponderate it by slot size + pool_init_slots = gc_params.heap_init_slots / (size_pool->slot_size / BASE_SLOT_SIZE); + } + else { + continue; + } + } + + if (pool_init_slots > size_pool->eden_heap.total_slots) { + size_t slots = pool_init_slots - size_pool->eden_heap.total_slots; int multiple = size_pool->slot_size / BASE_SLOT_SIZE; size_pool->allocatable_pages = slots * multiple / HEAP_PAGE_OBJ_LIMIT; } @@ -11823,7 +11836,10 @@ ruby_gc_set_params(void) /* RUBY_GC_HEAP_INIT_SLOTS */ if (get_envparam_size("RUBY_GC_HEAP_INIT_SLOTS", &gc_params.heap_init_slots, 0)) { - gc_set_initial_pages(objspace); + gc_set_initial_pages(objspace, TRUE); + } + else { + gc_set_initial_pages(objspace, FALSE); } get_envparam_double("RUBY_GC_HEAP_GROWTH_FACTOR", &gc_params.growth_factor, 1.0, 0.0, FALSE); diff --git a/man/ruby.1 b/man/ruby.1 index 86ad73c2ab..779167ac3e 100644 --- a/man/ruby.1 +++ b/man/ruby.1 @@ -550,7 +550,12 @@ There are currently 4 possible areas where the GC may be tuned by the following 11 environment variables: .Bl -hang -compact -width "RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR" .It Ev RUBY_GC_HEAP_INIT_SLOTS -Initial allocation slots. Introduced in Ruby 2.1, default: 10000. +Initial allocation slots. Applies to all slot sizes. Introduced in Ruby 2.1, default: 10000. +.Pp +.It Ev RUBY_GC_HEAP_INIT_SIZE_%d_SLOTS +Initial allocation of slots in a specific size pool. +The available size pools can be found in `GC.stat_heap`. +Introduced in Ruby 3.3. .Pp .It Ev RUBY_GC_HEAP_FREE_SLOTS Prepare at least this amount of slots after GC. diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb index 64125ea35b..0e3a3b4e1c 100644 --- a/test/ruby/test_gc.rb +++ b/test/ruby/test_gc.rb @@ -315,6 +315,21 @@ class TestGc < Test::Unit::TestCase } assert_normal_exit("exit", "[ruby-core:39777]", :child_env => env) + env = {} + GC.stat_heap.each do |_, s| + env["RUBY_GC_HEAP_INIT_SIZE_#{s[:slot_size]}_SLOTS"] = "200000" + end + assert_normal_exit("exit", "", :child_env => env) + + env["RUBY_GC_HEAP_INIT_SLOTS"] = "100000" + assert_normal_exit("exit", "", :child_env => env) + + env = {} + GC.stat_heap.each do |_, s| + env["RUBY_GC_HEAP_INIT_SIZE_#{s[:slot_size]}_SLOTS"] = "0" + end + assert_normal_exit("exit", "", :child_env => env) + env = { "RUBYOPT" => "", "RUBY_GC_HEAP_INIT_SLOTS" => "100000" |