turbopack: use Bitset in compute_chunk_group_info (#100643)
Stacked on #100566, which adds `turbo-bitset`. Stack: #100566 → this →
#100567 (`collect_graph`) → #100568 (`compute_merged_modules`) → #100630
(persisted chunk group sets).
## Summary
`compute_chunk_group_info` tracked each module's chunk groups with
`RoaringBitmapWrapper` during its fixed-point traversal. The traversal
checks "would `current |= parent` change `current`?" on every edge and
then does the union; on Roaring's array containers both cost time
proportional to the number of bits, which made this the slowest of the
module graph passes on `bench/nested-deps-app-router-many-pages`.
It now uses `Bitset` for the working per-module sets, and converts them
with `to_roaring()` when building the result. `ModuleToChunkGroups`, the
batch types and production chunking still use `RoaringBitmapWrapper`, so
persisted values are unchanged (#100630 switches those). The old code
called `RoaringBitmapWrapper::is_proper_superset` (which actually
computed `!parent.is_subset(current)`) and then `|=`. Now
`current.union_with(parent)` does both in one pass and returns whether
it added a bit. The separate first-visit `is_zero()` check plus
`clone()` is gone too: `union_with` copies into a set that stores no
blocks. This doesn't change the traversal, as a parent's set is never
empty when its children are visited.
## Benchmarks
> **Historical, not rerun:** measured in the previous review round,
before this stack was rebased onto canary `502b6b7d` and before the
latest review changes on `b149cf8a` (#100566), `c7ea9063` (#100643),
`e322a1c1` (#100567), `6536eeea` (#100568) and `417a41fd` (#100630).
This round only reran the `turbo-bitset` microbenchmarks in #100566.
`next build --experimental-build-mode compile` with release `next-swc`
(LTO off, 16 codegen units) built from each PR's head plus local-only
stage timers, on a shared VM with 8 vCPUs and 16 GB. Each number is the
median of 5 randomized, interleaved runs per variant, with the min–max
range in parentheses, in ms. All five layers of the stack were measured
in the same interleaved set, so adjacent PRs compare directly.
| stage (ms) | previous PR | this PR |
|---|---|---|
| `bench/nested-deps-app-router-many-pages` (3,000 routes): chunk-group
fixed point | 379 (375–384) | **49.9 (45.8–54.2)** |
| `bench/nested-deps-app-router-many-pages` (3,000 routes): building
`ChunkGroupInfo` | 3.73 (3.16–4.08) | **37.4 (35.7–42.2)** |
| generated 300-route app: chunk-group fixed point | 17.3 (16.4–18.1) |
**7.09 (6.93–7.33)** |
| generated 300-route app: building `ChunkGroupInfo` | 0.444
(0.417–0.471) | **3.57 (3.35–3.62)** |
Building `ChunkGroupInfo` now includes the `to_roaring()` conversion,
which #100630 removes. Visit counts are identical, and the emitted JS
chunks are byte-identical across all layers of the stack on both apps
(14,028 and 2,142 files, same digests). Whole-build time is too noisy on
these apps to show a reliable end-to-end difference. The microbenchmarks
are in #100566.
<details>
<summary>Charts: stage times (linear)</summary>
Median ms per stage; the first series is the previous PR. Exact values
and ranges are in the table above.
```mermaid
xychart-beta
title "bench/nested-deps-app-router-many-pages, median ms"
x-axis ["chunk-group fixed point", "building `ChunkGroupInfo`"]
y-axis "ms"
bar "previous PR" [379, 3.73]
bar "this PR" [49.9, 37.4]
```
```mermaid
xychart-beta
title "generated 300-route app, median ms"
x-axis ["chunk-group fixed point", "building `ChunkGroupInfo`"]
y-axis "ms"
bar "previous PR" [17.3, 0.444]
bar "this PR" [7.09, 3.57]
```
</details>
## Verification
- `cargo test -p turbopack-core --lib` and the turbopack snapshot tests
pass without snapshot changes; the execution tests pass on the top of
the stack.
- The real builds above.
<!-- NEXT_JS_LLM -->
<!-- fleet b56269ed-2145-4f30-b0fe-dc9762520521 -->
---------
Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com>
Co-authored-by: Luke Sandberg <210140+lukesandberg@users.noreply.github.com>
Co-authored-by: Vercel Fleet <fleet@vercel.com>
Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>