You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Today, for everything that isn't the BSDs, we grab the
maximum number of open fds the process supports and then
loop through from 3 -> max, calling close(2) on everything.
Even for a low open fd count of 65k this will typically result
in 99+% of these close's being EBADF. At a 65k nofile RLIMIT
the sluggishness is not really felt, but on systems that may
have this in the millions it is extremely stark. `swift run`
on a hello world program can take minutes before the program
is actually ran.
There's a couple ways to work around this, but there's also another issue
in that actually closing the fds poses a problem in some cases with debug
builds of libdispatch. There can be a race between libdispatch going to
use the kqueue fd(s) and us closing them before the execve. Because of this,
the most sane thing to do is instead of closing we can set all of the open
fds as CLOEXEC. To do this efficiently on linux and macOS we can read /dev/fd
and /proc/self/fd respectively and only close what's actually open.
Below is the delta between two runs of `swift run` on a simple hello world
program. The shell I'm running these in has a nofile rlimit of 1 billion.
At 100 million it falls to about 20 seconds on my machine, and gets progressively
smaller until the two approaches aren't really any different at all.
With the patch:
```
Build of product 'fdwoo' complete! (0.23s)
Hello, world!
real 0m0.925s
user 0m0.698s
sys 0m0.129s
```
Without:
```
Build of product 'closerange' complete! (0.15s)
Hello, world!
real 2m43.203s
user 0m47.357s
sys 1m55.344s
```
Signed-off-by: Danny Canter <[email protected]>
0 commit comments