turbo-tasks-backend: keep the active count inline (#101486)
## Summary
A task's activeness was an `ActivenessState` lazy field. The field was
added when the task became active and removed when it became inactive,
and tasks do that a few times per build: about 17.8M activations on a
large app with 7.9M tasks. Every one of those added and removed a lazy
field. The removals mostly happened long after the task completed, so
each also left an empty 40-byte slot in the lazy field vec.
The state is now split:
- **The active count** lives inline in an `i16`. It fits in
`TaskStorage`'s padding, so `TaskStorage` stays 128 bytes.
- **The lazy `activeness_state` field** holds the rarely needed rest:
root and active-until-clean state, the clean event, and the count while
it doesn't fit the `i16`. Only roots, tasks kept active until clean, and
very widely shared tasks need it.
- **Activeness is unchanged in meaning:** a task is active while either
is present, which covers a negative count during races.
Most activations are now just a counter update. The call sites go
through an `ActivenessAccessors` trait (`is_active`,
`has_positive_active_count`, `add_active_count`, …).
### Results
Cold `next build --experimental-build-mode=compile`, 4 interleaved runs
per side, median [range]. These were measured on a branch with other
task storage changes.
| | vercel-site | v0 chat |
| --- | --- | --- |
| wall | 62.7 s [60.2–63.9] → 59.8 s [58.8–61.2], −4.7% | 38.4 s
[37.9–40.4] → 36.6 s [36.5–37.3], −4.8% |
| user CPU | 439.1 s [437.2–443.3] → 428.4 s [423.1–431.5], −2.4% |
294.0 s [293.4–295.4] → 285.8 s [285.0–286.8], −2.8% |
| sys CPU | −3.8% | −3.8% |
With the old state, lazy field slack from removed `ActivenessState`s was
about 290 MiB on vercel-site at the end of the build. The inline count
doesn't create it.
## Verification
- `cargo nextest r -p turbo-tasks-backend -p turbo-tasks -p
turbopack-tests`. The schema size test checks that `TaskStorage` is
still 128 bytes.
- `cargo check -p turbo-tasks-backend --features <feature>` for
`verify_aggregation_graph`, `verify_determinism`,
`aggregation_update_no_batch`, `hanging_detection`,
`trace_aggregation_update` and `verify_immutable`
<!-- NEXT_JS_LLM -->