Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ruby 3.2 - Speed up rebuilding the loaded feature index and realpath cache #8023

Merged
merged 2 commits into from Jul 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 41 additions & 6 deletions load.c
Expand Up @@ -163,6 +163,12 @@ get_loaded_features_realpaths(rb_vm_t *vm)
return vm->loaded_features_realpaths;
}

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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions vm.c
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions vm_core.h
Expand Up @@ -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
Expand Down