Feature #21987
openAssume `chdir(2)` isn't called and cache `rb_dir_getwd_ospath()`
Description
Context¶
I'm looking at optimizing Ruby applications boot time, and one very common operation that seems wasteful is that when interpreting relative paths
we keep calling ruby_getcwd(), even though its result almost never changes (Dir.chdir calls are rare).
We have 3 distinct implementations of ruby_getcwd() depending on the platform, but generally speaking it involves:
- One or multiple syscalls (on macOS:
open+fnctl+stat+close). -
malloc+free -
strdup+free - For some implementations, allocating a
T_DATAto avoid leaks in case of failure.
Measure¶
Out of curiosity I measured our monolith. Just booting we end up calling getcwd(2) 6931 times, for a total of 90ms spent in rb_dir_getwd_ospath(), but the caching would allow to save a bit more than that, as callers would no longer need to manage that memory.
Proposal¶
I propose that we cache the result of ruby_getcwd(), and only flush the cache when Dir.chdir is called.
Compatibility concern¶
This however assumes that C extensions or other native libraries never call chdir(2) after executing Ruby, or at least always reset it before yielding back to Ruby.
I'm not aware of any C extension currently doing this, but it would be interesting to perform a gem-codesearch.
If necessary we can provide void ruby_cwd_changed(void) to reset the cache after calling chdir(2).