Reduce path-mapping cache memory usage for projects with many paths - #63998
Reduce path-mapping cache memory usage for projects with many paths#63998auvred wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Reduces path-mapping memory usage by sharing parsed patterns across module resolutions.
Changes:
- Adds a resolver-level cache keyed by path mappings.
- Corrects allocation sizing for parsed patterns and exact matches.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
tsc/internal/module/cache.go |
Adds the shared parsed-pattern cache. |
tsc/internal/module/resolver.go |
Uses the cache and improves parsing allocations. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| } | ||
| } | ||
| } | ||
| numMatchables := pathMappings.Size() - numPatterns |
There was a problem hiding this comment.
I accidentally noticed that numPatterns is used for patterns (StarIndex != -1), but here it was counted as the number paths of StarIndex == -1.
Also, numMatchables can be smaller than pathMappings.Size() - numPatterns since some patterns may be invalid, so it's better to explicitly count number of valid patterns with StarIndex == -1.
|
Linking back to microsoft/typescript-go#371 for the sake of context/continuity. |
|
I'm familiar with the core of all of this, but how exactly does this come up? Is it that multiple threads can do the same independent work on resolution? Or is it something around multi-project setups? |
Jake Bailey (jakebailey)
left a comment
There was a problem hiding this comment.
I think this is good?
|
I still don't get how this happens, so I'd prefer to really understand what happens here before merging. The original idea was that we would only ever grab |
Andrew Branch (andrewbranch)
left a comment
There was a problem hiding this comment.
There were two separate parsedPatternsForPaths and parsedPatternsForPathsOnce fields before this; one on module.Resolver's caches that was implicitly dependent on the compiler options of the host program, and one on every individual resolutionState. The former was used, and shared, between any lookups inside the host program's own files. But any lookups inside project reference redirects couldn't use the resolver's cache because those redirects need the paths of the referenced project's options. So for all lookups where a redirectedReference was passed in, we just recomputed the path patterns uncached. This change consolidates the two to a single shared cache, keyed by the path mappings from potentially multiple different compiler options.
Fixes #63997
This PR moves parsed patterns cache from
resolutionStatetocaches(embedded byResolver) so that different module resolutions can reuse already parsed patterns. As far as I understand, these patterns are immutable, so it's safe to cache them here.Before:
handled method 'textDocument/references' (22) in 2.518777125sAfter:
handled method 'textDocument/references' (23) in 1.461889542s