Project

General

Profile

Actions

Bug #19378

open

Windows: Use less syscalls for faster require of big gems

Added by aidog (Andi Idogawa) about 1 year ago. Updated about 1 year ago.

Status:
Assigned
Assignee:
Target version:
-
[ruby-core:112045]

Description

Hello 🙂

Problem

require is slow on windows for big gems. (example: require 'gtk3'=> 3 seconds+). This is a problem for people who want to make cross platform GUI apps with ruby.

Possible Reason

As touched on in #15797 it seems like require uses realpath, which is emulated on windows. It checks every parent directory. The same syscalls run many times.

Testfile

C:\tmp\speedtest\testrequire.rb:

require __dir__ + "/helloworld1.rb"
require __dir__ + "/helloworld2.rb"
ruby --disable-gems C:\tmp\speedtest\testrequire.rb

Syscalls per File/Directory:

  1. CreateFile
  2. QueryInformationVolume
  3. QueryIdInformation
  4. QueryAllInformationFile
  5. QueryNameInformationFile
  6. QueryNameInformationFile
  7. QueryNormalizedNameInformationFile
  8. CloseFile

Files/Directories checked

  1. C:\tmp
  2. C:\tmp\speedtest
  3. C:\tmp\speedtest\helloworld1.rb
  4. C:\tmp
  5. C:\tmp\speedtest
  6. C:\tmp\speedtest\helloworld2.rb

For two required files Ruby had to do 8*6 = 48 syscalls.
The syscalls orginate from rb_w32_reparse_symlink_p / lstat

Rubygems live in subfolders with 9+ parts: "C:\Ruby32-x64\lib\ruby\gems\3.2.0\gems\glib2-4.0.8\lib\glib2\variant.rb"
Each file takes 8 * 9 = 72+ calls. For variant.rb it is 80 calls.
The result for the syscalls don't change in such a short time, so it should be possible to cache it.

With require_relative it's twice as many calls.

Other testcases

Same result:

File.realpath __dir__ + "/helloworld1.rb"
File.realpath __dir__ + "/helloworld2.rb"
File.stat __dir__ + "/helloworld1.rb"
File.stat __dir__ + "/helloworld2.rb"

It does not happen in $LOAD_PATH.resolve_feature_path(dir + "/helloworld1.rb")

Request

Would it be possible to cache the stat calls when using require?
I tried to implement a cache inside the ruby source code, but failed.
If not, is there now a way to combine ruby files into one?

I previously talked about require here: YJIT: Windows support lacking.

How to reproduce

Ruby versions: At least 3.0+, most likely older ones too.
Tested using Ruby Installer 3.1 and 3.2.
Procmon Software by Sysinternals


Files

windows-no-realpath-require.patch (992 Bytes) windows-no-realpath-require.patch test to avoid repeated syscalls aidog (Andi Idogawa), 01/30/2023 03:10 AM
windows-revert-79a4484a.patch (5.42 KB) windows-revert-79a4484a.patch joshc (Josh C), 02/24/2023 01:40 AM
Actions

Also available in: Atom PDF

Like0
Like1Like0Like0Like0Like0Like0