blob: 21a12beae60a4d22e865ed4f22af7f0fda223a9d [file]
// Benchmarks for Eigen TensorInflation (zero-interleaved upsampling views).
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#include <benchmark/benchmark.h>
#include <contrib/Eigen/Tensor>
using namespace Eigen;
typedef float Scalar;
// --- Inflate only the inner-most (contiguous) dimension. ---
static void BM_Inflate2D_Inner(benchmark::State& state) {
const Index M = state.range(0);
const Index N = state.range(1);
const Index S = state.range(2);
Tensor<Scalar, 2> A(M, N);
A.setRandom();
Eigen::array<Index, 2> strides = {S, 1};
Tensor<Scalar, 2> B;
for (auto _ : state) {
B = A.inflate(strides);
benchmark::DoNotOptimize(B.data());
benchmark::ClobberMemory();
}
for (Index i = 0; i < B.dimension(0); ++i) {
for (Index j = 0; j < B.dimension(1); ++j) {
const Scalar expected = (i % S == 0) ? A(i / S, j) : Scalar(0);
if (B(i, j) != expected) {
state.SkipWithError("validation failed");
return;
}
}
}
state.SetItemsProcessed(state.iterations() * B.size());
}
// --- Inflate only an outer dimension. Inner dim stays contiguous. ---
static void BM_Inflate2D_Outer(benchmark::State& state) {
const Index M = state.range(0);
const Index N = state.range(1);
const Index S = state.range(2);
Tensor<Scalar, 2> A(M, N);
A.setRandom();
Eigen::array<Index, 2> strides = {1, S};
Tensor<Scalar, 2> B;
for (auto _ : state) {
B = A.inflate(strides);
benchmark::DoNotOptimize(B.data());
benchmark::ClobberMemory();
}
for (Index i = 0; i < B.dimension(0); ++i) {
for (Index j = 0; j < B.dimension(1); ++j) {
const Scalar expected = (j % S == 0) ? A(i, j / S) : Scalar(0);
if (B(i, j) != expected) {
state.SkipWithError("validation failed");
return;
}
}
}
state.SetItemsProcessed(state.iterations() * B.size());
}
// --- Inflate every dimension. ---
static void BM_Inflate2D_All(benchmark::State& state) {
const Index M = state.range(0);
const Index N = state.range(1);
const Index S = state.range(2);
Tensor<Scalar, 2> A(M, N);
A.setRandom();
Eigen::array<Index, 2> strides = {S, S};
Tensor<Scalar, 2> B;
for (auto _ : state) {
B = A.inflate(strides);
benchmark::DoNotOptimize(B.data());
benchmark::ClobberMemory();
}
for (Index i = 0; i < B.dimension(0); ++i) {
for (Index j = 0; j < B.dimension(1); ++j) {
const Scalar expected = (i % S == 0 && j % S == 0) ? A(i / S, j / S) : Scalar(0);
if (B(i, j) != expected) {
state.SkipWithError("validation failed");
return;
}
}
}
state.SetItemsProcessed(state.iterations() * B.size());
}
// --- Expression-sourced inflation (no raw buffer behind the argument) ---
static void BM_Inflate2D_Expr(benchmark::State& state) {
const Index M = state.range(0);
const Index N = state.range(1);
const Index S = state.range(2);
Tensor<Scalar, 2> A(M, N);
A.setRandom();
Eigen::array<Index, 2> strides = {S, S};
Tensor<Scalar, 2> B;
for (auto _ : state) {
B = (A + A.constant(Scalar(1))).inflate(strides);
benchmark::DoNotOptimize(B.data());
benchmark::ClobberMemory();
}
for (Index i = 0; i < B.dimension(0); ++i) {
for (Index j = 0; j < B.dimension(1); ++j) {
const Scalar expected = (i % S == 0 && j % S == 0) ? A(i / S, j / S) + Scalar(1) : Scalar(0);
if (B(i, j) != expected) {
state.SkipWithError("validation failed");
return;
}
}
}
state.SetItemsProcessed(state.iterations() * B.size());
}
// clang-format off
#define INFLATE_SIZES ->ArgsProduct({{256, 1024}, {1024}, {2, 4}})
// clang-format on
BENCHMARK(BM_Inflate2D_Inner) INFLATE_SIZES;
BENCHMARK(BM_Inflate2D_Outer) INFLATE_SIZES;
BENCHMARK(BM_Inflate2D_All) INFLATE_SIZES;
BENCHMARK(BM_Inflate2D_Expr) INFLATE_SIZES;