mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
317 lines
10 KiB
C++
317 lines
10 KiB
C++
#include <benchmark/benchmark.h>
|
|
#include <Eigen/Core>
|
|
#include <Eigen/LU>
|
|
#include <Eigen/Cholesky>
|
|
#include <Eigen/QR>
|
|
#include <Eigen/SVD>
|
|
#include <Eigen/Eigenvalues>
|
|
|
|
using namespace Eigen;
|
|
|
|
// ============================================================================
|
|
// Fixed-size matrix multiply (the fundamental operation)
|
|
// ============================================================================
|
|
|
|
template <typename Scalar, int N>
|
|
static void BM_MatMul(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a, b, c;
|
|
a.setRandom();
|
|
b.setRandom();
|
|
for (auto _ : state) {
|
|
c.noalias() = a * b;
|
|
benchmark::DoNotOptimize(c.data());
|
|
}
|
|
}
|
|
|
|
// Matrix-vector multiply
|
|
template <typename Scalar, int N>
|
|
static void BM_MatVec(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a;
|
|
Matrix<Scalar, N, 1> 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 <typename Scalar, int N>
|
|
EIGEN_DONT_INLINE void do_inverse(const Matrix<Scalar, N, N>& a, Matrix<Scalar, N, N>& r) {
|
|
r = a.inverse();
|
|
}
|
|
|
|
template <typename Scalar, int N>
|
|
static void BM_Inverse(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a, r;
|
|
a.setRandom();
|
|
a += Matrix<Scalar, N, N>::Identity() * Scalar(N); // ensure well-conditioned
|
|
for (auto _ : state) {
|
|
do_inverse(a, r);
|
|
benchmark::DoNotOptimize(r.data());
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// Fixed-size determinant
|
|
// ============================================================================
|
|
|
|
template <typename Scalar, int N>
|
|
static void BM_Determinant(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a;
|
|
a.setRandom();
|
|
Scalar d;
|
|
for (auto _ : state) {
|
|
d = a.determinant();
|
|
benchmark::DoNotOptimize(d);
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// LLT (Cholesky) — for SPD matrices (covariance, mass matrices)
|
|
// ============================================================================
|
|
|
|
template <typename Scalar, int N>
|
|
static void BM_LLT_Compute(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a;
|
|
a.setRandom();
|
|
a = a.transpose() * a + Matrix<Scalar, N, N>::Identity(); // SPD
|
|
LLT<Matrix<Scalar, N, N>> llt;
|
|
for (auto _ : state) {
|
|
llt.compute(a);
|
|
benchmark::DoNotOptimize(&llt);
|
|
}
|
|
}
|
|
|
|
template <typename Scalar, int N>
|
|
static void BM_LLT_Solve(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a;
|
|
a.setRandom();
|
|
a = a.transpose() * a + Matrix<Scalar, N, N>::Identity();
|
|
Matrix<Scalar, N, 1> b = Matrix<Scalar, N, 1>::Random();
|
|
LLT<Matrix<Scalar, N, N>> llt(a);
|
|
Matrix<Scalar, N, 1> x;
|
|
for (auto _ : state) {
|
|
x = llt.solve(b);
|
|
benchmark::DoNotOptimize(x.data());
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// LDLT — for semi-definite matrices
|
|
// ============================================================================
|
|
|
|
template <typename Scalar, int N>
|
|
static void BM_LDLT_Compute(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a;
|
|
a.setRandom();
|
|
a = a.transpose() * a + Matrix<Scalar, N, N>::Identity();
|
|
LDLT<Matrix<Scalar, N, N>> ldlt;
|
|
for (auto _ : state) {
|
|
ldlt.compute(a);
|
|
benchmark::DoNotOptimize(&ldlt);
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// PartialPivLU — for general square systems
|
|
// ============================================================================
|
|
|
|
template <typename Scalar, int N>
|
|
static void BM_PartialPivLU_Compute(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a;
|
|
a.setRandom();
|
|
a += Matrix<Scalar, N, N>::Identity() * Scalar(N);
|
|
PartialPivLU<Matrix<Scalar, N, N>> lu;
|
|
for (auto _ : state) {
|
|
lu.compute(a);
|
|
benchmark::DoNotOptimize(lu.matrixLU().data());
|
|
}
|
|
}
|
|
|
|
template <typename Scalar, int N>
|
|
static void BM_PartialPivLU_Solve(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a;
|
|
a.setRandom();
|
|
a += Matrix<Scalar, N, N>::Identity() * Scalar(N);
|
|
Matrix<Scalar, N, 1> b = Matrix<Scalar, N, 1>::Random();
|
|
PartialPivLU<Matrix<Scalar, N, N>> lu(a);
|
|
Matrix<Scalar, N, 1> x;
|
|
for (auto _ : state) {
|
|
x = lu.solve(b);
|
|
benchmark::DoNotOptimize(x.data());
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// ColPivHouseholderQR — for least-squares (camera calibration, etc.)
|
|
// ============================================================================
|
|
|
|
template <typename Scalar, int Rows, int Cols>
|
|
static void BM_ColPivQR_Compute(benchmark::State& state) {
|
|
Matrix<Scalar, Rows, Cols> a;
|
|
a.setRandom();
|
|
ColPivHouseholderQR<Matrix<Scalar, Rows, Cols>> qr;
|
|
for (auto _ : state) {
|
|
qr.compute(a);
|
|
benchmark::DoNotOptimize(qr.matrixR().data());
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// JacobiSVD — the workhorse for small matrices in CV
|
|
// ============================================================================
|
|
|
|
template <typename Scalar, int Rows, int Cols, int Options = ComputeThinU | ComputeThinV>
|
|
static void BM_JacobiSVD_Compute(benchmark::State& state) {
|
|
Matrix<Scalar, Rows, Cols> a;
|
|
a.setRandom();
|
|
JacobiSVD<Matrix<Scalar, Rows, Cols>, Options> svd;
|
|
for (auto _ : state) {
|
|
svd.compute(a);
|
|
benchmark::DoNotOptimize(svd.singularValues().data());
|
|
}
|
|
}
|
|
|
|
template <typename Scalar, int Rows, int Cols>
|
|
static void BM_JacobiSVD_Solve(benchmark::State& state) {
|
|
Matrix<Scalar, Rows, Cols> a;
|
|
a.setRandom();
|
|
Matrix<Scalar, Rows, 1> b = Matrix<Scalar, Rows, 1>::Random();
|
|
JacobiSVD<Matrix<Scalar, Rows, Cols>, ComputeThinU | ComputeThinV> svd(a);
|
|
Matrix<Scalar, Cols, 1> x;
|
|
for (auto _ : state) {
|
|
x = svd.solve(b);
|
|
benchmark::DoNotOptimize(x.data());
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// SelfAdjointEigenSolver — PCA, normal estimation
|
|
// ============================================================================
|
|
|
|
template <typename Scalar, int N>
|
|
static void BM_SelfAdjointEig_Compute(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a;
|
|
a.setRandom();
|
|
a = a.transpose() * a;
|
|
SelfAdjointEigenSolver<Matrix<Scalar, N, N>> eig;
|
|
for (auto _ : state) {
|
|
eig.compute(a);
|
|
benchmark::DoNotOptimize(eig.eigenvalues().data());
|
|
}
|
|
}
|
|
|
|
// SelfAdjointEigenSolver::computeDirect — closed-form for 2x2 and 3x3
|
|
template <typename Scalar, int N>
|
|
static void BM_SelfAdjointEig_ComputeDirect(benchmark::State& state) {
|
|
Matrix<Scalar, N, N> a;
|
|
a.setRandom();
|
|
a = a.transpose() * a;
|
|
SelfAdjointEigenSolver<Matrix<Scalar, N, N>> 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<float, 2>);
|
|
BENCHMARK(BM_MatMul<float, 3>);
|
|
BENCHMARK(BM_MatMul<float, 4>);
|
|
BENCHMARK(BM_MatMul<float, 6>);
|
|
BENCHMARK(BM_MatMul<double, 2>);
|
|
BENCHMARK(BM_MatMul<double, 3>);
|
|
BENCHMARK(BM_MatMul<double, 4>);
|
|
BENCHMARK(BM_MatMul<double, 6>);
|
|
|
|
// Matrix-vector multiply
|
|
BENCHMARK(BM_MatVec<float, 3>);
|
|
BENCHMARK(BM_MatVec<float, 4>);
|
|
BENCHMARK(BM_MatVec<float, 6>);
|
|
BENCHMARK(BM_MatVec<double, 3>);
|
|
BENCHMARK(BM_MatVec<double, 4>);
|
|
BENCHMARK(BM_MatVec<double, 6>);
|
|
|
|
// Inverse
|
|
BENCHMARK(BM_Inverse<float, 2>);
|
|
BENCHMARK(BM_Inverse<float, 3>);
|
|
BENCHMARK(BM_Inverse<float, 4>);
|
|
BENCHMARK(BM_Inverse<double, 2>);
|
|
BENCHMARK(BM_Inverse<double, 3>);
|
|
BENCHMARK(BM_Inverse<double, 4>);
|
|
|
|
// Determinant
|
|
BENCHMARK(BM_Determinant<float, 2>);
|
|
BENCHMARK(BM_Determinant<float, 3>);
|
|
BENCHMARK(BM_Determinant<float, 4>);
|
|
BENCHMARK(BM_Determinant<double, 2>);
|
|
BENCHMARK(BM_Determinant<double, 3>);
|
|
BENCHMARK(BM_Determinant<double, 4>);
|
|
|
|
// LLT (Cholesky)
|
|
BENCHMARK(BM_LLT_Compute<float, 3>);
|
|
BENCHMARK(BM_LLT_Compute<float, 4>);
|
|
BENCHMARK(BM_LLT_Compute<float, 6>);
|
|
BENCHMARK(BM_LLT_Compute<double, 3>);
|
|
BENCHMARK(BM_LLT_Compute<double, 4>);
|
|
BENCHMARK(BM_LLT_Compute<double, 6>);
|
|
BENCHMARK(BM_LLT_Solve<double, 3>);
|
|
BENCHMARK(BM_LLT_Solve<double, 6>);
|
|
|
|
// LDLT
|
|
BENCHMARK(BM_LDLT_Compute<double, 3>);
|
|
BENCHMARK(BM_LDLT_Compute<double, 6>);
|
|
|
|
// PartialPivLU
|
|
BENCHMARK(BM_PartialPivLU_Compute<float, 3>);
|
|
BENCHMARK(BM_PartialPivLU_Compute<float, 4>);
|
|
BENCHMARK(BM_PartialPivLU_Compute<double, 3>);
|
|
BENCHMARK(BM_PartialPivLU_Compute<double, 4>);
|
|
BENCHMARK(BM_PartialPivLU_Solve<double, 3>);
|
|
BENCHMARK(BM_PartialPivLU_Solve<double, 4>);
|
|
|
|
// ColPivHouseholderQR
|
|
BENCHMARK(BM_ColPivQR_Compute<float, 3, 3>);
|
|
BENCHMARK(BM_ColPivQR_Compute<double, 3, 3>);
|
|
BENCHMARK(BM_ColPivQR_Compute<double, 6, 6>);
|
|
BENCHMARK(BM_ColPivQR_Compute<double, 8, 3>); // overdetermined least-squares
|
|
|
|
// JacobiSVD — the key CV sizes
|
|
BENCHMARK(BM_JacobiSVD_Compute<float, 2, 2>);
|
|
BENCHMARK(BM_JacobiSVD_Compute<float, 3, 3>);
|
|
BENCHMARK(BM_JacobiSVD_Compute<float, 4, 4>);
|
|
BENCHMARK(BM_JacobiSVD_Compute<double, 2, 2>);
|
|
BENCHMARK(BM_JacobiSVD_Compute<double, 3, 3>);
|
|
BENCHMARK(BM_JacobiSVD_Compute<double, 4, 4>);
|
|
BENCHMARK(BM_JacobiSVD_Compute<double, 3, 4>); // projection matrix
|
|
BENCHMARK(BM_JacobiSVD_Compute<double, 6, 6>); // manipulator Jacobian
|
|
BENCHMARK(BM_JacobiSVD_Compute<double, 8, 9>); // fundamental matrix (8-point)
|
|
BENCHMARK(BM_JacobiSVD_Solve<double, 3, 3>);
|
|
BENCHMARK(BM_JacobiSVD_Solve<double, 6, 6>);
|
|
|
|
// Values-only SVD (when you just need singular values)
|
|
BENCHMARK((BM_JacobiSVD_Compute<double, 3, 3, 0>));
|
|
BENCHMARK((BM_JacobiSVD_Compute<double, 6, 6, 0>));
|
|
|
|
// SelfAdjointEigenSolver — PCA, normal estimation
|
|
BENCHMARK(BM_SelfAdjointEig_Compute<float, 3>);
|
|
BENCHMARK(BM_SelfAdjointEig_Compute<float, 4>);
|
|
BENCHMARK(BM_SelfAdjointEig_Compute<double, 3>);
|
|
BENCHMARK(BM_SelfAdjointEig_Compute<double, 4>);
|
|
BENCHMARK(BM_SelfAdjointEig_Compute<double, 6>);
|
|
|
|
// SelfAdjointEigenSolver::computeDirect (closed-form, 2x2 and 3x3 only)
|
|
BENCHMARK(BM_SelfAdjointEig_ComputeDirect<float, 2>);
|
|
BENCHMARK(BM_SelfAdjointEig_ComputeDirect<float, 3>);
|
|
BENCHMARK(BM_SelfAdjointEig_ComputeDirect<double, 2>);
|
|
BENCHMARK(BM_SelfAdjointEig_ComputeDirect<double, 3>);
|