52#include <benchmark/benchmark.h>
55using namespace benchmark;
64constexpr size_t N = 1 << 16;
83 for (
size_t i = 0; i <
N; ++i) {
91 void reset_self(State& state)
103struct CorrectnessGuard {
106 constexpr size_t M =
N;
110 for (
size_t i = 0; i < M; ++i) {
121 for (
size_t i = 0; i < M; ++i) {
122 a_ref.
at(i) = a_ref.
at(i) +
b.at(i) * s;
125 for (
size_t i = 0; i < M; ++i) {
126 if (!(
a.at(i) == a_ref.
at(i))) {
127 std::fprintf(stderr,
"[ADD_SCALED CORRECTNESS] mismatch at i=%zu\n", i);
133static const CorrectnessGuard correctness_guard;
136static void bench_add_scaled_scalar(State& state)
140 auto& other = f.other;
141 auto scaling = f.scaling;
142 for (
auto _ : state) {
144 for (
size_t i = 0; i <
N; ++i) {
145 self.at(i) = self.at(i) + other.at(i) * scaling;
147 DoNotOptimize(self.at(0));
152static void bench_add_scaled_vectorized_inline(State& state)
156 auto& other = f.other;
157 auto scaling = f.scaling;
163 for (
auto _ : state) {
165 vectorized_for<bb::VECTOR_FIELD_WIDTH, fr>(
166 0,
N, [&](
auto ctx) { self[ctx] = self[ctx] + other[ctx] * scaling_b[ctx]; });
167 DoNotOptimize(self.at(0));
172static void bench_add_scaled_vector_field_raw(State& state)
176 auto& other = f.other;
177 auto scaling = f.scaling;
186 for (
auto _ : state) {
189 const fr* o = other.
data();
191 for (; i + 5 <=
N; i += 5) {
194 (sv + ov * scaling_v).store_to(s + i);
198 s[i] = s[i] + o[i] * scaling;
200 DoNotOptimize(self.at(0));
213static void bench_add_scaled_bulk_transpose(State& state)
217 auto& other = f.other;
218 auto scaling = f.scaling;
221 constexpr size_t bulk_count =
N / 5;
222 constexpr size_t tail_count =
N % 5;
230 Vec* self_buf = self_inter.data();
231 Vec* other_buf = other_inter.data();
234 for (
auto _ : state) {
237 const fr* o = other.
data();
241 for (
size_t i = 0; i < bulk_count; ++i) {
242 self_buf[i] =
Vec(s + i * 5);
245 for (
size_t i = 0; i < bulk_count; ++i) {
246 other_buf[i] =
Vec(o + i * 5);
250 for (
size_t i = 0; i < bulk_count; ++i) {
251 self_buf[i] = self_buf[i] + other_buf[i] * scaling_v;
254 for (
size_t i = 0; i < bulk_count; ++i) {
258 for (
size_t i = bulk_count * 5; i <
N; ++i) {
259 s[i] = s[i] + o[i] * scaling;
261 DoNotOptimize(self.at(0));
267static void bench_add_scaled_full(State& state)
271 auto& other = f.other;
272 auto scaling = f.scaling;
273 for (
auto _ : state) {
276 DoNotOptimize(self.at(0));
292static void bench_add_scaled_kernel_only(State& state)
295 auto& other = f.other;
296 auto scaling = f.scaling;
299 constexpr size_t bulk_count =
N / 5;
303 Vec* self_buf = self_inter.data();
304 Vec* other_buf = other_inter.data();
307 const fr* s = f.self_ref.data();
308 const fr* o = other.
data();
309 for (
size_t i = 0; i < bulk_count; ++i) {
310 self_buf[i] =
Vec(s + i * 5);
311 other_buf[i] =
Vec(o + i * 5);
315 for (
auto _ : state) {
316 for (
size_t i = 0; i < bulk_count; ++i) {
317 self_buf[i] = self_buf[i] + other_buf[i] * scaling_v;
319 DoNotOptimize(self_buf[0]);
332static void bench_add_scaled_kernel_plus_writeback(State& state)
336 auto& other = f.other;
337 auto scaling = f.scaling;
340 constexpr size_t bulk_count =
N / 5;
344 Vec* self_buf = self_inter.data();
345 Vec* other_buf = other_inter.data();
348 const fr* s = f.self_ref.data();
349 const fr* o = other.
data();
350 for (
size_t i = 0; i < bulk_count; ++i) {
351 self_buf[i] =
Vec(s + i * 5);
352 other_buf[i] =
Vec(o + i * 5);
356 for (
auto _ : state) {
359 for (
size_t i = 0; i < bulk_count; ++i) {
360 self_buf[i] = self_buf[i] + other_buf[i] * scaling_v;
363 for (
size_t i = 0; i < bulk_count; ++i) {
366 DoNotOptimize(self.at(0));
375static void bench_load_contiguous_only(State& state)
379 auto& other = f.other;
382 constexpr size_t bulk_count =
N / 5;
385 Vec* sink_buf = sink.data();
387 for (
auto _ : state) {
388 const fr* s = self.
data();
389 const fr* o = other.
data();
390 for (
size_t i = 0; i < bulk_count; ++i) {
391 sink_buf[i] =
Vec(s + i * 5);
393 for (
size_t i = 0; i < bulk_count; ++i) {
394 sink_buf[i] =
Vec(o + i * 5);
396 DoNotOptimize(sink_buf[0]);
403static void bench_store_contiguous_only(State& state)
409 constexpr size_t bulk_count =
N / 5;
412 Vec* src_buf = src.data();
414 const fr* s = f.self_ref.data();
415 for (
size_t i = 0; i < bulk_count; ++i) {
416 src_buf[i] =
Vec(s + i * 5);
420 for (
auto _ : state) {
422 for (
size_t i = 0; i < bulk_count; ++i) {
425 DoNotOptimize(self.at(0));
433static void bench_memcpy_only(State& state)
439 constexpr size_t bulk_count =
N / 5;
442 Vec* sink_buf = sink.data();
444 for (
auto _ : state) {
445 const fr* s = self.
data();
446 for (
size_t i = 0; i < bulk_count; ++i) {
449 DoNotOptimize(sink_buf[0]);
BENCHMARK(bench_add_scaled_scalar)
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
void vectorized_for(size_t start, size_t end, K &&kernel)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
static VectorField broadcast(const Field &s) noexcept
void store_to(Field *base) const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept
bb::VectorField< bb::Bn254FrParams > Vec