Skip to content

Commit 61b9746

Browse files
committed
Speed up rebuilding the loaded feature index
Rebuilding the loaded feature index slowed down with the bug fix for #17885 in 79a4484. The slowdown was extreme if realpath emulation was used, but even when not emulated, it could be about 10x slower. This adds loaded_features_realpath_map to rb_vm_struct. This is a hidden hash mapping loaded feature paths to realpaths. When rebuilding the loaded feature index, look at this hash to get cached realpath values, and skip calling rb_check_realpath if a cached value is found. Fixes [Bug #19246]
1 parent 0ac3f2c commit 61b9746

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

load.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,12 @@ get_loaded_features_realpaths(rb_vm_t *vm)
163163
return vm->loaded_features_realpaths;
164164
}
165165

166+
static VALUE
167+
get_loaded_features_realpath_map(rb_vm_t *vm)
168+
{
169+
return vm->loaded_features_realpath_map;
170+
}
171+
166172
static VALUE
167173
get_LOADED_FEATURES(ID _x, VALUE *_y)
168174
{
@@ -361,7 +367,10 @@ get_loaded_features_index(rb_vm_t *vm)
361367
st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
362368

363369
VALUE realpaths = vm->loaded_features_realpaths;
370+
VALUE realpath_map = vm->loaded_features_realpath_map;
371+
VALUE previous_realpath_map = rb_hash_dup(realpath_map);
364372
rb_hash_clear(realpaths);
373+
rb_hash_clear(realpath_map);
365374
features = vm->loaded_features;
366375
for (i = 0; i < RARRAY_LEN(features); i++) {
367376
VALUE entry, as_str;
@@ -378,9 +387,14 @@ get_loaded_features_index(rb_vm_t *vm)
378387
long j = RARRAY_LEN(features);
379388
for (i = 0; i < j; i++) {
380389
VALUE as_str = rb_ary_entry(features, i);
381-
VALUE realpath = rb_check_realpath(Qnil, as_str, NULL);
382-
if (NIL_P(realpath)) realpath = as_str;
383-
rb_hash_aset(realpaths, rb_fstring(realpath), Qtrue);
390+
VALUE realpath = rb_hash_aref(previous_realpath_map, as_str);
391+
if (NIL_P(realpath)) {
392+
realpath = rb_check_realpath(Qnil, as_str, NULL);
393+
if (NIL_P(realpath)) realpath = as_str;
394+
realpath = rb_fstring(realpath);
395+
}
396+
rb_hash_aset(realpaths, realpath, Qtrue);
397+
rb_hash_aset(realpath_map, as_str, realpath);
384398
}
385399
}
386400
return vm->loaded_features_index;
@@ -1161,6 +1175,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
11611175
volatile VALUE saved_path;
11621176
volatile VALUE realpath = 0;
11631177
VALUE realpaths = get_loaded_features_realpaths(th->vm);
1178+
VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
11641179
volatile bool reset_ext_config = false;
11651180
struct rb_ext_config prev_ext_config;
11661181

@@ -1252,7 +1267,9 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
12521267
rb_provide_feature(th2->vm, path);
12531268
VALUE real = realpath;
12541269
if (real) {
1255-
rb_hash_aset(realpaths, rb_fstring(real), Qtrue);
1270+
real = rb_fstring(real);
1271+
rb_hash_aset(realpaths, real, Qtrue);
1272+
rb_hash_aset(realpath_map, path, real);
12561273
}
12571274
}
12581275
ec->errinfo = saved.errinfo;
@@ -1473,6 +1490,8 @@ Init_load(void)
14731490
vm->loaded_features_index = st_init_numtable();
14741491
vm->loaded_features_realpaths = rb_hash_new();
14751492
rb_obj_hide(vm->loaded_features_realpaths);
1493+
vm->loaded_features_realpath_map = rb_hash_new();
1494+
rb_obj_hide(vm->loaded_features_realpath_map);
14761495

14771496
rb_define_global_function("load", rb_f_load, -1);
14781497
rb_define_global_function("require", rb_f_require, 1);

vm.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,6 +2699,7 @@ rb_vm_update_references(void *ptr)
26992699
vm->loaded_features = rb_gc_location(vm->loaded_features);
27002700
vm->loaded_features_snapshot = rb_gc_location(vm->loaded_features_snapshot);
27012701
vm->loaded_features_realpaths = rb_gc_location(vm->loaded_features_realpaths);
2702+
vm->loaded_features_realpath_map = rb_gc_location(vm->loaded_features_realpath_map);
27022703
vm->top_self = rb_gc_location(vm->top_self);
27032704
vm->orig_progname = rb_gc_location(vm->orig_progname);
27042705

@@ -2790,6 +2791,7 @@ rb_vm_mark(void *ptr)
27902791
rb_gc_mark_movable(vm->loaded_features);
27912792
rb_gc_mark_movable(vm->loaded_features_snapshot);
27922793
rb_gc_mark_movable(vm->loaded_features_realpaths);
2794+
rb_gc_mark_movable(vm->loaded_features_realpath_map);
27932795
rb_gc_mark_movable(vm->top_self);
27942796
rb_gc_mark_movable(vm->orig_progname);
27952797
RUBY_MARK_MOVABLE_UNLESS_NULL(vm->coverages);

vm_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ typedef struct rb_vm_struct {
676676
VALUE loaded_features;
677677
VALUE loaded_features_snapshot;
678678
VALUE loaded_features_realpaths;
679+
VALUE loaded_features_realpath_map;
679680
struct st_table *loaded_features_index;
680681
struct st_table *loading_table;
681682
#if EXTSTATIC

0 commit comments

Comments
 (0)