Low priority. Filed to record an observation, not to schedule work. It may
simply be what this run costs, and we currently lack the instrument to say.
The observation
Reusing a buffer across b_compare_parallel calls, instead of letting it be
allocated and freed each time, makes the map closure's own compute measurably
slower. It reproduces across two independent implementations at two buffer sizes:
| lever |
how the buffer is reused |
size (ITS2 R2) |
user / busy |
A (#147, ef46356) |
16 B element drops under glibc's 32 MB mmap cap, so the arena recycles it |
15.0 MB |
+11% |
D (#147, bd59f6b) |
one Vec held on B, filled via collect_into_vec |
45.1 MB |
+16% |
Both collapse sys (70% and 94%). Neither improves wall time: D is −3.9% on
ITS2 R1 and +6.5% on R2; A is −5.9% / −1.5%. Total CPU rises in both cases.
Size modulates the penalty. Reuse is what causes it. That is the part worth
recording, because "hoist the allocation out of the loop" is a reflex
optimisation and here it costs more than it saves — twice, by different routes.
What is already ruled out
- Rayon spin-wait. Falsified by accounting: the whole ITS2 R2 run has 838
core-seconds of CPU outside the map's summed busy time, and D's rise alone is
1,211. No room for it.
- Load imbalance. Work-matched uniform-vs-skewed arms in
examples/parallel_overhead measure ±0.1% on both pool shapes.
- A cost on the destination store (the read-for-ownership account I proposed
and then falsified). busy rises +16.0%, but busy times the closure body —
the write into the destination happens in rayon's collect after the closure
returns, so a destination-store cost could never appear there. The screen and
alignment compute is what got slower.
parallel_overhead reproducing it at all. Its synthetic reports reuse as
faster. Its work function is pure ALU while production's map streams 1.7 GB
of k-mer vectors, so it has nothing to contend with. Do not treat that
benchmark as evidence either way here.
The remaining hypothesis, and why it is stuck
A live buffer stays resident in LLC and contends with the k-mer vectors the
screen streams, where a freed region's lines die naturally. It fits the size
dependence (45.1 MB hurts more than 15.0 MB) but rests on one paired
observation.
Settling it wants hardware counters — LLC-loads/misses, dTLB-load-misses — on one
B-vs-D pair. perf is not available on compute-5-6, which is the blocker.
Every hypothesis in the #147 arc died to a timer that could say that but never
why, and this is exactly the case where a counter would answer directly.
A cheap falsifiable test, if this is ever picked up
Without counters, the testable claim is the size dependence. If the penalty
scales with resident buffer size, LLC contention is supported; if it is flat
across sizes, it is not.
A+D combined has never been run — reuse and the 16 B element, giving a 15 MB
persistent buffer with no allocation at all. That is a small change on top of the
two existing branches and gives a third point on the size curve. Expect it to be
the least-bad of the three if the hypothesis holds.
Framing it honestly: this is a curiosity, not a candidate. The wall numbers do
not suggest a win is hiding here, and there are two larger open targets — the ~6
unattributed points of map parallel efficiency, and the serial ramp that #150's
progress lines exposed (occupancy climbs 22 → 42 effective cores of 64 across a
single run).
Context: docs/findings/compare-store-scan.md. Branches perf/store-scan-147
(A) and perf/store-scratch-147 (D) are left in place, unmerged.
Low priority. Filed to record an observation, not to schedule work. It may
simply be what this run costs, and we currently lack the instrument to say.
The observation
Reusing a buffer across
b_compare_parallelcalls, instead of letting it beallocated and freed each time, makes the map closure's own compute measurably
slower. It reproduces across two independent implementations at two buffer sizes:
user/busyef46356)mmapcap, so the arena recycles itbd59f6b)Vecheld onB, filled viacollect_into_vecBoth collapse
sys(70% and 94%). Neither improves wall time: D is −3.9% onITS2 R1 and +6.5% on R2; A is −5.9% / −1.5%. Total CPU rises in both cases.
Size modulates the penalty. Reuse is what causes it. That is the part worth
recording, because "hoist the allocation out of the loop" is a reflex
optimisation and here it costs more than it saves — twice, by different routes.
What is already ruled out
core-seconds of CPU outside the map's summed busy time, and D's rise alone is
1,211. No room for it.
examples/parallel_overheadmeasure ±0.1% on both pool shapes.and then falsified).
busyrises +16.0%, butbusytimes the closure body —the write into the destination happens in rayon's collect after the closure
returns, so a destination-store cost could never appear there. The screen and
alignment compute is what got slower.
parallel_overheadreproducing it at all. Its synthetic reports reuse asfaster. Its work function is pure ALU while production's map streams 1.7 GB
of k-mer vectors, so it has nothing to contend with. Do not treat that
benchmark as evidence either way here.
The remaining hypothesis, and why it is stuck
A live buffer stays resident in LLC and contends with the k-mer vectors the
screen streams, where a freed region's lines die naturally. It fits the size
dependence (45.1 MB hurts more than 15.0 MB) but rests on one paired
observation.
Settling it wants hardware counters — LLC-loads/misses, dTLB-load-misses — on one
B-vs-D pair.
perfis not available on compute-5-6, which is the blocker.Every hypothesis in the #147 arc died to a timer that could say that but never
why, and this is exactly the case where a counter would answer directly.
A cheap falsifiable test, if this is ever picked up
Without counters, the testable claim is the size dependence. If the penalty
scales with resident buffer size, LLC contention is supported; if it is flat
across sizes, it is not.
A+D combined has never been run — reuse and the 16 B element, giving a 15 MB
persistent buffer with no allocation at all. That is a small change on top of the
two existing branches and gives a third point on the size curve. Expect it to be
the least-bad of the three if the hypothesis holds.
Framing it honestly: this is a curiosity, not a candidate. The wall numbers do
not suggest a win is hiding here, and there are two larger open targets — the ~6
unattributed points of map parallel efficiency, and the serial ramp that #150's
progress lines exposed (occupancy climbs 22 → 42 effective cores of 64 across a
single run).
Context:
docs/findings/compare-store-scan.md. Branchesperf/store-scan-147(A) and
perf/store-scratch-147(D) are left in place, unmerged.