blob: 6a5c931f600ccf4330a948c0e2bb175a34d91a77 [file]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#include <benchmark/benchmark.h>
#include <Eigen/Core>
using namespace Eigen;
template <int Operation, typename Dst, typename Lhs, typename Rhs>
static void outer_product(Dst& dst, const Lhs& lhs, const Rhs& rhs) {
if (Operation == 0) dst.noalias() = lhs * rhs;
if (Operation == 1) dst.noalias() += lhs * rhs;
if (Operation == 2) dst.noalias() -= lhs * rhs;
}
template <typename LhsScalar, typename RhsScalar, int Order, int Operation>
static void BM_OuterProduct(benchmark::State& state) {
using Scalar = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar>::ReturnType;
using Real = typename NumTraits<Scalar>::Real;
using Lhs = Matrix<LhsScalar, Dynamic, 1>;
using Rhs = Matrix<RhsScalar, 1, Dynamic>;
static_assert(internal::product_type<Lhs, Rhs>::value == OuterProduct, "Exercise the outer-product selector");
const Index rows = state.range(0), cols = state.range(1);
const Lhs lhs = Lhs::Random(rows);
const Rhs rhs = Rhs::Random(cols);
Matrix<Scalar, Dynamic, Dynamic, Order> dst =
Matrix<Scalar, Dynamic, Dynamic, Order>::Constant(rows, cols, Scalar(1));
outer_product<Operation>(dst, lhs, rhs);
for (Index j = 0; j < cols; ++j) {
for (Index i = 0; i < rows; ++i) {
const Scalar value = lhs(i) * rhs(j);
const Scalar expected = Operation == 0 ? value : Operation == 1 ? Scalar(1) + value : Scalar(1) - value;
const Real bound = Real(8) * NumTraits<Real>::epsilon() * (Real(1) + numext::abs(value));
if (!(numext::abs(dst(i, j) - expected) <= bound)) {
state.SkipWithError("Outer product disagrees with the scalar reference");
return;
}
}
}
for (auto _ : state) {
outer_product<Operation>(dst, lhs, rhs);
benchmark::DoNotOptimize(dst.data());
benchmark::ClobberMemory();
}
state.SetItemsProcessed(state.iterations() * rows * cols);
}
// Include both sides of the small-assignment threshold and rectangular tails.
#define OUTER_SIZES \
->Args({3, 3}) \
->Args({4, 4}) \
->Args({8, 8}) \
->Args({15, 15}) \
->Args({16, 16}) \
->Args({17, 17}) \
->Args({32, 32}) \
->Args({128, 128}) \
->Args({3, 16}) \
->Args({16, 3}) \
->Args({3, 17}) \
->Args({17, 3})
#define OUTER_OPERATIONS(LHS, RHS, ORDER) \
BENCHMARK_TEMPLATE(BM_OuterProduct, LHS, RHS, ORDER, 0) OUTER_SIZES; \
BENCHMARK_TEMPLATE(BM_OuterProduct, LHS, RHS, ORDER, 1) OUTER_SIZES; \
BENCHMARK_TEMPLATE(BM_OuterProduct, LHS, RHS, ORDER, 2) OUTER_SIZES
#define OUTER_LAYOUTS(LHS, RHS) \
OUTER_OPERATIONS(LHS, RHS, ColMajor); \
OUTER_OPERATIONS(LHS, RHS, RowMajor)
OUTER_LAYOUTS(float, float);
OUTER_LAYOUTS(double, double);
OUTER_LAYOUTS(std::complex<float>, std::complex<float>);
OUTER_LAYOUTS(std::complex<double>, std::complex<double>);
OUTER_LAYOUTS(float, std::complex<float>);
OUTER_LAYOUTS(std::complex<float>, float);
OUTER_LAYOUTS(double, std::complex<double>);
OUTER_LAYOUTS(std::complex<double>, double);
#undef OUTER_LAYOUTS
#undef OUTER_OPERATIONS
#undef OUTER_SIZES