mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
canary
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a80c0c0588 |
Cache immutable current task IDs outside the task-state lock (#96180)
## What changed Introduce a cloneable `CurrentTaskStateHandle` that keeps the execution's immutable `Option<TaskId>` beside the existing shared `Arc<RwLock<CurrentTaskState>>`. Global tasks, local tasks, detached futures, and top-level runs continue to share the same mutable state and task-local scope. Only current-task ID reads bypass the lock; all other state remains behind the existing `RwLock`. This was split from #96179 following review feedback. It is source-independent and changes only `turbopack/crates/turbo-tasks/src/manager.rs`. ## Why `current_task_if_available` and `current_task` acquired a shared standard-library `RwLock` on every native function call and tracked read, even though the task ID is fixed for the entire execution. The lock and its contention path remained visible in both HMR and production profiles. ## Performance evidence Measured at `0950e8ae05db20c33302f02257114f5b857edabc` as an incremental change on top of the independently proposed immutable-read bypass in #96179. These measurements are directional evidence, not a precise standalone estimate. Changes around 1–2% are difficult to measure reliably. The #96179 and #96180 campaigns used separate run sets, and #96179's absolute endpoint does not match this campaign's starting point; that mismatch demonstrates cross-campaign noise. The percentages must not be added, and the absolute values must not be compared across the two PRs. The standalone GitHub aggregate benchmark also moved in the opposite direction, reinforcing that build-level percentages are inconclusive at this scale. ### Browser-driven HMR, 30-second B/C/C/B - Evaluation: 19.772807 → 19.356650 ms (**-2.105%**) - Commit: 20.632962 → 20.167726 ms (**-2.255%**) - Both candidate runs beat both controls for both metrics. ### Production builds - Matrix 1: **-1.804%** - Complementary matrix 2: **-1.474%** - Combined 24 campaigns: 1,641.839610 → 1,614.918617 ms (**-1.640%**) - All six balanced blocks favored the candidate. - Six-block mean: -1.636%, with 95% interval **[-2.718%, -0.555%]**. ### Causal profiles - The `current_task_if_available` helper and contended read-lock symbols disappeared from candidate profiles. - HMR voluntary context switches fell 2.700%. - Production voluntary context switches fell 2.576%. - All eight accepted perf captures reported zero lost samples. ## Validation On the exact standalone head (`bce272743ff44021fda204d98924bf8519cd8c1d`): - Complete `turbo-tasks` package tests and doctests - Complete `turbo-tasks-backend` package tests, integrations, and doctests - `cargo fmt --check -p turbo-tasks -p turbo-tasks-backend` - `cargo clippy -p turbo-tasks -p turbo-tasks-backend --all-targets -- -D warnings` - `git diff --check` - Conflict-free merge-tree check against current `canary` (`91c6309c52`) |
||
|
|
779fbad904 |
Optimize implicit cache tag derivation (#96120)
## What
Derive implicit cache tags by scanning pathname slash boundaries
incrementally instead of repeatedly rebuilding prefixes with `split`,
`slice`, and `join`.
The new loop emits exactly the same derived-tag array as the old helper,
including the full-path prefix. The caller's existing `Set` continues to
deduplicate that tag against `pathname` when they are equal. This PR's
optimization is specifically the removal of repeated intermediate path
arrays and prefix joins; it does not rely on changing deduplication
semantics or tag order.
Coverage includes root paths, `page` and `route` suffixes, missing
leading slashes, repeated/trailing slashes, Unicode, malformed UTF-16,
and already-encoded pathnames.
## Correctness
The candidate was compared element-by-element with the original
`split('/').slice(0, i).join('/')` implementation over **1,713,653
paths** on each of Node 20.9.0, Node 22.23.1, and Node 24.14.1:
- 349,525 exhaustive strings of length 0–9 over a slash/ASCII alphabet;
- every UTF-16 code unit: 65,536 cases;
- every valid surrogate pair: 1,048,576 cases;
- 250,000 deterministic randomized paths with Unicode, malformed
surrogates, controls, reserved characters, suffix-like content, and
arbitrary slash placement;
- 16 targeted cases, including a one-million-character segment and a
1,024-segment path.
All three runtime runs completed with **0 mismatches**.
## Performance
Pinned CPU 4 on a 16-vCPU / 32-GiB Vercel DevBox. Each of 35 scenarios
used 31 interleaved rounds, adaptive iterations, and two identical
baseline lanes (A/A control). Scenarios cover depth 1–256, slash-dense
paths, segment widths 1–512, suffix cases, no-leading-slash inputs,
Unicode/malformed code units, and seeded shallow/medium/deep corpora.
| Runtime | Scenarios improved | Seeded shallow | Seeded medium | Seeded
deep |
| --- | ---: | ---: | ---: | ---: |
| Node 20.9.0 / V8 11.3 | 35/35 | **-77.11%** | **-82.59%** |
**-92.69%** |
| Node 22.23.1 / V8 12.4 | 35/35 | **-81.07%** | **-88.60%** |
**-95.47%** |
| Node 24.14.1 / V8 13.6 | 35/35 | **-80.98%** | **-89.00%** |
**-95.88%** |
No candidate p05–p95 interval crosses zero on any runtime. Selected Node
24 results:
| Scenario | Median delta | p05–p95 |
| --- | ---: | ---: |
| Realistic root/suffix corpus | **-77.70%** | -78.02% to -77.22% |
| Repeated/trailing slashes | **-77.88%** | -79.24% to -77.07% |
| Unicode and malformed UTF-16 | **-63.49%** | -64.59% to -62.31% |
| Depth 8, 4-char segments | **-83.14%** | -83.98% to -82.74% |
| Depth 32, 4-char segments | **-92.48%** | -92.60% to -92.22% |
| Depth 256, 4-char segments | **-98.77%** | -98.80% to -98.75% |
| Depth 32, 512-char segments | **-97.02%** | -97.09% to -96.98% |
Inspector heap-allocation sampling, five repeats (median sampled bytes):
| Corpus | Baseline | Candidate | Change |
| --- | ---: | ---: | ---: |
| Realistic, 500k calls | 489,583,800 | 206,253,144 | **-57.87%** |
| Shallow, 500k calls | 493,465,152 | 203,994,592 | **-58.66%** |
| Deep, 20k calls | 843,885,312 | 112,216,736 | **-86.70%** |
### Alternative tested
A split-once implementation that accumulated prefix strings also passed
all 1.71M cases, but a direct 35-scenario interleaved comparison found
the shipped `indexOf` implementation faster in **35/35** cases.
Accumulation was 26.49% to 1,810.86% slower and sampled
47.5%/70.3%/280.8% more bytes on realistic/shallow/deep corpora. It was
rejected.
### Production profile
The original matched render-pipeline profile used 1,000 serial plus
10,000 concurrent-load requests:
| Attribution | Baseline | Candidate |
| --- | ---: | ---: |
| Total sampled CPU | 20,534.6 ms | 20,461.6 ms |
| Next runtime sampled CPU | 7,786.1 ms | 7,856.8 ms |
| `implicit-tags.ts` | 54.1 ms (0.69%) | 41.4 ms (0.53%) |
That is a **23.48% reduction** in source-attributed production CPU. A
single load-throughput run improved 3.64%, but that is inside the
workload's established 6.76% full range, so this PR does not claim a
separately resolvable total-throughput improvement.
## Validation
- `pnpm exec jest packages/next/src/server/lib/implicit-tags.test.ts
--runInBand` — 12/12 passed
- `pnpm prettier --check packages/next/src/server/lib/implicit-tags.ts
packages/next/src/server/lib/implicit-tags.test.ts`
- `pnpm eslint packages/next/src/server/lib/implicit-tags.ts
packages/next/src/server/lib/implicit-tags.test.ts`
- `pnpm --filter next types`
- `pnpm --filter next build`
- `pnpm build-all` — 18/18 tasks successful, including
`@vercel/turbopack-next` checks
- Correctly scoped Codex GPT-5.6 Sol xhigh review: clean, 0.98
correctness confidence
- Correctly scoped Claude Opus 4.8 xhigh review: clean, 0.90 correctness
confidence
GitHub CI has 111 passing checks. The Windows integration job failed
after `curl` received a connection reset while downloading Datadog
tooling (exit 35); the aggregate `thank you, next` check reflects that
infrastructure failure. No changed-file or implicit-tag test failed.
---------
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
|
||
|
|
d5cc1e12a7 |
Avoid quadratic HMR queue shifts (#96137)
## What - Replace repeated `Array.shift()` calls in the HMR affected-module breadth-first traversal with a monotonically increasing queue index. - Clear each consumed slot immediately so copied dependency chains can be collected during deep traversals. ## Why `getAffectedModuleEffects` can enqueue a wide set of parents when a shared dependency changes. Repeatedly shifting the queue moves the remaining array contents on every iteration, making broad invalidations increasingly expensive. Indexed reads keep traversal FIFO and make queue consumption linear. The slot clearing is important for deep graphs: it avoids retaining every processed item's copied `dependencyChain` until traversal returns. ## Benchmark Three independent 8-vCPU/16-GiB Vercel Sandbox workers ran Node.js 24.14.1 from exact commit `0950e8ae05db20c33302f02257114f5b857edabc`. The balanced `A1/B1/B2/A2` benchmark mirrors this loop for one changed shared dependency imported by N root modules, including dependency-chain allocation. Each phase used three warm-ups and nine samples. | Affected parents | `shift()` median | Indexed median | Improvement | Speedup | Worker agreement | Max baseline A/A drift | |---:|---:|---:|---:|---:|---:|---:| | 1,000 | 0.160 ms | 0.089 ms | 45.81% | 1.85x | 3/3 | 9.91% | | 20,000 | 27.895 ms | 2.929 ms | 89.43% | 9.46x | 3/3 | 7.85% | | 50,000 | 164.960 ms | 7.342 ms | 95.52% | 22.33x | 3/3 | 1.21% | | 100,000 | 665.564 ms | 15.840 ms | 97.62% | 42.02x | 3/3 | 2.23% | The small-graph effect is intentionally modest; this targets very broad HMR invalidations in large applications. ## Validation - targeted Prettier: pass - targeted ESLint: pass - `pnpm --filter @vercel/turbopack-ecmascript-runtime check:nodejs`: pass - `CARGO_TARGET_DIR=/home/vercel-sandbox/next.js/target cargo check -p turbopack-ecmascript-runtime`: pass - GPT-5.6 Sol xhigh + Claude Opus 4.8 xhigh autoreview: clean after addressing a first-round dependency-chain retention finding (0 findings, correctness 0.99) The aggregate runtime TypeScript check remains blocked by an existing `runtime-utils.ts:239` `EsmExport` type mismatch. The identical `check:browser-dev-client` failure reproduces on the untouched baseline and is unrelated to this file. --------- Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> |
||
|
|
6c5e0bbd74 |
[turbopack] Skip redundant top-level root updates (#95903)
## Summary - skip the redundant aggregation-root update when `ConnectChildOperation` reconnects an already constructed top-level task that is already an aggregation root - avoid entering the aggregation operation loop when no update was queued The fast path is intentionally narrow. It applies only when the connection has no parent, the task has materialized output, and the task's aggregation number is already the root sentinel. The task may still be dirty and need to run; this only skips an idempotent aggregation update. A task that is not yet a root still goes through the normal update on its first top-level connection. Tasks without output are still scheduled, parented connections retain their activeness and aggregation updates, and transient-state boundaries are unchanged. ## Findings The earlier scheduler experiment has been removed completely. The apparent benefit from keeping a worker alive with `std::thread::yield_now()` was specific to the benchmark topology: Criterion's `Runtime::block_on` caller runs outside the single-worker Tokio runtime, so that external caller can enqueue the next root task while the runtime worker is yielding at the OS level. The sole Tokio worker itself cannot produce work during that loop. In normal scheduling, tasks typically enqueue their children before the current job exits, and a multi-worker runtime can start another worker when it is below its target. That does not justify burning CPU in an idle worker, nor replacing the loop with an async-yield retry loop. The retained optimization is independent of that artifact. An already constructed top-level task that is already rooted has no new root update to perform; re-enqueuing the idempotent update only forces the operation executor through unnecessary suspend points. This PR now contains no changes to `priority_runner`, worker lifetime, busy waiting, OS-thread yielding, async yielding, HMR, filesystem watching, or documentation. ## Benchmark results The benchmark source, runtime construction, profiles, allocator, toolchain, and worker count were unchanged. Frozen baseline and candidate executables were run adjacently in alternating order. Three focused pairs met the control-drift threshold; one pair was excluded before analysis because its Tokio control moved by more than 2%. Median candidate changes across the valid pairs: | Case | Change | | --- | ---: | | direct control | +0.071% | | Tokio control | -0.177% | | uncached task | +1.266% | | cached, same key | -37.868% | | cached, different keys | -26.783% | The complete all-duration local sweeps did not meet the control thresholds, so their task measurements are deliberately not cited. Fresh remote CodeSpeed and Stats results are the authoritative guardrail for the full benchmark. ## Verification - `cargo fmt --all -- --check` - `cargo clippy -p turbo-tasks-backend --all-targets -- -D warnings -A deprecated` - `cargo test -p turbo-tasks-backend` - `pnpm build-all` - two-engine autoreview after the final changes, with no findings - Not run: `pnpm --filter=next dev` (the final diff is Rust-only and was covered by the full bootstrap build and Cargo suites) |
||
|
|
cc57d6521d |
Run Rust doctests in CI (#95911)
## Summary Run all Rust workspace doctests as part of the existing Turbo-cached cargo unit test task so future documentation regressions fail CI without adding an uncached workspace build. ## Verification - `cargo test --workspace --doc --profile=release-with-assertions --no-fail-fast` - Not run: `pnpm --filter=@next/swc test-cargo-unit` (`cargo-nextest` is installed in CI but unavailable locally; the new doctest suffix passed independently) <!-- NEXT_JS_LLM --> |
||
|
|
7e817e863b |
Fix Rust doctest failures (#95909)
## Summary - Fix Rust documentation examples so workspace doctests compile successfully. - Mark incomplete illustrative snippets as ignored while keeping runnable examples checked. - Update stale imports and API usage, and classify directory trees as text. ## Verification - cargo fmt --all -- --check - cargo test --workspace --doc --no-fail-fast - autoreview --mode local --stream-engine-output (Codex + Claude: 0 findings) |