diff --git a/benchmarks/Core/CMakeLists.txt b/benchmarks/Core/CMakeLists.txt index ff4709e9c..30f21d103 100644 --- a/benchmarks/Core/CMakeLists.txt +++ b/benchmarks/Core/CMakeLists.txt @@ -21,3 +21,4 @@ eigen_add_benchmark(bench_syr2 bench_syr2.cpp) eigen_add_benchmark(bench_construction bench_construction.cpp) eigen_add_benchmark(bench_fixed_size bench_fixed_size.cpp) eigen_add_benchmark(bench_fixed_size_double bench_fixed_size.cpp DEFINITIONS SCALAR=double) +eigen_add_benchmark(bench_small_matrix bench_small_matrix.cpp) diff --git a/benchmarks/Core/bench_small_matrix.cpp b/benchmarks/Core/bench_small_matrix.cpp new file mode 100644 index 000000000..f060e0eda --- /dev/null +++ b/benchmarks/Core/bench_small_matrix.cpp @@ -0,0 +1,316 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace Eigen; + +// ============================================================================ +// Fixed-size matrix multiply (the fundamental operation) +// ============================================================================ + +template +static void BM_MatMul(benchmark::State& state) { + Matrix a, b, c; + a.setRandom(); + b.setRandom(); + for (auto _ : state) { + c.noalias() = a * b; + benchmark::DoNotOptimize(c.data()); + } +} + +// Matrix-vector multiply +template +static void BM_MatVec(benchmark::State& state) { + Matrix a; + Matrix v, r; + a.setRandom(); + v.setRandom(); + for (auto _ : state) { + r.noalias() = a * v; + benchmark::DoNotOptimize(r.data()); + } +} + +// ============================================================================ +// Fixed-size inverse (critical for transform operations) +// ============================================================================ + +template +EIGEN_DONT_INLINE void do_inverse(const Matrix& a, Matrix& r) { + r = a.inverse(); +} + +template +static void BM_Inverse(benchmark::State& state) { + Matrix a, r; + a.setRandom(); + a += Matrix::Identity() * Scalar(N); // ensure well-conditioned + for (auto _ : state) { + do_inverse(a, r); + benchmark::DoNotOptimize(r.data()); + } +} + +// ============================================================================ +// Fixed-size determinant +// ============================================================================ + +template +static void BM_Determinant(benchmark::State& state) { + Matrix a; + a.setRandom(); + Scalar d; + for (auto _ : state) { + d = a.determinant(); + benchmark::DoNotOptimize(d); + } +} + +// ============================================================================ +// LLT (Cholesky) — for SPD matrices (covariance, mass matrices) +// ============================================================================ + +template +static void BM_LLT_Compute(benchmark::State& state) { + Matrix a; + a.setRandom(); + a = a.transpose() * a + Matrix::Identity(); // SPD + LLT> llt; + for (auto _ : state) { + llt.compute(a); + benchmark::DoNotOptimize(&llt); + } +} + +template +static void BM_LLT_Solve(benchmark::State& state) { + Matrix a; + a.setRandom(); + a = a.transpose() * a + Matrix::Identity(); + Matrix b = Matrix::Random(); + LLT> llt(a); + Matrix x; + for (auto _ : state) { + x = llt.solve(b); + benchmark::DoNotOptimize(x.data()); + } +} + +// ============================================================================ +// LDLT — for semi-definite matrices +// ============================================================================ + +template +static void BM_LDLT_Compute(benchmark::State& state) { + Matrix a; + a.setRandom(); + a = a.transpose() * a + Matrix::Identity(); + LDLT> ldlt; + for (auto _ : state) { + ldlt.compute(a); + benchmark::DoNotOptimize(&ldlt); + } +} + +// ============================================================================ +// PartialPivLU — for general square systems +// ============================================================================ + +template +static void BM_PartialPivLU_Compute(benchmark::State& state) { + Matrix a; + a.setRandom(); + a += Matrix::Identity() * Scalar(N); + PartialPivLU> lu; + for (auto _ : state) { + lu.compute(a); + benchmark::DoNotOptimize(lu.matrixLU().data()); + } +} + +template +static void BM_PartialPivLU_Solve(benchmark::State& state) { + Matrix a; + a.setRandom(); + a += Matrix::Identity() * Scalar(N); + Matrix b = Matrix::Random(); + PartialPivLU> lu(a); + Matrix x; + for (auto _ : state) { + x = lu.solve(b); + benchmark::DoNotOptimize(x.data()); + } +} + +// ============================================================================ +// ColPivHouseholderQR — for least-squares (camera calibration, etc.) +// ============================================================================ + +template +static void BM_ColPivQR_Compute(benchmark::State& state) { + Matrix a; + a.setRandom(); + ColPivHouseholderQR> qr; + for (auto _ : state) { + qr.compute(a); + benchmark::DoNotOptimize(qr.matrixR().data()); + } +} + +// ============================================================================ +// JacobiSVD — the workhorse for small matrices in CV +// ============================================================================ + +template +static void BM_JacobiSVD_Compute(benchmark::State& state) { + Matrix a; + a.setRandom(); + JacobiSVD, Options> svd; + for (auto _ : state) { + svd.compute(a); + benchmark::DoNotOptimize(svd.singularValues().data()); + } +} + +template +static void BM_JacobiSVD_Solve(benchmark::State& state) { + Matrix a; + a.setRandom(); + Matrix b = Matrix::Random(); + JacobiSVD, ComputeThinU | ComputeThinV> svd(a); + Matrix x; + for (auto _ : state) { + x = svd.solve(b); + benchmark::DoNotOptimize(x.data()); + } +} + +// ============================================================================ +// SelfAdjointEigenSolver — PCA, normal estimation +// ============================================================================ + +template +static void BM_SelfAdjointEig_Compute(benchmark::State& state) { + Matrix a; + a.setRandom(); + a = a.transpose() * a; + SelfAdjointEigenSolver> eig; + for (auto _ : state) { + eig.compute(a); + benchmark::DoNotOptimize(eig.eigenvalues().data()); + } +} + +// SelfAdjointEigenSolver::computeDirect — closed-form for 2x2 and 3x3 +template +static void BM_SelfAdjointEig_ComputeDirect(benchmark::State& state) { + Matrix a; + a.setRandom(); + a = a.transpose() * a; + SelfAdjointEigenSolver> eig; + for (auto _ : state) { + eig.computeDirect(a); + benchmark::DoNotOptimize(eig.eigenvalues().data()); + } +} + +// ============================================================================ +// Registration — focus on robotics/CV sizes +// ============================================================================ + +// Matrix multiply: 2x2, 3x3, 4x4, 6x6 +BENCHMARK(BM_MatMul); +BENCHMARK(BM_MatMul); +BENCHMARK(BM_MatMul); +BENCHMARK(BM_MatMul); +BENCHMARK(BM_MatMul); +BENCHMARK(BM_MatMul); +BENCHMARK(BM_MatMul); +BENCHMARK(BM_MatMul); + +// Matrix-vector multiply +BENCHMARK(BM_MatVec); +BENCHMARK(BM_MatVec); +BENCHMARK(BM_MatVec); +BENCHMARK(BM_MatVec); +BENCHMARK(BM_MatVec); +BENCHMARK(BM_MatVec); + +// Inverse +BENCHMARK(BM_Inverse); +BENCHMARK(BM_Inverse); +BENCHMARK(BM_Inverse); +BENCHMARK(BM_Inverse); +BENCHMARK(BM_Inverse); +BENCHMARK(BM_Inverse); + +// Determinant +BENCHMARK(BM_Determinant); +BENCHMARK(BM_Determinant); +BENCHMARK(BM_Determinant); +BENCHMARK(BM_Determinant); +BENCHMARK(BM_Determinant); +BENCHMARK(BM_Determinant); + +// LLT (Cholesky) +BENCHMARK(BM_LLT_Compute); +BENCHMARK(BM_LLT_Compute); +BENCHMARK(BM_LLT_Compute); +BENCHMARK(BM_LLT_Compute); +BENCHMARK(BM_LLT_Compute); +BENCHMARK(BM_LLT_Compute); +BENCHMARK(BM_LLT_Solve); +BENCHMARK(BM_LLT_Solve); + +// LDLT +BENCHMARK(BM_LDLT_Compute); +BENCHMARK(BM_LDLT_Compute); + +// PartialPivLU +BENCHMARK(BM_PartialPivLU_Compute); +BENCHMARK(BM_PartialPivLU_Compute); +BENCHMARK(BM_PartialPivLU_Compute); +BENCHMARK(BM_PartialPivLU_Compute); +BENCHMARK(BM_PartialPivLU_Solve); +BENCHMARK(BM_PartialPivLU_Solve); + +// ColPivHouseholderQR +BENCHMARK(BM_ColPivQR_Compute); +BENCHMARK(BM_ColPivQR_Compute); +BENCHMARK(BM_ColPivQR_Compute); +BENCHMARK(BM_ColPivQR_Compute); // overdetermined least-squares + +// JacobiSVD — the key CV sizes +BENCHMARK(BM_JacobiSVD_Compute); +BENCHMARK(BM_JacobiSVD_Compute); +BENCHMARK(BM_JacobiSVD_Compute); +BENCHMARK(BM_JacobiSVD_Compute); +BENCHMARK(BM_JacobiSVD_Compute); +BENCHMARK(BM_JacobiSVD_Compute); +BENCHMARK(BM_JacobiSVD_Compute); // projection matrix +BENCHMARK(BM_JacobiSVD_Compute); // manipulator Jacobian +BENCHMARK(BM_JacobiSVD_Compute); // fundamental matrix (8-point) +BENCHMARK(BM_JacobiSVD_Solve); +BENCHMARK(BM_JacobiSVD_Solve); + +// Values-only SVD (when you just need singular values) +BENCHMARK((BM_JacobiSVD_Compute)); +BENCHMARK((BM_JacobiSVD_Compute)); + +// SelfAdjointEigenSolver — PCA, normal estimation +BENCHMARK(BM_SelfAdjointEig_Compute); +BENCHMARK(BM_SelfAdjointEig_Compute); +BENCHMARK(BM_SelfAdjointEig_Compute); +BENCHMARK(BM_SelfAdjointEig_Compute); +BENCHMARK(BM_SelfAdjointEig_Compute); + +// SelfAdjointEigenSolver::computeDirect (closed-form, 2x2 and 3x3 only) +BENCHMARK(BM_SelfAdjointEig_ComputeDirect); +BENCHMARK(BM_SelfAdjointEig_ComputeDirect); +BENCHMARK(BM_SelfAdjointEig_ComputeDirect); +BENCHMARK(BM_SelfAdjointEig_ComputeDirect);