Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
vector_field.bench.cpp
Go to the documentation of this file.
1// Benchmarks VectorField's batched q1s1 kernels (5 fields/call: 1 scalar + 1
2// quad) against the plain field<Bn254FrParams> baseline (1 field/op).
3//
4// Reports ns/field so the speedup number is directly comparable to the
5// field-bench-v2 gist (https://gist.github.com/AztecBot/2ad5f310fd0e8a3badda33487f4536ff):
6//
7// Gist s1q1 on Zen3+V8: add 4.35 ns/field (2.11×), sub 4.53 (2.04×),
8// eq 5.53 (2.01×), is_zero 1.51 (1.24×).
9//
10// Run on WASM via `benchmark_wasm_remote.sh vector_field_bench` for V8
11// numbers; run locally for native-x86_64 numbers (no speedup expected on
12// native since there's no SIMD code path wired in for native yet).
13
16
17#include <array>
18#include <benchmark/benchmark.h>
19
20using namespace benchmark;
21using bb::fr;
23
24// How many ops per benchmark iteration. Loop runs ITERATIONS ops, so
25// per-op time = reported time / ITERATIONS.
26static constexpr int64_t ITERATIONS = 256;
27
28// ---------------------------------------------------------------------------
29// Baselines: plain field<>. Each iteration of the outer loop does
30// ITERATIONS * 5 scalar ops so the reported time is directly comparable to
31// the batched kernel (which does ITERATIONS calls × 5 fields/call).
32// ---------------------------------------------------------------------------
33
34static void bench_scalar_add(State& state)
35{
36 fr a[5];
37 fr b[5];
38 for (size_t i = 0; i < 5; ++i) {
39 a[i] = fr::random_element();
40 b[i] = fr::random_element();
41 }
42 for (auto _ : state) {
43 for (int64_t it = 0; it < ITERATIONS; ++it) {
44 for (size_t i = 0; i < 5; ++i) {
45 a[i] = a[i] + b[i];
46 DoNotOptimize(a[i]);
47 }
48 }
49 }
50 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * ITERATIONS * 5);
51}
52BENCHMARK(bench_scalar_add);
53
54static void bench_scalar_sub(State& state)
55{
56 fr a[5];
57 fr b[5];
58 for (size_t i = 0; i < 5; ++i) {
59 a[i] = fr::random_element();
60 b[i] = fr::random_element();
61 }
62 for (auto _ : state) {
63 for (int64_t it = 0; it < ITERATIONS; ++it) {
64 for (size_t i = 0; i < 5; ++i) {
65 a[i] = a[i] - b[i];
66 DoNotOptimize(a[i]);
67 }
68 }
69 }
70 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * ITERATIONS * 5);
71}
72BENCHMARK(bench_scalar_sub);
73
74static void bench_scalar_mul(State& state)
75{
76 fr a[5];
77 fr b[5];
78 for (size_t i = 0; i < 5; ++i) {
79 a[i] = fr::random_element();
80 b[i] = fr::random_element();
81 }
82 for (auto _ : state) {
83 for (int64_t it = 0; it < ITERATIONS; ++it) {
84 for (size_t i = 0; i < 5; ++i) {
85 a[i] = a[i] * b[i];
86 DoNotOptimize(a[i]);
87 }
88 }
89 }
90 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * ITERATIONS * 5);
91}
92BENCHMARK(bench_scalar_mul);
93
94static void bench_scalar_eq(State& state)
95{
96 fr a[5];
97 fr b[5];
98 for (size_t i = 0; i < 5; ++i) {
99 a[i] = fr::random_element();
100 b[i] = fr::random_element();
101 }
102 volatile int sink = 0;
103 for (auto _ : state) {
104 for (int64_t it = 0; it < ITERATIONS; ++it) {
105 int s = 0;
106 for (size_t i = 0; i < 5; ++i) {
107 s += (a[i] == b[i]) ? 1 : 0;
108 }
109 sink += s;
110 DoNotOptimize(sink);
111 }
112 }
113 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * ITERATIONS * 5);
114}
115BENCHMARK(bench_scalar_eq);
116
117static void bench_scalar_is_zero(State& state)
118{
119 fr a[5];
120 for (size_t i = 0; i < 5; ++i) {
121 a[i] = fr::random_element();
122 }
123 a[2] = fr::zero(); // make one zero to keep branch prediction honest
124 volatile int sink = 0;
125 for (auto _ : state) {
126 for (int64_t it = 0; it < ITERATIONS; ++it) {
127 int s = 0;
128 for (size_t i = 0; i < 5; ++i) {
129 s += a[i].is_zero() ? 1 : 0;
130 }
131 sink += s;
132 DoNotOptimize(sink);
133 }
134 }
135 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * ITERATIONS * 5);
136}
137BENCHMARK(bench_scalar_is_zero);
138
139// ---------------------------------------------------------------------------
140// VectorField batched kernels. Same total work per iteration as the
141// baselines (ITERATIONS * 5 fields), but issued as ITERATIONS batch calls.
142// ---------------------------------------------------------------------------
143
144static void bench_vector_add(State& state)
145{
148 };
151 };
152 Vec a(a_in), b(b_in);
153 for (auto _ : state) {
154 for (int64_t it = 0; it < ITERATIONS; ++it) {
155 a = a + b;
156 DoNotOptimize(a);
157 }
158 }
159 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * ITERATIONS * 5);
160}
161BENCHMARK(bench_vector_add);
162
163static void bench_vector_sub(State& state)
164{
167 };
170 };
171 Vec a(a_in), b(b_in);
172 for (auto _ : state) {
173 for (int64_t it = 0; it < ITERATIONS; ++it) {
174 a = a - b;
175 DoNotOptimize(a);
176 }
177 }
178 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * ITERATIONS * 5);
179}
180BENCHMARK(bench_vector_sub);
181
182static void bench_vector_mul(State& state)
183{
186 };
189 };
190 Vec a(a_in), b(b_in);
191 for (auto _ : state) {
192 for (int64_t it = 0; it < ITERATIONS; ++it) {
193 a = a * b;
194 DoNotOptimize(a);
195 }
196 }
197 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * ITERATIONS * 5);
198}
199BENCHMARK(bench_vector_mul);
200
201static void bench_vector_eq(State& state)
202{
205 };
208 };
209 Vec a(a_in), b(b_in);
210 volatile uint32_t sink = 0;
211 for (auto _ : state) {
212 for (int64_t it = 0; it < ITERATIONS; ++it) {
213 sink += a.eq_mask(b);
214 DoNotOptimize(sink);
215 }
216 }
217 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * ITERATIONS * 5);
218}
219BENCHMARK(bench_vector_eq);
220
221static void bench_vector_is_zero(State& state)
222{
224 Vec a(a_in);
225 volatile uint32_t sink = 0;
226 for (auto _ : state) {
227 for (int64_t it = 0; it < ITERATIONS; ++it) {
228 sink += a.is_zero_mask();
229 DoNotOptimize(sink);
230 }
231 }
232 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * ITERATIONS * 5);
233}
234BENCHMARK(bench_vector_is_zero);
235
FF a
FF b
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr bool is_zero() const noexcept
static constexpr field zero()
BENCHMARK(bench_scalar_add)
BENCHMARK_MAIN()