summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMSP-Greg <MSP-Greg@users.noreply.github.com>2023-08-21 18:33:47 -0500
committerGitHub <noreply@github.com>2023-08-21 23:33:47 +0000
commit788b03d5ba82fd8b35ce1fe2618ce6bacc648333 (patch)
treee6fb84d186606ce6ad74b8beeb48cb182944c5cb
parente517ba2e5b6434e7d2370de7703f481dcb8eecba (diff)
Re-apply "Ruby 3.2 - Speed up rebuilding the loaded feature index and realpath cache (#8023)" (#8252)
* Re-apply "Ruby 3.2 - Speed up rebuilding the loaded feature index and realpath cache (#8023)" * [CI] mingw.yml - remove IBM437 encoding for test-all, use cmd shell for test & test-all * Skip failing test on mingw with readline.so Co-authored-by: nagachika <nagachika@ruby-lang.org> --------- Co-authored-by: nagachika <nagachika@ruby-lang.org>
-rw-r--r--.github/workflows/mingw.yml4
-rw-r--r--load.c47
-rw-r--r--test/excludes/TestReadline.rb4
-rw-r--r--vm.c2
-rw-r--r--vm_core.h1
5 files changed, 50 insertions, 8 deletions
diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml
index ba3886218a..c8b53ad76b 100644
--- a/.github/workflows/mingw.yml
+++ b/.github/workflows/mingw.yml
@@ -139,12 +139,11 @@ jobs:
run: |
make test
if: ${{matrix.test_task == 'check' || matrix.test_task == 'test'}}
+ shell: cmd
- name: test-all
timeout-minutes: 45
run: |
- # Actions uses UTF8, causes test failures, similar to normal OS setup
- chcp.com 437
make ${{ StartsWith(matrix.test_task, 'test/') && matrix.test_task || 'test-all' }}
env:
RUBY_TESTOPTS: >-
@@ -152,6 +151,7 @@ jobs:
${{ matrix.test-all-opts }}
BUNDLER_VERSION:
if: ${{matrix.test_task == 'check' || matrix.test_task == 'test-all' || StartsWith(matrix.test_task, 'test/')}}
+ shell: cmd
- name: test-spec
timeout-minutes: 10
diff --git a/load.c b/load.c
index f3d39c2c08..44449fc77e 100644
--- a/load.c
+++ b/load.c
@@ -164,6 +164,12 @@ get_loaded_features_realpaths(rb_vm_t *vm)
}
static VALUE
+get_loaded_features_realpath_map(rb_vm_t *vm)
+{
+ return vm->loaded_features_realpath_map;
+}
+
+static VALUE
get_LOADED_FEATURES(ID _x, VALUE *_y)
{
return get_loaded_features(GET_VM());
@@ -361,7 +367,10 @@ get_loaded_features_index(rb_vm_t *vm)
st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
VALUE realpaths = vm->loaded_features_realpaths;
+ VALUE realpath_map = vm->loaded_features_realpath_map;
+ VALUE previous_realpath_map = rb_hash_dup(realpath_map);
rb_hash_clear(realpaths);
+ rb_hash_clear(realpath_map);
features = vm->loaded_features;
for (i = 0; i < RARRAY_LEN(features); i++) {
VALUE entry, as_str;
@@ -378,9 +387,14 @@ get_loaded_features_index(rb_vm_t *vm)
long j = RARRAY_LEN(features);
for (i = 0; i < j; i++) {
VALUE as_str = rb_ary_entry(features, i);
- VALUE realpath = rb_check_realpath(Qnil, as_str, NULL);
- if (NIL_P(realpath)) realpath = as_str;
- rb_hash_aset(realpaths, rb_fstring(realpath), Qtrue);
+ VALUE realpath = rb_hash_aref(previous_realpath_map, as_str);
+ if (NIL_P(realpath)) {
+ realpath = rb_check_realpath(Qnil, as_str, NULL);
+ if (NIL_P(realpath)) realpath = as_str;
+ realpath = rb_fstring(realpath);
+ }
+ rb_hash_aset(realpaths, realpath, Qtrue);
+ rb_hash_aset(realpath_map, as_str, realpath);
}
}
return vm->loaded_features_index;
@@ -675,6 +689,19 @@ rb_provide(const char *feature)
NORETURN(static void load_failed(VALUE));
+static inline VALUE
+realpath_internal_cached(VALUE hash, VALUE path)
+{
+ VALUE ret = rb_hash_aref(hash, path);
+ if(RTEST(ret)) {
+ return ret;
+ }
+
+ VALUE realpath = rb_realpath_internal(Qnil, path, 1);
+ rb_hash_aset(hash, rb_fstring(path), rb_fstring(realpath));
+ return realpath;
+}
+
static inline void
load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
{
@@ -687,8 +714,12 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
VALUE parser = rb_parser_new();
rb_parser_set_context(parser, NULL, FALSE);
ast = (rb_ast_t *)rb_parser_load_file(parser, fname);
+
+ rb_thread_t *th = rb_ec_thread_ptr(ec);
+ VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
+
iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit("<top (required)>"),
- fname, rb_realpath_internal(Qnil, fname, 1), NULL);
+ fname, realpath_internal_cached(realpath_map, fname), NULL);
rb_ast_dispose(ast);
rb_vm_pop_frame(ec);
RB_GC_GUARD(v);
@@ -1161,6 +1192,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
volatile VALUE saved_path;
volatile VALUE realpath = 0;
VALUE realpaths = get_loaded_features_realpaths(th->vm);
+ VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
volatile bool reset_ext_config = false;
struct rb_ext_config prev_ext_config;
@@ -1194,7 +1226,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
}
#endif
else if (RTEST(rb_hash_aref(realpaths,
- realpath = rb_realpath_internal(Qnil, path, 1)))) {
+ realpath = realpath_internal_cached(realpath_map, path)))) {
result = 0;
}
else {
@@ -1252,7 +1284,8 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
rb_provide_feature(th2->vm, path);
VALUE real = realpath;
if (real) {
- rb_hash_aset(realpaths, rb_fstring(real), Qtrue);
+ real = rb_fstring(real);
+ rb_hash_aset(realpaths, real, Qtrue);
}
}
ec->errinfo = saved.errinfo;
@@ -1473,6 +1506,8 @@ Init_load(void)
vm->loaded_features_index = st_init_numtable();
vm->loaded_features_realpaths = rb_hash_new();
rb_obj_hide(vm->loaded_features_realpaths);
+ vm->loaded_features_realpath_map = rb_hash_new();
+ rb_obj_hide(vm->loaded_features_realpath_map);
rb_define_global_function("load", rb_f_load, -1);
rb_define_global_function("require", rb_f_require, 1);
diff --git a/test/excludes/TestReadline.rb b/test/excludes/TestReadline.rb
new file mode 100644
index 0000000000..706736f6f6
--- /dev/null
+++ b/test/excludes/TestReadline.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: false
+if /mingw/i.match?(RUBY_PLATFORM)
+ exclude(:test_input_metachar_multibyte, "failed with readline.so on MiNGW")
+end
diff --git a/vm.c b/vm.c
index d009a5f64a..de43d022c0 100644
--- a/vm.c
+++ b/vm.c
@@ -2703,6 +2703,7 @@ rb_vm_update_references(void *ptr)
vm->loaded_features = rb_gc_location(vm->loaded_features);
vm->loaded_features_snapshot = rb_gc_location(vm->loaded_features_snapshot);
vm->loaded_features_realpaths = rb_gc_location(vm->loaded_features_realpaths);
+ vm->loaded_features_realpath_map = rb_gc_location(vm->loaded_features_realpath_map);
vm->top_self = rb_gc_location(vm->top_self);
vm->orig_progname = rb_gc_location(vm->orig_progname);
@@ -2794,6 +2795,7 @@ rb_vm_mark(void *ptr)
rb_gc_mark_movable(vm->loaded_features);
rb_gc_mark_movable(vm->loaded_features_snapshot);
rb_gc_mark_movable(vm->loaded_features_realpaths);
+ rb_gc_mark_movable(vm->loaded_features_realpath_map);
rb_gc_mark_movable(vm->top_self);
rb_gc_mark_movable(vm->orig_progname);
RUBY_MARK_MOVABLE_UNLESS_NULL(vm->coverages);
diff --git a/vm_core.h b/vm_core.h
index d86fdbaecd..b6adeadd87 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -680,6 +680,7 @@ typedef struct rb_vm_struct {
VALUE loaded_features;
VALUE loaded_features_snapshot;
VALUE loaded_features_realpaths;
+ VALUE loaded_features_realpath_map;
struct st_table *loaded_features_index;
struct st_table *loading_table;
#if EXTSTATIC