blob: 4c79c4f74f4d0aead890a8aaad058d13a9fcd180 [file]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#include <benchmark/benchmark.h>
#include <Eigen/Core>
#include "benchmark_boolean_helpers.h"
namespace Eigen {
namespace {
using namespace benchmark_detail;
struct AllVisitor {
static bool run(const BoolArray& input) { return input.all(); }
static bool reference(const BoolArray& input) {
for (Index i = 0; i < input.size(); ++i)
if (!input[i]) return false;
return true;
}
};
struct AnyVisitor {
static bool run(const BoolArray& input) { return input.any(); }
static bool reference(const BoolArray& input) {
for (Index i = 0; i < input.size(); ++i)
if (input[i]) return true;
return false;
}
};
template <typename Operation, InputPattern Pattern>
void BM_BooleanVisitor(benchmark::State& state) {
const Index size = state.range(0);
BoolArray input(size);
fill_input<Pattern>(input, 0x12345678u);
bool result = false;
for (auto _ : state) {
benchmark::ClobberMemory();
result = Operation::run(input);
benchmark::DoNotOptimize(result);
}
if (result != Operation::reference(input)) state.SkipWithError("visitor result does not match the scalar reference");
}
#define EIGEN_BENCH_BOOLEAN_VISITOR(OPERATION) \
BENCHMARK_TEMPLATE(BM_BooleanVisitor, OPERATION, Random)->Arg(262151); \
BENCHMARK_TEMPLATE(BM_BooleanVisitor, OPERATION, AllFalse)->Arg(262151); \
BENCHMARK_TEMPLATE(BM_BooleanVisitor, OPERATION, AllTrue)->Arg(262151); \
BENCHMARK_TEMPLATE(BM_BooleanVisitor, OPERATION, FirstTrue)->Arg(262151); \
BENCHMARK_TEMPLATE(BM_BooleanVisitor, OPERATION, LastTrue)->Arg(262151); \
BENCHMARK_TEMPLATE(BM_BooleanVisitor, OPERATION, FirstFalse)->Arg(262151); \
BENCHMARK_TEMPLATE(BM_BooleanVisitor, OPERATION, LastFalse)->Arg(262151)
EIGEN_BENCH_BOOLEAN_VISITOR(AllVisitor);
EIGEN_BENCH_BOOLEAN_VISITOR(AnyVisitor);
#undef EIGEN_BENCH_BOOLEAN_VISITOR
template <typename Packet>
struct PacketAny {
static bool run(const Packet& packet) { return internal::predux_any(packet); }
static bool reference(bool any, bool) { return any; }
};
template <typename Packet>
struct PacketOr {
static bool run(const Packet& packet) { return internal::predux(packet); }
static bool reference(bool any, bool) { return any; }
};
template <typename Packet>
struct PacketAnd {
static bool run(const Packet& packet) { return internal::predux_mul(packet); }
static bool reference(bool, bool all) { return all; }
};
template <typename Packet, template <typename> class Operation, InputPattern Pattern>
void BM_PacketReduction(benchmark::State& state) {
using Scalar = typename internal::unpacket_traits<Packet>::type;
constexpr int PacketSize = internal::unpacket_traits<Packet>::size;
alignas(internal::unpacket_traits<Packet>::alignment) Scalar input[PacketSize];
std::uint32_t randomState = 0x12345678u;
for (int i = 0; i < PacketSize; ++i) {
randomState = randomState * 1664525u + 1013904223u;
const bool value = Pattern == AllTrue || Pattern == FirstFalse || Pattern == LastFalse ||
(Pattern == Random && (randomState >> 31) != 0);
input[i] = Scalar(value);
}
if (Pattern == FirstTrue) input[0] = Scalar(1);
if (Pattern == LastTrue) input[PacketSize - 1] = Scalar(1);
if (Pattern == FirstFalse) input[0] = Scalar(0);
if (Pattern == LastFalse) input[PacketSize - 1] = Scalar(0);
Packet packet = internal::pload<Packet>(input);
bool result = false;
for (auto _ : state) {
benchmark::DoNotOptimize(packet);
result = Operation<Packet>::run(packet);
benchmark::DoNotOptimize(result);
}
bool any = false;
bool all = true;
for (int i = 0; i < PacketSize; ++i) {
any = any || input[i] != Scalar(0);
all = all && input[i] != Scalar(0);
}
const bool reference = Operation<Packet>::reference(any, all);
if (result != reference) state.SkipWithError("packet result does not match the scalar reference");
state.SetItemsProcessed(state.iterations() * PacketSize);
}
#ifdef EIGEN_VECTORIZE_SSE
#define EIGEN_BENCH_PACKET16B(OPERATION) \
BENCHMARK_TEMPLATE(BM_PacketReduction, internal::Packet16b, OPERATION, Random); \
BENCHMARK_TEMPLATE(BM_PacketReduction, internal::Packet16b, OPERATION, AllFalse); \
BENCHMARK_TEMPLATE(BM_PacketReduction, internal::Packet16b, OPERATION, AllTrue); \
BENCHMARK_TEMPLATE(BM_PacketReduction, internal::Packet16b, OPERATION, FirstTrue); \
BENCHMARK_TEMPLATE(BM_PacketReduction, internal::Packet16b, OPERATION, LastTrue); \
BENCHMARK_TEMPLATE(BM_PacketReduction, internal::Packet16b, OPERATION, FirstFalse); \
BENCHMARK_TEMPLATE(BM_PacketReduction, internal::Packet16b, OPERATION, LastFalse)
EIGEN_BENCH_PACKET16B(PacketOr);
EIGEN_BENCH_PACKET16B(PacketAnd);
#undef EIGEN_BENCH_PACKET16B
#endif
#ifdef EIGEN_VECTORIZE_AVX512
#define EIGEN_BENCH_AVX512_PACKET(PACKET) \
BENCHMARK_TEMPLATE(BM_PacketReduction, PACKET, PacketAny, Random); \
BENCHMARK_TEMPLATE(BM_PacketReduction, PACKET, PacketAny, AllFalse); \
BENCHMARK_TEMPLATE(BM_PacketReduction, PACKET, PacketAny, AllTrue); \
BENCHMARK_TEMPLATE(BM_PacketReduction, PACKET, PacketAny, FirstTrue); \
BENCHMARK_TEMPLATE(BM_PacketReduction, PACKET, PacketAny, LastTrue)
EIGEN_BENCH_AVX512_PACKET(internal::Packet16i);
EIGEN_BENCH_AVX512_PACKET(internal::Packet8l);
EIGEN_BENCH_AVX512_PACKET(internal::Packet16f);
EIGEN_BENCH_AVX512_PACKET(internal::Packet8d);
#ifdef EIGEN_VECTORIZE_AVX512FP16
EIGEN_BENCH_AVX512_PACKET(internal::Packet32h);
EIGEN_BENCH_AVX512_PACKET(internal::Packet16h);
EIGEN_BENCH_AVX512_PACKET(internal::Packet8h);
#endif
#undef EIGEN_BENCH_AVX512_PACKET
#endif
} // namespace
} // namespace Eigen