Skip to content

Commit 398a5e6

Browse files
authored
feat(bb): faster create_circuit — arithmetic, tiled gate storage, containers, cold assert paths (#537)
* feat(bb): faster create_circuit — wide arithmetic, tiled (AoSoA) gate storage, size hints Barrett fast paths for scalar-field divmod, native Montgomery + safegcd bigfield division, constexpr folding for small field literals, gate storage as 8-gate tiles with contiguous per-selector arrays (single append_gate surface, bulk copy_into extraction), and builder size hints from ACIR. * feat(bb): container and allocation optimizations (polynomial backing, copy cycles, builder reserves) Lazy zero-initialized (anonymous mmap) polynomial backing memory, CSR copy cycles in trace population, and reserved per-variable bookkeeping vectors in the ACIR builder path. * feat(bb): compile BB_BENCH instrumentation out of shipped wasm Sets ENABLE_WASM_BENCH=OFF in the wasm-threads preset so the released wasm no longer carries op-counting overhead. Wasm bench runs keep wall-clock and peak-memory measurements; hierarchical breakdowns and memory profiles are native-only, and the CI breakdown upload is skipped for wasm. Configure with -DENABLE_WASM_BENCH=ON to get wasm op counts for dev runs. * refactor(bb): review feedback — name magic numbers, drop stale comment, GateRowT alias - databus selector array sized by NUM_BUS_COLUMNS instead of a literal 7 - named constants for the ACIR block size hints and variable reserve - remove orphaned doc block for the deleted check_selector_length_consistency - replace 19 'typename std::decay_t<decltype(...)>::Row' sites with the existing GateRowT alias * refactor(bb): single NON_GATE_SELECTORS table drives gate-storage selector wiring The non-gate selector list (q_m, q_c, q_1..q_5) was duplicated across GateRow, GateTile, append_gate's copies, the columns_ wiring, and a literal 7. A single constexpr member-pointer table now defines the list and its order; the count, append_gate, and column construction derive from it. Also: GATE_TILE_SHIFT derived from GATE_TILE_SIZE (power-of-two asserted), tile-size comment expressed in terms of sizeof(FF), and shared gate_selector_or_zero read helper.
1 parent 5e9fe41 commit 398a5e6

22 files changed

Lines changed: 1175 additions & 832 deletions

barretenberg/.claude/skills/benchmark-chonk/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ HARDWARE_CONCURRENCY=8 BB_BENCH=1 \
133133
The wasmtime wrapper sets:
134134
- `-Wthreads=y -Sthreads=y` — enable WASM threads and shared memory
135135
- `--env HARDWARE_CONCURRENCY` — thread count
136-
- `--env BB_BENCH` — enable operation counting (`ENABLE_WASM_BENCH=ON` is set by the `wasm-threads` preset)
136+
- `--env BB_BENCH` — enable operation counting (requires configuring with `-DENABLE_WASM_BENCH=ON`; it is OFF by default in the `wasm-threads` preset to keep the shipped wasm fast)
137137
- `--dir=$HOME/.bb-crs --dir=.` — filesystem access for CRS and working directory
138138

139139
## Local runs are noisy — average 3 runs
@@ -322,7 +322,7 @@ The generic Google-Benchmark A/B scripts still exist for non-Chonk targets:
322322
- **Use `./bootstrap.sh` for initial builds** — it downloads cached artifacts and avoids build issues. Use `cmake --preset clang20 && cd build && ninja bb` for incremental rebuilds after code changes.
323323
- **Build dir is `build/`** — the `clang20` preset outputs to `build/`, not `build-no-avm`. The `clang20-no-avm` preset also uses `build/` (it disables AVM at cmake level, not via directory name).
324324
- **If the zig cache breaks** (missing `libubsan_rt.a` errors), delete `build/` and reconfigure: `rm -rf build && cmake --preset clang20`.
325-
- **WASM preset:** `wasm-threads`. Build dir is `build-wasm-threads/`. The preset enables `ENABLE_WASM_BENCH=ON` automatically.
325+
- **WASM preset:** `wasm-threads`. Build dir is `build-wasm-threads/`. `ENABLE_WASM_BENCH` is OFF by default (the shipped wasm carries no BB_BENCH instrumentation); configure with `cmake --preset wasm-threads -DENABLE_WASM_BENCH=ON` when you need wasm op counts, and reconfigure without it afterwards.
326326
- **WASM is ~2.8x slower than native** — this ratio is consistent across all circuit types.
327327
- **CRS:** Ensure `~/.bb-crs` exists. For WASM, wasmtime needs `--dir=$HOME/.bb-crs`.
328328
- **`BB_BENCH=1` vs `--print_bench`:** Either activates profiling. `--print_bench` also triggers the hierarchical tree output to stderr. In Google-Benchmark targets that wrap their loops with `GOOGLE_BB_BENCH_REPORTER`, the same activation happens automatically when `BB_BENCH=1` is set.

barretenberg/cpp/CLAUDE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ These are load-bearing: violating them will compile on native but break WASM, or
9797

9898
**IMPORTANT**: In the barretenberg context, "bench" or "benchmark" almost always means running `benchmark_remote.sh` for the given target on a remote benchmarking machine.
9999

100+
**Never benchmark against test binaries (`*_tests`) — the results will always be wrong.** Test circuits are small mocks whose cost profile does not resemble real proving workloads. Benchmark against real inputs: the pinned Chonk flows (`scripts/chonk_inputs.sh download`, then `bb prove --scheme chonk --ivc_inputs_path chonk-pinned-flows/<flow>/ivc-inputs.msgpack`) or the dedicated `*_bench` targets.
101+
100102
To run benchmarks for a specific target:
101103
```bash
102104
cd barretenberg/cpp
@@ -196,7 +198,7 @@ For bb.js, run:
196198

197199
```bash
198200
barretenberg/cpp/scripts/chonk_inputs.sh download
199-
barretenberg/ts/bb.js/scripts/run_test.sh bbapi/chonk_pinned_inputs.test.js
201+
barretenberg/ts/scripts/run_test.sh bbapi/chonk_pinned_inputs.test.js
200202
```
201203

202204
Typical workflow

barretenberg/cpp/CMakePresets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@
434434
"cacheVariables": {
435435
"CMAKE_BUILD_TYPE": "Release",
436436
"MULTITHREADING": "ON",
437-
"ENABLE_WASM_BENCH": "ON"
437+
"ENABLE_WASM_BENCH": "OFF"
438438
}
439439
},
440440
{

barretenberg/cpp/scripts/benchmark_wasm.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ HARDWARE_CONCURRENCY=${HARDWARE_CONCURRENCY:-16}
99
cd $(dirname $0)/..
1010

1111
# Configure and build.
12+
# BB_BENCH op counts are compiled out of wasm by default; add -DENABLE_WASM_BENCH=ON here if you
13+
# need them (timings are unaffected either way).
1214
cmake --preset wasm-threads
1315
cmake --build --preset wasm-threads --target $BENCHMARK
1416

barretenberg/cpp/scripts/ci_benchmark_ivc_flows.sh

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,12 @@ function run_bb_cli_bench {
167167
}
168168
else # wasm
169169
export WASMTIME_ALLOWED_DIRS="--dir=$flow_folder --dir=$output"
170-
# Add --bench_out_hierarchical flag for wasm builds to capture hierarchical op counts and timings
171-
# Note: --memory_profile_out is native-only (getrusage not available in wasm)
172-
memusage scripts/wasmtime.sh $WASMTIME_ALLOWED_DIRS ./build-wasm-threads/bin/bb "$@" "--bench_out_hierarchical" "$output/benchmark_breakdown.json" || {
173-
echo "bb wasm failed with args: $@ --bench_out_hierarchical $output/benchmark_breakdown.json"
170+
# No --bench_out_hierarchical or --memory_profile_out here: BB_BENCH instrumentation is compiled out
171+
# of wasm builds (ENABLE_WASM_BENCH is OFF in the wasm-threads preset to keep the shipped wasm fast),
172+
# and --memory_profile_out is native-only (getrusage not available in wasm).
173+
# Only wall-clock time and peak memory are measured for wasm.
174+
memusage scripts/wasmtime.sh $WASMTIME_ALLOWED_DIRS ./build-wasm-threads/bin/bb "$@" || {
175+
echo "bb wasm failed with args: $@"
174176
print_chonk_flow_reuse_hint "$runtime" "$flow_folder"
175177
exit 1
176178
}
@@ -262,7 +264,8 @@ chonk_flow "$runtime_arg" "$resolved_chonk_flow_folder"
262264
runtime="$runtime_arg"
263265
flow_name="$(basename "$resolved_chonk_flow_folder")"
264266

265-
if [[ "${CI:-}" == "1" ]] && [[ "${CI_USE_BUILD_INSTANCE_KEY:-0}" == "1" ]]; then
267+
# Breakdown and memory profile only exist for native runs (BB_BENCH is compiled out of wasm builds).
268+
if [[ "$runtime" == "native" ]] && [[ "${CI:-}" == "1" ]] && [[ "${CI_USE_BUILD_INSTANCE_KEY:-0}" == "1" ]]; then
266269
echo_header "Uploading Barretenberg benchmark breakdowns for $flow_name"
267270

268271
current_sha=$(git rev-parse HEAD)

barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mega_honk.bench.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,20 @@ BENCHMARK(construct_proof_megahonk_power_of_2)
9494

9595
int main(int argc, char** argv)
9696
{
97+
#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
9798
bb::detail::use_bb_bench = true;
99+
#endif
98100

99101
::benchmark::Initialize(&argc, argv);
100102
if (::benchmark::ReportUnrecognizedArguments(argc, argv))
101103
return 1;
102104
::benchmark::RunSpecifiedBenchmarks();
103105
::benchmark::Shutdown();
104106

107+
#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
105108
std::cout << "\n=== Detailed BB_BENCH Profiling Stats ===\n";
106109
bb::detail::GLOBAL_BENCH_STATS.print_aggregate_counts_hierarchical(std::cout);
110+
#endif
107111

108112
return 0;
109113
}

barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk.bench.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,10 @@ BENCHMARK(construct_proof_ultrahonk_1M_gates_dyadic_2_21)->Unit(kMillisecond);
173173

174174
int main(int argc, char** argv)
175175
{
176+
#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
176177
// Enable BB_BENCH profiling
177178
bb::detail::use_bb_bench = true;
179+
#endif
178180

179181
// Run benchmarks
180182
::benchmark::Initialize(&argc, argv);
@@ -183,9 +185,11 @@ int main(int argc, char** argv)
183185
::benchmark::RunSpecifiedBenchmarks();
184186
::benchmark::Shutdown();
185187

188+
#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
186189
// Print detailed profiling stats
187190
std::cout << "\n=== Detailed BB_BENCH Profiling Stats ===\n";
188191
bb::detail::GLOBAL_BENCH_STATS.print_aggregate_counts_hierarchical(std::cout);
192+
#endif
189193

190194
return 0;
191195
}

barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_builder_arithmetic.test.cpp

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -543,29 +543,22 @@ TEST_F(UltraCircuitBuilderArithmetic, QArith3Gate)
543543
uint32_t w4_next_idx = builder.add_variable(w_4_next);
544544

545545
// Gate 1: q_arith = 3
546-
builder.blocks.arithmetic.populate_wires(w1_idx, w2_idx, w3_idx, w4_idx);
547-
builder.blocks.arithmetic.q_m().emplace_back(q_m);
548-
builder.blocks.arithmetic.q_1().emplace_back(q_1);
549-
builder.blocks.arithmetic.q_2().emplace_back(q_2);
550-
builder.blocks.arithmetic.q_3().emplace_back(q_3);
551-
builder.blocks.arithmetic.q_4().emplace_back(q_4);
552-
builder.blocks.arithmetic.q_5().emplace_back(0);
553-
builder.blocks.arithmetic.q_c().emplace_back(q_c);
554-
builder.blocks.arithmetic.set_gate_selector(GateKind::Arith, 3);
555-
builder.check_selector_length_consistency();
546+
builder.blocks.arithmetic.append_gate({ .wires = { w1_idx, w2_idx, w3_idx, w4_idx },
547+
.q_m = q_m,
548+
.q_c = q_c,
549+
.q_1 = q_1,
550+
.q_2 = q_2,
551+
.q_3 = q_3,
552+
.q_4 = q_4,
553+
.gate_kind = GateKind::Arith,
554+
.gate_value = 3 });
556555
builder.increment_num_gates();
557556

558557
// Gate 2: provides w_1_shift and w_4_shift
559-
builder.blocks.arithmetic.populate_wires(w1_next_idx, builder.zero_idx(), builder.zero_idx(), w4_next_idx);
560-
builder.blocks.arithmetic.q_m().emplace_back(0);
561-
builder.blocks.arithmetic.q_1().emplace_back(0);
562-
builder.blocks.arithmetic.q_2().emplace_back(0);
563-
builder.blocks.arithmetic.q_3().emplace_back(0);
564-
builder.blocks.arithmetic.q_4().emplace_back(0);
565-
builder.blocks.arithmetic.q_5().emplace_back(0);
566-
builder.blocks.arithmetic.q_c().emplace_back(0);
567-
builder.blocks.arithmetic.set_gate_selector(GateKind::Arith, 1);
568-
builder.check_selector_length_consistency();
558+
builder.blocks.arithmetic.append_gate(
559+
{ .wires = { w1_next_idx, builder.zero_idx(), builder.zero_idx(), w4_next_idx },
560+
.gate_kind = GateKind::Arith,
561+
.gate_value = 1 });
569562
builder.increment_num_gates();
570563

571564
if (expect_valid) {

0 commit comments

Comments
 (0)