Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/tools/internal/gopathwalk: regression in module cache scan performance #65531

Closed
findleyr opened this issue Feb 5, 2024 · 5 comments
Closed
Assignees
Labels
FixPending Issues that have a fix which has not yet been reviewed or submitted. NeedsFix The path to resolution is known, but the work has not been done. Tools This label describes issues relating to any tools in the x/tools repository. ToolSpeed
Milestone

Comments

@findleyr
Copy link
Contributor

findleyr commented Feb 5, 2024

As described in the discussion of https://go.dev/cl/508506, simplifying gopathwalk to use filepath.WalkDir had the unfortunate consequence of significantly slowing performance when starting from a cold module cache, as would be the case when running goimports from the command line. This is also very noticeable when gopls is initially started. On my laptop, with a 19GB module cache, warming up goimports went from ~6s to ~30s.

Because this latency was already a concern for gopls (see #44863), I don't think we can afford such a significant regression. With that said, the regression is probably possible to mitigate with alternative concurrency strategies. A benchmark is added in https://go.dev/cl/561436 which we can use for revisiting the simplification. For now, I think we need to temporarily revert CL 508506.

CC @bcmills

@gopherbot gopherbot added the Tools This label describes issues relating to any tools in the x/tools repository. label Feb 5, 2024
@gopherbot gopherbot added this to the Unreleased milestone Feb 5, 2024
@gopherbot
Copy link

Change https://go.dev/cl/561655 mentions this issue: Revert "internal/gopathwalk: use filepath.WalkDir instead of internal/fastwalk"

@gopherbot
Copy link

Change https://go.dev/cl/561675 mentions this issue: internal/gopathwalk: walk directories concurrently

@findleyr
Copy link
Contributor Author

findleyr commented Feb 5, 2024

A comparison of reverting vs fixing forward, in a relatively stable development environment. For lack of better names, "fastwalk.txt" is the revert, and "bryan.txt" is the fix forward :).

goarch: amd64
pkg: golang.org/x/tools/internal/imports
cpu: AMD EPYC 7B12
                              │ fastwalk.txt │              bryan.txt              │
                              │    sec/op    │   sec/op     vs base                │
ModuleResolver_InitialScan-48    366.0m ± 5%   403.2m ± 1%  +10.17% (p=0.000 n=20)

Limiting concurrency of the fix forward to 4 (the nominal concurrency limit of fastwalk), and results were noticeably worse:

goarch: amd64
pkg: golang.org/x/tools/internal/imports
cpu: AMD EPYC 7B12
                              │ fastwalk.txt │     bryan-limitconcurrency.txt      │
                              │    sec/op    │   sec/op     vs base                │
ModuleResolver_InitialScan-48    366.0m ± 5%   698.0m ± 2%  +90.72% (p=0.000 n=20)

However, CPU profiling indicated that the fix forward only uses 25% more CPU than fastwalk, so we can perhaps just say this is due to differences in scheduling, and run with the default concurrency of GOMAXPROCS.

Notably, the fix forward is still 4x faster than the non-concurrent implementation:

goos: linux
goarch: amd64
pkg: golang.org/x/tools/internal/imports
cpu: AMD EPYC 7B12
                              │  before.txt  │              bryan.txt              │
                              │    sec/op    │   sec/op     vs base                │
ModuleResolver_InitialScan-48   1620.8m ± 2%   403.2m ± 1%  -75.13% (p=0.000 n=20)

Therefore, I think we should fix forward. I'd rather get this fix into the gopls prerelease, so that it can get some exposure.

@findleyr findleyr modified the milestones: Unreleased, gopls/v0.15.0 Feb 6, 2024
@bcmills bcmills self-assigned this Feb 6, 2024
@bcmills
Copy link
Contributor

bcmills commented Feb 6, 2024

Limiting concurrency of the fix forward to 4 (the nominal concurrency limit of fastwalk), and results were noticeably worse

Ah, turns out that I misread the old code. 4 goroutines was the minimum; runtime.NumCPU() was the old default. (But runtime.GOMAXPROCS(0) seems like a better maximum, since the user may intentionally decrease that to prevent tools like gopls from oversaturating their system.)

@bcmills bcmills added NeedsFix The path to resolution is known, but the work has not been done. FixPending Issues that have a fix which has not yet been reviewed or submitted. labels Feb 6, 2024
@findleyr
Copy link
Contributor Author

findleyr commented Feb 6, 2024

Ah, turns out that I misread the old code. 4 goroutines was the minimum; runtime.NumCPU() was the old default. (But runtime.GOMAXPROCS(0) seems like a better maximum, since the user may intentionally decrease that to prevent tools like gopls from oversaturating their system.)

Oh, I misread it too! Then everything makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FixPending Issues that have a fix which has not yet been reviewed or submitted. NeedsFix The path to resolution is known, but the work has not been done. Tools This label describes issues relating to any tools in the x/tools repository. ToolSpeed
Projects
None yet
Development

No branches or pull requests

3 participants