From 9e51e0be59a8821061d5469be2d10d48b3b606d7 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Tue, 21 Feb 2023 12:38:25 +0100 Subject: [PATCH] Process.warmup: precompute strings coderange This both save time for when it will be eventually needed, and avoid mutating heap pages after a potential fork. Instrumenting some large Rails app, I've witnessed up to 58% of String instances having their coderange still unknown. --- process.c | 25 ++++++++++++++++++++++++- test/ruby/test_process.rb | 12 ++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/process.c b/process.c index 5761aea718d277..20360aceae4ba5 100644 --- a/process.c +++ b/process.c @@ -8535,6 +8535,27 @@ static VALUE rb_mProcUID; static VALUE rb_mProcGID; static VALUE rb_mProcID_Syscall; + +static int +proc_warmup_each_object(void *vstart, void *vend, size_t stride, void *data) +{ + VALUE v = (VALUE)vstart; + for (; v != (VALUE)vend; v += stride) { + switch (BUILTIN_TYPE(v)) { + case T_STRING: + // precompute the string coderange. This both save time for when it will be + // eventually needed, and avoid mutating heap pages after a potential fork. + rb_enc_str_coderange(v); + break; + default: + break; + } + } + + return 0; +} + + /* * call-seq: * Process.warmup -> true @@ -8563,10 +8584,12 @@ proc_warmup(VALUE _) RB_VM_LOCK_ENTER(); rb_gc_prepare_heap(); RB_VM_LOCK_LEAVE(); + + rb_objspace_each_objects(proc_warmup_each_object, NULL); + return Qtrue; } - /* * Document-module: Process * diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb index 6ca16733bbf014..12946dce669f46 100644 --- a/test/ruby/test_process.rb +++ b/test/ruby/test_process.rb @@ -2709,4 +2709,16 @@ def test_warmup_run_major_gc_and_compact assert_equal compact_count + 1, GC.stat(:compact_count) end; end + + def test_warmup_precompute_string_coderange + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + require 'objspace' + begin; + obj = "a" * 12 + obj.force_encoding(Encoding::BINARY) + assert_includes(ObjectSpace.dump(obj), '"coderange":"unknown"') + Process.warmup + assert_includes(ObjectSpace.dump(obj), '"coderange":"7bit"') + end; + end end