blob: 420e6605bd6ae70143ec97a5162089d65712cb9b [file]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#include <benchmark/benchmark.h>
#include <Eigen/Core>
#include <cstdint>
namespace Eigen {
namespace {
using BoolArray = Array<bool, Dynamic, 1>;
enum InputPattern { Random, AllFalse, AllTrue, Sparse };
template <InputPattern Pattern>
bool next_input(std::uint32_t& state) {
state = state * 1664525u + 1013904223u;
return Pattern == AllFalse ? false : Pattern == AllTrue ? true : Pattern == Sparse ? state % 10 == 0 : state >> 31;
}
template <InputPattern Pattern>
void fill_input(BoolArray& input, std::uint32_t state) {
for (Index i = 0; i < input.size(); ++i) input[i] = next_input<Pattern>(state);
}
struct Sum {
static bool run(const BoolArray& input) { return input.sum(); }
static bool reference(bool accum, bool value) { return accum || value; }
static bool identity() { return false; }
};
struct Product {
static bool run(const BoolArray& input) { return input.prod(); }
static bool reference(bool accum, bool value) { return accum && value; }
static bool identity() { return true; }
};
template <typename Operation, InputPattern Pattern>
void BM_BooleanReduction(benchmark::State& state) {
const Index size = state.range(0);
BoolArray input(size);
fill_input<Pattern>(input, 0x12345678u);
bool result = Operation::identity();
for (auto _ : state) {
result = Operation::run(input);
benchmark::DoNotOptimize(result);
}
bool reference = Operation::identity();
for (Index i = 0; i < size; ++i) reference = Operation::reference(reference, input[i]);
if (result != reference) state.SkipWithError("reduction result does not match the boolean reference");
state.SetItemsProcessed(state.iterations() * size);
}
struct LogicalAnd {
static void run(BoolArray& result, const BoolArray& lhs, const BoolArray& rhs) { result = lhs && rhs; }
static bool reference(bool lhs, bool rhs) { return lhs && rhs; }
};
struct LogicalOr {
static void run(BoolArray& result, const BoolArray& lhs, const BoolArray& rhs) { result = lhs || rhs; }
static bool reference(bool lhs, bool rhs) { return lhs || rhs; }
};
template <typename Operation, InputPattern Pattern>
void BM_BooleanBinary(benchmark::State& state) {
const Index size = state.range(0);
BoolArray lhs(size);
BoolArray rhs(size);
BoolArray result(size);
fill_input<Pattern>(lhs, 0x12345678u);
fill_input<Pattern>(rhs, 0x87654321u);
for (auto _ : state) {
Operation::run(result, lhs, rhs);
benchmark::DoNotOptimize(result.data());
benchmark::ClobberMemory();
}
for (Index i = 0; i < size; ++i) {
if (result[i] != Operation::reference(lhs[i], rhs[i])) {
state.SkipWithError("binary result does not match the boolean reference");
break;
}
}
state.SetItemsProcessed(state.iterations() * size);
}
#define EIGEN_BENCH_BOOLEAN_PATTERNS(BENCHMARK_FUNCTION, OPERATION) \
BENCHMARK_TEMPLATE(BENCHMARK_FUNCTION, OPERATION, Random)->Arg(262151); \
BENCHMARK_TEMPLATE(BENCHMARK_FUNCTION, OPERATION, AllFalse)->Arg(262151); \
BENCHMARK_TEMPLATE(BENCHMARK_FUNCTION, OPERATION, AllTrue)->Arg(262151); \
BENCHMARK_TEMPLATE(BENCHMARK_FUNCTION, OPERATION, Sparse)->Arg(262151)
EIGEN_BENCH_BOOLEAN_PATTERNS(BM_BooleanReduction, Sum);
EIGEN_BENCH_BOOLEAN_PATTERNS(BM_BooleanReduction, Product);
EIGEN_BENCH_BOOLEAN_PATTERNS(BM_BooleanBinary, LogicalAnd);
EIGEN_BENCH_BOOLEAN_PATTERNS(BM_BooleanBinary, LogicalOr);
#undef EIGEN_BENCH_BOOLEAN_PATTERNS
} // namespace
} // namespace Eigen