libeigen/eigen!2509 Closes #2868 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
136 lines
5.7 KiB
C++
136 lines
5.7 KiB
C++
// SPDX-FileCopyrightText: The Eigen Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
#include <benchmark/benchmark.h>
|
|
#include <Eigen/SVD>
|
|
|
|
using namespace Eigen;
|
|
|
|
// Benchmark the UpperBidiagonalization reduction in isolation,
|
|
// covering both the unblocked and blocked code paths, and
|
|
// sweeping the block size parameter for tuning.
|
|
|
|
template <typename Scalar>
|
|
using Mat = Matrix<Scalar, Dynamic, Dynamic>;
|
|
|
|
// ---------- Blocked (default) path ----------
|
|
|
|
template <typename Scalar>
|
|
static void BM_UpperBidiag_Blocked(benchmark::State& state) {
|
|
const Index rows = state.range(0);
|
|
const Index cols = state.range(1);
|
|
Mat<Scalar> A = Mat<Scalar>::Random(rows, cols);
|
|
internal::UpperBidiagonalization<Mat<Scalar>> ubd(rows, cols);
|
|
for (auto _ : state) {
|
|
ubd.compute(A);
|
|
benchmark::DoNotOptimize(ubd.bidiagonal().toDenseMatrix().data());
|
|
}
|
|
state.SetItemsProcessed(state.iterations());
|
|
}
|
|
|
|
// ---------- Unblocked path ----------
|
|
|
|
template <typename Scalar>
|
|
static void BM_UpperBidiag_Unblocked(benchmark::State& state) {
|
|
const Index rows = state.range(0);
|
|
const Index cols = state.range(1);
|
|
Mat<Scalar> A = Mat<Scalar>::Random(rows, cols);
|
|
internal::UpperBidiagonalization<Mat<Scalar>> ubd(rows, cols);
|
|
for (auto _ : state) {
|
|
ubd.computeUnblocked(A);
|
|
benchmark::DoNotOptimize(ubd.bidiagonal().toDenseMatrix().data());
|
|
}
|
|
state.SetItemsProcessed(state.iterations());
|
|
}
|
|
|
|
// ---------- Blocked with explicit block size ----------
|
|
|
|
template <typename Scalar>
|
|
static void BM_UpperBidiag_BlockSize(benchmark::State& state) {
|
|
const Index rows = state.range(0);
|
|
const Index cols = state.range(1);
|
|
const Index blockSize = state.range(2);
|
|
Mat<Scalar> A = Mat<Scalar>::Random(rows, cols);
|
|
using RealScalar = typename NumTraits<Scalar>::Real;
|
|
using BidiagType = internal::BandMatrix<RealScalar, Dynamic, Dynamic, 1, 0, RowMajor>;
|
|
Mat<Scalar> householder(rows, cols);
|
|
BidiagType bidiagonal(cols, cols);
|
|
for (auto _ : state) {
|
|
householder = A;
|
|
internal::upperbidiagonalization_inplace_blocked(householder, bidiagonal, blockSize);
|
|
benchmark::DoNotOptimize(bidiagonal.toDenseMatrix().data());
|
|
}
|
|
state.SetItemsProcessed(state.iterations());
|
|
state.SetLabel("bs=" + std::to_string(blockSize));
|
|
}
|
|
|
|
// ---------- Size configurations ----------
|
|
|
|
// clang-format off
|
|
|
|
// Small sizes: always hit the unblocked path.
|
|
#define SMALL_SIZES \
|
|
->Args({4, 4})->Args({8, 8})->Args({16, 16})->Args({32, 32}) \
|
|
->Args({16, 4})->Args({32, 8})->Args({32, 16})
|
|
|
|
// Medium sizes: exercise the blocked path.
|
|
#define MEDIUM_SIZES \
|
|
->Args({64, 64})->Args({128, 128})->Args({256, 256})->Args({512, 512}) \
|
|
->Args({256, 64})->Args({512, 64})->Args({512, 128})
|
|
|
|
// Large sizes: dominated by the blocked GEMM updates.
|
|
#define LARGE_SIZES \
|
|
->Args({1024, 1024})->Args({2048, 2048})->Args({4096, 4096}) \
|
|
->Args({2048, 256})->Args({4096, 256})->Args({4096, 1024})
|
|
|
|
// Block size sweep: {rows, cols, blockSize}
|
|
// Square matrices from 128 to 4096, block sizes 16..96.
|
|
#define BLOCKSIZE_SWEEP \
|
|
->Args({128, 128, 16})->Args({128, 128, 32})->Args({128, 128, 48})->Args({128, 128, 64})->Args({128, 128, 96}) \
|
|
->Args({256, 256, 16})->Args({256, 256, 32})->Args({256, 256, 48})->Args({256, 256, 64})->Args({256, 256, 96}) \
|
|
->Args({512, 512, 16})->Args({512, 512, 32})->Args({512, 512, 48})->Args({512, 512, 64})->Args({512, 512, 96}) \
|
|
->Args({1024, 1024, 16})->Args({1024, 1024, 32})->Args({1024, 1024, 48})->Args({1024, 1024, 64})->Args({1024, 1024, 96}) \
|
|
->Args({2048, 2048, 16})->Args({2048, 2048, 32})->Args({2048, 2048, 48})->Args({2048, 2048, 64})->Args({2048, 2048, 96}) \
|
|
->Args({4096, 4096, 16})->Args({4096, 4096, 32})->Args({4096, 4096, 48})->Args({4096, 4096, 64})->Args({4096, 4096, 96})
|
|
|
|
// Tall-skinny block size sweep.
|
|
#define BLOCKSIZE_SWEEP_TALL \
|
|
->Args({1024, 128, 16})->Args({1024, 128, 32})->Args({1024, 128, 48})->Args({1024, 128, 64}) \
|
|
->Args({4096, 256, 16})->Args({4096, 256, 32})->Args({4096, 256, 48})->Args({4096, 256, 64}) \
|
|
->Args({4096, 1024, 16})->Args({4096, 1024, 32})->Args({4096, 1024, 48})->Args({4096, 1024, 64})
|
|
|
|
// ---------- Register benchmarks ----------
|
|
|
|
// Blocked — float
|
|
BENCHMARK(BM_UpperBidiag_Blocked<float>) SMALL_SIZES ->Name("Bidiag_Blocked_float_Small");
|
|
BENCHMARK(BM_UpperBidiag_Blocked<float>) MEDIUM_SIZES ->Name("Bidiag_Blocked_float_Medium");
|
|
BENCHMARK(BM_UpperBidiag_Blocked<float>) LARGE_SIZES ->Name("Bidiag_Blocked_float_Large");
|
|
|
|
// Blocked — double
|
|
BENCHMARK(BM_UpperBidiag_Blocked<double>) SMALL_SIZES ->Name("Bidiag_Blocked_double_Small");
|
|
BENCHMARK(BM_UpperBidiag_Blocked<double>) MEDIUM_SIZES ->Name("Bidiag_Blocked_double_Medium");
|
|
BENCHMARK(BM_UpperBidiag_Blocked<double>) LARGE_SIZES ->Name("Bidiag_Blocked_double_Large");
|
|
|
|
// Unblocked — float
|
|
BENCHMARK(BM_UpperBidiag_Unblocked<float>) SMALL_SIZES ->Name("Bidiag_Unblocked_float_Small");
|
|
BENCHMARK(BM_UpperBidiag_Unblocked<float>) MEDIUM_SIZES ->Name("Bidiag_Unblocked_float_Medium");
|
|
|
|
// Unblocked — double
|
|
BENCHMARK(BM_UpperBidiag_Unblocked<double>) SMALL_SIZES ->Name("Bidiag_Unblocked_double_Small");
|
|
BENCHMARK(BM_UpperBidiag_Unblocked<double>) MEDIUM_SIZES ->Name("Bidiag_Unblocked_double_Medium");
|
|
|
|
// Block size sweep — double
|
|
BENCHMARK(BM_UpperBidiag_BlockSize<double>) BLOCKSIZE_SWEEP ->Name("Bidiag_BS_double_Square");
|
|
BENCHMARK(BM_UpperBidiag_BlockSize<double>) BLOCKSIZE_SWEEP_TALL ->Name("Bidiag_BS_double_Tall");
|
|
|
|
// Block size sweep — float
|
|
BENCHMARK(BM_UpperBidiag_BlockSize<float>) BLOCKSIZE_SWEEP ->Name("Bidiag_BS_float_Square");
|
|
BENCHMARK(BM_UpperBidiag_BlockSize<float>) BLOCKSIZE_SWEEP_TALL ->Name("Bidiag_BS_float_Tall");
|
|
|
|
#undef SMALL_SIZES
|
|
#undef MEDIUM_SIZES
|
|
#undef LARGE_SIZES
|
|
#undef BLOCKSIZE_SWEEP
|
|
#undef BLOCKSIZE_SWEEP_TALL
|
|
// clang-format on
|