Skip to content

perf: cache HTTP operation resolution at the program level#11318

Open
iscai-msft wants to merge 1 commit into
microsoft:mainfrom
iscai-msft:iscai-msft-linter-perf-improvements
Open

perf: cache HTTP operation resolution at the program level#11318
iscai-msft wants to merge 1 commit into
microsoft:mainfrom
iscai-msft:iscai-msft-linter-perf-improvements

Conversation

@iscai-msft

Copy link
Copy Markdown
Member

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 empty Map() as its internal cache on every call. Since listHttpOperationsIn() already uses a shared local cache within a single invocation, the issue arises when multiple independent callers (linter rules, emitters) each call getHttpOperation() 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 stateMap as a persistent cache for resolved HTTP operations. Since the HTTP validator ($onValidate) already calls getAllHttpServices() which resolves all operations via listHttpOperationsIn(), it naturally populates the cache before linter rules run. All subsequent callers get cached results for free.

This approach:

  • Attributes resolution cost to the validation phase (not individual rules)
  • Avoids confusing per-rule benchmarks where one rule "pays" for others
  • Benefits all consumers automatically (linter rules, emitters, etc.)

Impact

On Compute RP (66 tsp files, 31,831 types, 74 linter rules):

  • Rules like no-query-explode and no-header-explode drop from ~140ms each to ~0ms
  • Total linter time drops from ~846ms to ~440ms (~48% reduction)

Changes

  • packages/http/src/lib.ts: Add httpOperationCache state key
  • packages/http/src/operations.ts: Use program-level stateMap in getHttpOperation() and listHttpOperationsIn() instead of creating fresh local Maps

@pkg-pr-new

pkg-pr-new Bot commented Jul 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http@11318

commit: d566a48

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/http
Show changes

@typespec/http - fix ✏️

Cache HTTP operation resolution at the program level so multiple callers (validators, linter rules, emitters) share results without redundant recomputation. On large specs this reduces linter time by ~48%.

@iscai-msft
iscai-msft force-pushed the iscai-msft-linter-perf-improvements branch from fe080fb to 489827a Compare July 20, 2026 20:52
@azure-sdk-automation

azure-sdk-automation Bot commented Jul 20, 2026

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

@iscai-msft
iscai-msft force-pushed the iscai-msft-linter-perf-improvements branch 5 times, most recently from eff893e to 41da546 Compare July 21, 2026 17:35
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
iscai-msft force-pushed the iscai-msft-linter-perf-improvements branch from 41da546 to d566a48 Compare July 21, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant