Repository navigation
Watch mode: ~2.5-4 s of fixed setup per iteration in large monorepos (git status -uall, O(n虏) queue scan, state hashes)聽#6122
Description
馃 Filed by GitHub Copilot acting for Naman Kanakiya (@namankanakiya) (light review only).
Repro context: a large private monorepo (~240,000 tracked files, ~1,040 operations in the watch selection), Rush 5.178.1, Node 22.16, Linux, 16 cores. rush start --to <tag> (also run through a wrapper that adds plugins), editing one source file of a library that ~1,000 operations depend on.
Observed: on every watch iteration, Rush's own performance marks (written to common/temp/telemetry) show 2.2-2.9 s (median about 2.35 s) between scheduling the iteration and rush:executionManager:configureIteration, before any operation starts. A CPU profile of the rush process (node --cpu-prof) over two edits attributes it to:
- Inputs snapshot (
getDetailedRepoStateAsyncin package-deps-hash):git --no-optional-locks status -z -u --no-renames --ignore-submodules --no-ahead-behind(untracked files: all) takes 1.07 s wall on this repository. The same command with-unormaltakes 0.52 s, because git's untracked cache (core.untrackedCache=true) only serves normal mode; with-unoit takes 0.18 s.git ls-files(0.17 s) runs in parallel and is not the bottleneck. Parsing the ls-files output costs 0.17 s CPU. - State hashes:
OperationExecutionRecord.getStateHashfor ~1,040 records costs 0.67 s CPU, mostlyInputsSnapshot.getTrackedFileHashesForOperation(LookupByPath lookups over all tracked files). It is recomputed for every operation on every iteration, although almost no operation's tracked files changed. AsyncOperationQueue.assignOperations: called from everynext()andcomplete(), it scans the whole queue (for (let i = queue.length - 1; ...)) and compares each record's status against eight enum members, each read through a webpack harmony getter (_OperationStatus__WEBPACK_IMPORTED_MODULE_0__.OperationStatus.X). With ~1,040 records that is O(n虏) per iteration: 1.05 s and 2.06 s CPU in the two profiled iterations. The profiler inflates this; the unprofiled cost is still to be confirmed.
Proposed changes (one PR each, or one PR with three commits)
(a) package-deps-hash: use -unormal and expand untracked directories
- Run
git status -z -unormal ...instead of-u(all). - For each entry that is an untracked directory (path ends with
/), enumerate its files while respecting.gitignore(for examplegit ls-files -o --exclude-standard -z -- <dir>), and only for those directories. - Expected: about 0.5 s less per iteration on this repository, for
rush start,rush build(initial snapshot) and any other caller ofgetRepoStateAsync. The returned file list is identical. - Test: a fixture repository with an untracked directory containing nested files; assert that the returned map matches the
-uallresult.
(b) AsyncOperationQueue: maintain a ready set
- Keep
Readyrecords in a separate structure thatcomplete()fills when a consumer's last dependency completes, and remove terminal records when they complete, soassignOperations()only looks at ready records. - Hoist the status constants to module-level locals (or use a
Setof terminal statuses) so the hot path does not go through harmony getters. - Expected: removes the O(n虏) scan, worth up to about 1 s CPU per iteration at ~1,000 operations.
- Test: the existing AsyncOperationQueue tests (ordering, and cobuild re-queue semantics:
timesQueuedordering must be kept).
(c) Reuse per-operation state hashes across iterations
- Cache
getOperationOwnStateHashper operation, keyed by the identity of the operation's tracked-file map, or skip recomputation when the new snapshot's hashes for the operation's project folder are unchanged (a per-project digest computed once per snapshot). - Expected: most of the 0.67 s CPU per iteration.
Evidence
- Telemetry:
common/temp/telemetry/telemetry_*.json, theperformanceEntriesofrush startiterations. - A CPU profile of the rush main thread, aggregated over the first 6 s after each edit.
- git timings:
date +%s%Naround each command, three runs each, on the same checkout.
Happy to share more detail or test a candidate fix against this repository.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNeeds triage
Activity