Avoid getcwd when the path is already absolute#846
Open
Brett-Best wants to merge 1 commit into
Open
Conversation
`absolutePathRepresentation()` returns immediately for an already-absolute path, but its default argument `FileManager.default.currentDirectoryPath` is evaluated at every call site regardless, because Swift evaluates default arguments before the callee runs. That property is not cached: each access allocates a buffer, issues a `getcwd` syscall, and builds a new String (see swift-foundation FileManager+Directories.swift), so callers that pass absolute paths pay for it needlessly. SourceKitten hits this once per file when constructing `File(pathDeferringReading:)`, so tools like SwiftLint that lint thousands of files make thousands of pointless `getcwd` calls during file discovery. In an Instruments trace of linting a ~7,000-file project this accounts for ~0.8 s of CPU on the serial pre-lint critical path. Make `rootDirectory` optional and resolve the working directory lazily, only on the relative-path branch that actually uses it. The relative-path behavior is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Brett-Best
marked this pull request as ready for review
July 17, 2026 06:20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Avoid
getcwdwhen the path is already absoluteWhat
NSString.absolutePathRepresentation(rootDirectory:)has an early return for already-absolute paths, but its default argument runs agetcwdsyscall on every call regardless — even when that early return means the value is never used.This makes
rootDirectoryoptional and resolves the working directory lazily, only on the relative-path branch that actually uses it.Why it's not as cheap as it looks
Swift evaluates a default argument at the call site, before the callee body runs. So
absolutePathRepresentation()on an absolute path still computesFileManager.default.currentDirectoryPathand then discards it.FileManager.defaultis a singleton, but.currentDirectoryPathis not a cached value — it does real work on every access. In swift-foundation it allocates a buffer, issues agetcwd(2)syscall, and constructs a freshString:https://github.com/swiftlang/swift-foundation/blob/96d4094612d02bdc6f474f73efa0695196e786e9/Sources/FoundationEssentials/FileManager/FileManager+Directories.swift#L512-L529
(On Darwin the ObjC Foundation implementation is at least as expensive.)
Impact
File(pathDeferringReading:)calls this once per file, always with an absolute path. Tools that enumerate large projects therefore make one pointlessgetcwdper file during file discovery.Profiling SwiftLint linting a ~7,000-file project (Instruments Time Profiler, release build):
currentDirectoryPathaccounts for ~0.8 s of CPU (≈2.7 % of the run), and it sits on the serial pre-lint file-discovery path, so it is a proportionally larger share of warm/incremental runs where little else executes. An isolated before/after A/B of the same lint measured ~3 % off both cold and warm wall-clock (the wall figure is smaller than the CPU figure because the directory walk is parallelized).Correctness
Behavior-preserving by construction: the resolved working directory is only ever used on the relative-path branch, which is unchanged; the absolute-path branch never read it. Verified end-to-end by linting a large project with all rules enabled — identical violation output (same count, files, lines, columns) before and after.