perf: cache HTTP operation resolution at the program level#11318
Open
iscai-msft wants to merge 1 commit into
Open
perf: cache HTTP operation resolution at the program level#11318iscai-msft wants to merge 1 commit into
iscai-msft wants to merge 1 commit into
Conversation
iscai-msft
requested review from
bterlson,
catalinaperalta,
markcowl,
timotheeguerin and
witemple-msft
as code owners
July 20, 2026 20:42
commit: |
Contributor
|
All changed packages have been documented.
Show changes
|
iscai-msft
force-pushed
the
iscai-msft-linter-perf-improvements
branch
from
July 20, 2026 20:52
fe080fb to
489827a
Compare
|
You can try these changes here
|
iscai-msft
force-pushed
the
iscai-msft-linter-perf-improvements
branch
5 times, most recently
from
July 21, 2026 17:35
eff893e to
41da546
Compare
getHttpOperation() previously created a fresh empty Map() on every call, so multiple callers (validators, linter rules, emitters) each recomputed full HTTP operation details from scratch. On large specs like Compute RP with ~8 linter rules calling getHttpOperation() per operation, this resulted in massive redundant work. This change uses the program's stateMap as a persistent cache, keyed by Operation. The HTTP validator ($onValidate) naturally runs first and populates the cache via getAllHttpServices() -> listHttpOperationsIn(). All subsequent callers (linter rules, emitters) get cached results for free, with the resolution cost attributed to the validation phase rather than any individual linter rule. On Compute RP (66 tsp files, 31,831 types, 74 rules), this eliminates ~375ms of redundant per-rule HTTP operation resolution in the linter. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 71734702-1f81-447e-87e6-ff9f7040268a
iscai-msft
force-pushed
the
iscai-msft-linter-perf-improvements
branch
from
July 21, 2026 17:39
41da546 to
d566a48
Compare
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.
Motivation
Feedback from teams working on large ARM spec conversions indicates linter delays are long enough that engineers sometimes give up waiting. Profiling shows the linter accounts for ~40-50% of total compile time on large specs, with the top rules all bottlenecked on redundant
getHttpOperation()calls.Root Cause
getHttpOperation()creates a fresh emptyMap()as its internal cache on every call. SincelistHttpOperationsIn()already uses a shared local cache within a single invocation, the issue arises when multiple independent callers (linter rules, emitters) each callgetHttpOperation()separately -- they all recompute from scratch.On Compute RP with ~8 linter rules calling
getHttpOperation()per operation, this means 8x redundant resolution of paths, parameters, responses, and authentication per operation.Solution
Use the program's
stateMapas a persistent cache for resolved HTTP operations. Since the HTTP validator ($onValidate) already callsgetAllHttpServices()which resolves all operations vialistHttpOperationsIn(), it naturally populates the cache before linter rules run. All subsequent callers get cached results for free.This approach:
Impact
On Compute RP (66 tsp files, 31,831 types, 74 linter rules):
no-query-explodeandno-header-explodedrop from ~140ms each to ~0msChanges
packages/http/src/lib.ts: AddhttpOperationCachestate keypackages/http/src/operations.ts: Use program-level stateMap ingetHttpOperation()andlistHttpOperationsIn()instead of creating fresh local Maps