| // Benchmarks for the Toeplitz operator's products across its dispatch tiers and |
| // shapes (square, tall, wide; 5-smooth and prime embedding sizes) against the |
| // dense product, plus the one-time circulant-embedding construction. |
| // SPDX-FileCopyrightText: The Eigen Authors |
| // SPDX-License-Identifier: MPL-2.0 |
| |
| #include <benchmark/benchmark.h> |
| #include <Eigen/Dense> |
| #include <contrib/Eigen/StructuredMatrices> |
| |
| using namespace Eigen; |
| |
| typedef Matrix<double, Dynamic, 1> Vec; |
| typedef Matrix<double, Dynamic, Dynamic> Mat; |
| typedef Matrix<std::complex<double>, Dynamic, 1> CVec; |
| |
| // --- Construction: the one-time embedding symbol FFT --- |
| // 97 exercises the 5-smooth padding of the embedding (2*97-1 = 193 is prime). |
| static void BM_ToeplitzConstruct(benchmark::State& state) { |
| const Index n = state.range(0); |
| Vec c = Vec::Random(n), r = Vec::Random(n); |
| for (auto _ : state) { |
| Toeplitz<double> T(c, r); |
| benchmark::DoNotOptimize(T); |
| } |
| } |
| BENCHMARK(BM_ToeplitzConstruct)->Arg(96)->Arg(97)->Arg(1024)->Arg(4096); |
| |
| // --- Square product y = T * x across the dispatch tiers --- |
| // 8: scalar loop; 32: segment tier boundary; larger: FFT via the embedding. |
| static void BM_ToeplitzProduct(benchmark::State& state) { |
| const Index n = state.range(0); |
| Vec c = Vec::Random(n), r = Vec::Random(n), x = Vec::Random(n), y(n); |
| Toeplitz<double> T(c, r); |
| for (auto _ : state) { |
| y.noalias() = T * x; |
| benchmark::DoNotOptimize(y.data()); |
| } |
| } |
| BENCHMARK(BM_ToeplitzProduct)->Arg(8)->Arg(32)->Arg(96)->Arg(1024)->Arg(4096); |
| |
| static void BM_ToeplitzProductDense(benchmark::State& state) { |
| const Index n = state.range(0); |
| Vec c = Vec::Random(n), r = Vec::Random(n), x = Vec::Random(n), y(n); |
| Mat dense = Toeplitz<double>(c, r); |
| for (auto _ : state) { |
| y.noalias() = dense * x; |
| benchmark::DoNotOptimize(y.data()); |
| } |
| } |
| BENCHMARK(BM_ToeplitzProductDense)->Arg(96)->Arg(1024)->Arg(4096); |
| |
| // --- Rectangular products: tall (2n x n) and wide (n x 2n) --- |
| static void BM_ToeplitzProductTall(benchmark::State& state) { |
| const Index n = state.range(0); |
| Vec c = Vec::Random(2 * n), r = Vec::Random(n), x = Vec::Random(n), y(2 * n); |
| Toeplitz<double> T(c, r); |
| for (auto _ : state) { |
| y.noalias() = T * x; |
| benchmark::DoNotOptimize(y.data()); |
| } |
| } |
| BENCHMARK(BM_ToeplitzProductTall)->Arg(96)->Arg(1024)->Arg(4096); |
| |
| static void BM_ToeplitzProductWide(benchmark::State& state) { |
| const Index n = state.range(0); |
| Vec c = Vec::Random(n), r = Vec::Random(2 * n), x = Vec::Random(2 * n), y(n); |
| Toeplitz<double> T(c, r); |
| for (auto _ : state) { |
| y.noalias() = T * x; |
| benchmark::DoNotOptimize(y.data()); |
| } |
| } |
| BENCHMARK(BM_ToeplitzProductWide)->Arg(96)->Arg(1024)->Arg(4096); |
| |
| static void BM_ToeplitzProductComplex(benchmark::State& state) { |
| const Index n = state.range(0); |
| CVec c = CVec::Random(n), r = CVec::Random(n), x = CVec::Random(n), y(n); |
| Toeplitz<std::complex<double>> T(c, r); |
| for (auto _ : state) { |
| y.noalias() = T * x; |
| benchmark::DoNotOptimize(y.data()); |
| } |
| } |
| BENCHMARK(BM_ToeplitzProductComplex)->Arg(96)->Arg(4096); |
| |
| // Multi-column right-hand sides: one FFT round trip per column. |
| static void BM_ToeplitzProductMultiRhs(benchmark::State& state) { |
| const Index n = state.range(0), k = state.range(1); |
| Vec c = Vec::Random(n), r = Vec::Random(n); |
| Mat X = Mat::Random(n, k), Y(n, k); |
| Toeplitz<double> T(c, r); |
| for (auto _ : state) { |
| Y.noalias() = T * X; |
| benchmark::DoNotOptimize(Y.data()); |
| } |
| } |
| BENCHMARK(BM_ToeplitzProductMultiRhs)->ArgsProduct({{96, 4096}, {8}}); |