Commit 413a8d2
authored
Ports #24456 to `v5-next`.
## What was wrong
The interactions tracegen phase runs every lookup/permutation job
concurrently: `AvmTraceGenHelper::fill_trace_interactions` concatenates
all builders' jobs and dispatches them with `parallel_for`. Lookups
whose fine-grained destination selector is a *shared* column
(`DST_SELECTOR != outer_dst_selector`) can resolve to the same `dst_row`
from different jobs, so multiple threads write the same `(selector,
row)` cell at once.
The previous code did a guarded read-modify-write on that shared cell:
```cpp
if (DST_SELECTOR != outer_dst_selector && trace.get(DST_SELECTOR, dst_row) != 1) {
trace.set(DST_SELECTOR, dst_row, 1);
}
```
Both the `get` and the non-atomic 32-byte `set` race against the other
threads' writes to the same cell — a data race, i.e. undefined behavior.
In practice it produced the right value (every writer stores `1`), but
it is still UB.
## The fix
Add an opt-in `use_atomic_limbs` flag to `TraceContainer::set`. When
set, the field's four 64-bit limbs are written with **relaxed atomic
stores** — four plain `movq` on x86-64, no lock and no libatomic call.
(A whole-field `std::atomic_ref<FF>` is *not* an option on the hot path:
at 32 bytes it exceeds the hardware lock-free width and falls back to a
locked libatomic call.)
The shared selector write now uses it and drops the guard read:
```cpp
if (DST_SELECTOR != outer_dst_selector) {
trace.set(DST_SELECTOR, dst_row, 1, /*use_atomic_limbs=*/true);
}
```
The write is an unconditional, idempotent atomic store of `1`. Because
every concurrent writer stores the *same* value, per-limb atomicity is
sufficient — no torn value is possible — so this is data-race-free
without the cost of whole-field atomicity. The default (non-atomic)
`set` hot path is untouched and keeps its sparse-column "zero = absent"
fast path.
## Performance (this PR vs baseline)
Mega bulk AVM tx, full proving, `HARDWARE_CONCURRENCY=16`. Tracegen
stage timings, median of runs (baseline n=3, this PR n=6):
| Stage | baseline | this PR |
|---|---|---|
| tracegen traces | 1,536 ms | 1,537 ms |
| tracegen interactions | 350 ms | 329 ms |
| tracegen all | 1,917 ms | 1,936 ms |
No measurable cost — the safety fix is free. The per-limb atomic only
fires on the shared selector writes in the interactions stage; the
traces stage is byte-for-byte the same hot path as baseline.
3 files changed
Lines changed: 41 additions & 14 deletions
File tree
- barretenberg/cpp/src/barretenberg/vm2/tracegen
- lib
Lines changed: 8 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
| |||
198 | 198 | | |
199 | 199 | | |
200 | 200 | | |
201 | | - | |
202 | | - | |
203 | | - | |
204 | | - | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
205 | 205 | | |
206 | 206 | | |
207 | 207 | | |
| |||
Lines changed: 28 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
| |||
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
17 | 30 | | |
18 | 31 | | |
19 | 32 | | |
| |||
62 | 75 | | |
63 | 76 | | |
64 | 77 | | |
65 | | - | |
| 78 | + | |
66 | 79 | | |
67 | 80 | | |
68 | 81 | | |
| |||
73 | 86 | | |
74 | 87 | | |
75 | 88 | | |
76 | | - | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
77 | 95 | | |
78 | | - | |
| 96 | + | |
| 97 | + | |
79 | 98 | | |
80 | 99 | | |
81 | | - | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
82 | 105 | | |
83 | 106 | | |
84 | 107 | | |
| |||
Lines changed: 5 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
79 | | - | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
80 | 84 | | |
81 | 85 | | |
82 | 86 | | |
| |||
0 commit comments