blob: a97cba5f4ddbea47865699cfb4430e34a2b63b3e [file]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#include <benchmark/benchmark.h>
#include <Eigen/Core>
using namespace Eigen;
#ifndef SCALAR
#define SCALAR float
#endif
using Scalar = SCALAR;
using Mat = Matrix<Scalar, Dynamic, Dynamic>;
template <typename T>
struct ScaledGemmAlpha {
static T value() { return T(1.375); }
};
template <typename T>
struct ScaledGemmAlpha<std::complex<T>> {
static std::complex<T> value() { return std::complex<T>(T(1.375), T(-0.625)); }
};
template <typename A, typename B, typename C>
EIGEN_DONT_INLINE void gemm_scaled(const A& a, const B& b, C& c, Scalar alpha) {
c.noalias() += alpha * (a * b);
}
static void BM_EigenGemmScaled(benchmark::State& state) {
const Index m = state.range(0), n = state.range(1), k = state.range(2);
const Mat a = Mat::Random(m, k), b = Mat::Random(k, n);
const Scalar alpha = ScaledGemmAlpha<Scalar>::value();
Mat c = Mat::Ones(m, n);
// Check a sampled column independently without timing the reference product.
const Matrix<Scalar, Dynamic, 1> expected = Matrix<Scalar, Dynamic, 1>::Ones(m) + alpha * a.lazyProduct(b.col(0));
gemm_scaled(a, b, c, alpha);
if (!c.col(0).isApprox(expected)) {
state.SkipWithError("scaled GEMM validation failed");
return;
}
for (auto _ : state) {
c.setZero();
gemm_scaled(a, b, c, alpha);
benchmark::DoNotOptimize(c.data());
benchmark::ClobberMemory();
}
constexpr double flops = NumTraits<Scalar>::IsComplex ? 8.0 : 2.0;
state.counters["GFLOPS"] =
benchmark::Counter(flops * m * n * k, benchmark::Counter::kIsIterationInvariantRate, benchmark::Counter::kIs1000);
}
template <typename A, typename B, typename C>
EIGEN_DONT_INLINE void gemm_subtract(const A& a, const B& b, C& c) {
c.noalias() -= a * b;
}
// C -= A*B: alpha = -1, the real-alpha store path for complex scalars.
static void BM_EigenGemmSubtract(benchmark::State& state) {
const Index m = state.range(0), n = state.range(1), k = state.range(2);
const Mat a = Mat::Random(m, k), b = Mat::Random(k, n);
Mat c = Mat::Ones(m, n);
const Matrix<Scalar, Dynamic, 1> expected = Matrix<Scalar, Dynamic, 1>::Ones(m) - a.lazyProduct(b.col(0));
gemm_subtract(a, b, c);
if (!c.col(0).isApprox(expected)) {
state.SkipWithError("GEMM subtraction validation failed");
return;
}
for (auto _ : state) {
c.setZero();
gemm_subtract(a, b, c);
benchmark::DoNotOptimize(c.data());
benchmark::ClobberMemory();
}
constexpr double flops = NumTraits<Scalar>::IsComplex ? 8.0 : 2.0;
state.counters["GFLOPS"] =
benchmark::Counter(flops * m * n * k, benchmark::Counter::kIsIterationInvariantRate, benchmark::Counter::kIs1000);
}
// clang-format off
#define EIGEN_GEMM_SCALED_SHAPES \
->Args({8, 8, 8})->Args({16, 16, 16})->Args({32, 32, 32})->Args({64, 64, 64})->Args({128, 128, 128}) \
->ArgsProduct({{8, 24, 40, 264, 520, 16, 32, 256, 1024}, {256, 1024}, {256, 1024}}) \
->Args({4096, 96, 96})->Args({4096, 128, 128})->Args({4096, 144, 144}) \
->Args({4096, 160, 160})->Args({4096, 176, 176})->Args({8192, 128, 128})
BENCHMARK(BM_EigenGemmScaled) EIGEN_GEMM_SCALED_SHAPES;
BENCHMARK(BM_EigenGemmSubtract) EIGEN_GEMM_SCALED_SHAPES;
// clang-format on