Project

General

Profile

Bug #19378 » recommendations.txt

aidog (Andi Idogawa), 06/16/2026 09:17 PM

 
Based on recent profiling and experimental patches aimed at speeding up native-extension loads on Windows, here are some potential areas for improvement that might be worth investigating. These are based on prototype results, so they would likely need deeper evaluation by the core team to ensure they don't introduce subtle regressions.

1. Potential reduction of syscalls in rb_file_load_ok
Where: win32/file.c (in rb_file_load_ok)
The Idea: The current implementation uses GetFileAttributesW followed by CreateFileW + CloseHandle to verify ACL readability. It might be worth exploring whether the CreateFileW calls can be safely skipped for standard files.
Proposed Experiment: Try relying solely on GetFileAttributesW for regular files, reserving the CreateFileW fallback strictly for files with the FILE_ATTRIBUTE_REPARSE_POINT attribute.
Potential Benefit: Initial profiling suggests that avoiding the handle allocation and open/close syscalls for the vast majority of existing files could save ~50µs per check, potentially yielding a small but measurable speedup during heavy require chains.

2. Exploring faster stat paths on Windows
Where: win32/win32.c (in winnt_stat)
The Idea: The existing winnt_stat implementation uses a multi-syscall approach (CreateFile → GetFileInformationByHandle → GetFileType → get_handle_pathname → CloseHandle). It could be beneficial to look into newer Windows APIs as fast paths for existing files.
Proposed Experiment:
Check if dynamically loading GetFileInformationByName (available in Win11 24H2+) could allow fetching all necessary info (file ID, timestamps, sizes, links) in a single syscall.
For older Windows versions, test using GetFileAttributesExW as a fallback to fetch attributes, timestamps, and sizes in one call.
Potential Benefit: Prototyping indicated this could significantly reduce the overhead of File.exist? and File.stat calls, appearing to speed them up considerably in microbenchmarks.

3. Using native Windows APIs for realpath
Where: file.c (in rb_check_realpath_internal) and win32/win32.c
The Idea: For absolute paths on Windows, the OS-level GetFinalPathNameByHandleW(FILE_NAME_NORMALIZED) might serve as a faster alternative to Ruby's portable realpath_rec walker.
Proposed Experiment: See if routing absolute Windows paths through this native API reduces the number of per-component stat calls.
Important Caveat: If this is attempted, experiments showed it is critical to normalize the returned backslashes (\) to forward slashes (/) so that $LOADED_FEATURES deduplicates paths correctly and prevents double-loading bugs.

4. Experimenting with GC deferral during require
Where: load.c (in require_internal)
The Idea: Profiling suggests that heavily allocated native extensions (like GUI bindings) can trigger dozens of GC cycles just during their load phase.
Proposed Experiment: Try temporarily disabling GC at the start of a top-level require using rb_ensure() to guarantee it gets re-enabled when the load finishes. (Care must be taken to check if GC was already disabled by user code so it isn't accidentally re-enabled).
Potential Benefit/Trade-off: While this seemed to improve wall-clock time in tests, it would likely increase peak memory usage during startup. The core team might want to evaluate if this trade-off is worthwhile, or if it should be placed behind a feature flag for memory-constrained environments.

5. Investigating modern DLL loading semantics
Where: dln.c (in dln_open) and win32/win32.c (in rb_w32_sysinit)
The Idea: Migrating from legacy LoadLibraryW to LoadLibraryExW might offer safer and slightly more predictable DLL loading behavior on modern Windows.
Proposed Experiment: Test switching to LoadLibraryExW(winfile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH).
Further Exploration: The team might also want to explore an opt-in mechanism (like a RUBY_DLL_PATH environment variable) that uses SetDefaultDllDirectories to enforce a strict User-Dirs loading mode. This could help self-contained gems resolve transitive DLL dependencies without relying on the system PATH.
(4-4/4)