Summary
Measured while establishing the per-cycle GC picture for the retain cluster (gc-handoff/RETAIN4-NOTES.md):
asyncpipe collects at 1,200–1,650 ns/object when it collects at all — including a 122 ms minor that handled ZERO objects.
For scale, the retain cluster's in-place promotion runs at 8.9 ns/object and a real evacuation of 245,752 objects costs 30.2 ms. So asyncpipe's collections are two orders of magnitude more expensive per object, and one of them did no per-object work whatsoever yet still cost 122 ms — longer than the entire program's 127 ms runtime.
A collection whose cost is independent of the number of objects it processes is a fixed overhead being paid per cycle, not collection work. That points at root scanning, side-table maintenance, or a per-cycle setup/teardown cost that scales with something other than the live set.
Relationship to #7909
#7909 covers the incremental old-gen work asyncpipe pays while running zero cycles. This issue is different: it is about the cost of the cycles that do run, once the workload is scaled far enough to trigger them (per gc-handoff/ASYNC2-NOTES.md, 120 batches → zero cycles, 240 → two copying minors, 1200 → GC-dominated).
The two may share a root cause. They should be investigated together but neither should be closed by the other without evidence.
Acceptance
- Explain what a 122 ms minor spends its time on when it processes zero objects.
- A gate that asserts its subject was live (per CLAUDE.md's "four ways a gate can be unable to fail") — e.g. assert a nonzero cycle count and a bounded per-cycle fixed cost, not merely that nothing threw.
Note on measuring this
gc-handoff/apps/asyncpipe_big.ts is not a valid scaled proxy for asyncpipe — the zero-GC property is a knife-edge of the exact batch count. Any scaling used to trigger collections must be reported explicitly, along with confirmation that the mechanism under study survived the scaling.
Summary
Measured while establishing the per-cycle GC picture for the retain cluster (
gc-handoff/RETAIN4-NOTES.md):asyncpipecollects at 1,200–1,650 ns/object when it collects at all — including a 122 ms minor that handled ZERO objects.For scale, the retain cluster's in-place promotion runs at 8.9 ns/object and a real evacuation of 245,752 objects costs 30.2 ms. So
asyncpipe's collections are two orders of magnitude more expensive per object, and one of them did no per-object work whatsoever yet still cost 122 ms — longer than the entire program's 127 ms runtime.A collection whose cost is independent of the number of objects it processes is a fixed overhead being paid per cycle, not collection work. That points at root scanning, side-table maintenance, or a per-cycle setup/teardown cost that scales with something other than the live set.
Relationship to #7909
#7909 covers the incremental old-gen work
asyncpipepays while running zero cycles. This issue is different: it is about the cost of the cycles that do run, once the workload is scaled far enough to trigger them (pergc-handoff/ASYNC2-NOTES.md, 120 batches → zero cycles, 240 → two copying minors, 1200 → GC-dominated).The two may share a root cause. They should be investigated together but neither should be closed by the other without evidence.
Acceptance
Note on measuring this
gc-handoff/apps/asyncpipe_big.tsis not a valid scaled proxy forasyncpipe— the zero-GC property is a knife-edge of the exact batch count. Any scaling used to trigger collections must be reported explicitly, along with confirmation that the mechanism under study survived the scaling.