Skip to content

perf: Reduce per-task allocations in visitor dispatch loop#11986

Merged
anthonyshew merged 1 commit intomainfrom
shew/reduce-dispatch-loop-allocations
Feb 24, 2026
Merged

perf: Reduce per-task allocations in visitor dispatch loop#11986
anthonyshew merged 1 commit intomainfrom
shew/reduce-dispatch-loop-allocations

Conversation

@anthonyshew
Copy link
Copy Markdown
Contributor

@anthonyshew anthonyshew commented Feb 24, 2026

Summary

  • Use HashMap::remove() instead of .get().clone() for pre-computed task hash/env lookups — moves values out instead of deep-cloning (String, EnvironmentVariableMap) per task
  • Reorder the non-dry dispatch path so reference-only consumers of TaskId (output_client, telemetry) are built before the final move, eliminating one TaskId clone per task
Repo Size Baseline (mean) Improved (mean) Change
~1,000 packages 1.448s ± 0.035s 1.422s ± 0.027s 26ms faster (1.8%), 23% less variance
~125 packages 585.2ms ± 39.7ms 557.9ms ± 28.2ms 27ms faster (4.7%), 29% less variance
5 packages 69.1ms ± 13.1ms 87.4ms ± 61.1ms noise (min times identical at ~55ms)

Why

The visitor dispatch loop runs once per task (~1,700 iterations in a large monorepo). Each iteration was:

  1. Deep-cloning a (String, HashMap<String, String>) from the precomputed map via .get().clone() — even though each task is dispatched exactly once
  2. Cloning TaskId (two Cow<str> fields) 3 times when only 2 owned copies are needed

Since each task ID appears exactly once in the dispatch stream, HashMap::remove() moves the value out at zero cost. And reordering reference-only uses before the final info.into_owned() eliminates one clone.

Testing

No behavioral change — same tasks dispatched in the same order, same hashes and environments. The only difference is ownership transfer (move vs clone) and evaluation order of independent expressions.

Two changes to the task dispatch loop in visitor/mod.rs:

1. Use HashMap::remove() instead of .get().clone() when looking up
   pre-computed task hashes and execution environments. Each task is
   dispatched exactly once, so we can move the values out instead of
   deep-cloning (String, EnvironmentVariableMap) per task.

2. Reorder the non-dry dispatch path so reference-only consumers of
   the TaskId (output_client, telemetry) are built before the final
   move, eliminating one TaskId clone per task.
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Feb 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
examples-basic-web Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm
examples-designsystem-docs Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm
examples-gatsby-web Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm
examples-kitchensink-blog Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm
examples-nonmonorepo Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm
examples-svelte-web Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm
examples-tailwind-web Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm
examples-vite-web Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm
turbo-site Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm
turborepo-agents Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm
turborepo-test-coverage Ready Ready Preview, Comment, Open in v0 Feb 24, 2026 7:22pm

@github-actions
Copy link
Copy Markdown
Contributor

Coverage Report

Metric Coverage
Lines 75.10%
Functions 46.84%
Branches 0.00%

View full report

@anthonyshew anthonyshew marked this pull request as ready for review February 24, 2026 19:46
@anthonyshew anthonyshew requested a review from a team as a code owner February 24, 2026 19:46
@anthonyshew anthonyshew requested review from tknickman and removed request for a team February 24, 2026 19:46
@anthonyshew anthonyshew enabled auto-merge (squash) February 24, 2026 20:09
@anthonyshew anthonyshew merged commit 53b2b4f into main Feb 24, 2026
177 of 178 checks passed
@anthonyshew anthonyshew deleted the shew/reduce-dispatch-loop-allocations branch February 24, 2026 20:09
anthonyshew added a commit that referenced this pull request Feb 25, 2026
## Release v2.8.11-canary.28

> [!NOTE]
> This release PR was created manually because the [automated release
workflow
failed](https://github.com/vercel/turborepo/actions/runs/22396672874/job/64834751381)
during the "Create Release PR" step. The npm packages were already
published successfully.

### Changes

- release(turborepo): 2.8.11-canary.27 (#11975) (`09e2557`)
- chore: Move git hooks from pre-commit to pre-push and match CI lint
checks (#11977) (`68928c0`)
- chore: Update AGENTS.md (#11978) (`3887e0d`)
- fix: Use correct pnpm version in library release workflow (#11979)
(`716229d`)
- fix: Fix library release workflow for Trusted Publishing OIDC (#11980)
(`f2b57af`)
- fix: Use repo setup-node action in library release package job
(#11981) (`c8d6fd8`)
- fix: Add repository field to @turbo/repository package.json (#11982)
(`2865110`)
- perf: Replace heap-allocated String with stack-allocated OidHash for
git OIDs (#11984) (`24e1937`)
- perf: Eliminate redundant syscalls in FSCache fetch and exists
(#11985) (`ba1e3bb`)
- release(library): 0.0.1-canary.19 (#11983) (`a5bc714`)
- perf: Reduce per-task allocations in visitor dispatch loop (#11986)
(`53b2b4f`)
- docs: Fix same-page anchor links that don't scroll to target (#11989)
(`b1d5ec2`)
- docs: Mention inputs key in package hash inputs table (#11990)
(`6bc216b`)
- fix(docs): update sitemap.md to single-line pipe-delimited format
(#11976) (`fd15d24`)
- fix: Disable husky pre-push hook during release staging (#11991)
(`2365307`)
- fix: Disable husky pre-push hook in release workflow (#11992)
(`71ca25c`)
github-actions Bot added a commit that referenced this pull request Feb 25, 2026
## Release v2.8.11-canary.29

Versioned docs: https://v2-8-11-canary-29.turborepo.dev

### Changes

- release(turborepo): 2.8.11-canary.27 (#11975) (`09e2557`)
- chore: Move git hooks from pre-commit to pre-push and match CI lint
checks (#11977) (`68928c0`)
- chore: Update AGENTS.md (#11978) (`3887e0d`)
- fix: Use correct pnpm version in library release workflow (#11979)
(`716229d`)
- fix: Fix library release workflow for Trusted Publishing OIDC (#11980)
(`f2b57af`)
- fix: Use repo setup-node action in library release package job
(#11981) (`c8d6fd8`)
- fix: Add repository field to @turbo/repository package.json (#11982)
(`2865110`)
- perf: Replace heap-allocated String with stack-allocated OidHash for
git OIDs (#11984) (`24e1937`)
- perf: Eliminate redundant syscalls in FSCache fetch and exists
(#11985) (`ba1e3bb`)
- release(library): 0.0.1-canary.19 (#11983) (`a5bc714`)
- perf: Reduce per-task allocations in visitor dispatch loop (#11986)
(`53b2b4f`)
- docs: Fix same-page anchor links that don't scroll to target (#11989)
(`b1d5ec2`)
- docs: Mention inputs key in package hash inputs table (#11990)
(`6bc216b`)
- fix(docs): update sitemap.md to single-line pipe-delimited format
(#11976) (`fd15d24`)
- fix: Disable husky pre-push hook during release staging (#11991)
(`2365307`)
- fix: Disable husky pre-push hook in release workflow (#11992)
(`71ca25c`)
- release(turborepo): 2.8.11-canary.28 (#11993) (`5793b0a`)
- fix: Use versioned schema URLs in Turborepo skill files (#11994)
(`7e48e24`)

---------

Co-authored-by: Turbobot <turbobot@vercel.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant