summaryrefslogtreecommitdiff
path: root/load.c
diff options
context:
space:
mode:
authorkrk <keremkat@gmail.com>2023-07-03 00:00:00 +0000
committerNobuyoshi Nakada <nobu@ruby-lang.org>2023-07-10 18:05:19 +0900
commitabfac2222bd51a03ec11b64f4770179cb6d06515 (patch)
tree00b77efa1ce6d9f583fb536b9c7b499b00d21d06 /load.c
parentd516910b61586fc6de676cf75930788594afe479 (diff)
Add a realpath cache to reduce number of syscalls.
Number of lstat and stat syscalls for each 'require'd file is doubled, because rb_realpath_internal is called from two places with the same arguments in require_internal; once for checking the realpaths cache, and once in load_iseq_eval when iseq is not found. Introduce rb_realpath_internal_cached function to reuse the realpath_map cache which memoizes rb_realpath_internal function, leading to less syscalls and increased startup performance depending on the cost of the syscalls in a particular environment.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/8017
Diffstat (limited to 'load.c')
-rw-r--r--load.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/load.c b/load.c
index debc544038..499d5af6f2 100644
--- a/load.c
+++ b/load.c
@@ -689,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)
{
@@ -701,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);
@@ -1208,7 +1225,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
result = TAG_RETURN;
}
else if (RTEST(rb_hash_aref(realpaths,
- realpath = rb_realpath_internal(Qnil, path, 1)))) {
+ realpath = realpath_internal_cached(realpath_map, path)))) {
result = 0;
}
else {
@@ -1268,7 +1285,6 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
if (real) {
real = rb_fstring(real);
rb_hash_aset(realpaths, real, Qtrue);
- rb_hash_aset(realpath_map, path, real);
}
}
ec->errinfo = saved.errinfo;