Eigen库的优化技巧

文章目录

    • Eigen 优化技巧
    • Eigen优化介绍
    • Eigen用法
    • 内存对齐

Eigen 优化技巧

  • 编译的时候加上-O3
  • 利用.noalis()进行矩阵乘法m_res.noalias() = m1 * m2;, 只有当右值是乘积的时候才有意义;
  • 对 Eigen 3.3 或以上的版本编译的时候加上-mavx和-mfma
  • 使用Eigen时应该尽可能用静态内存代替动态内存,能提供多一些信息就多提供一些,如果内存在整个程序中大小会变,但知道最大可能的大小,都可以告知Eigen,Eigen同样会选择用静态内存。

Eigen::MatrixXd Jacobian_i = Eigen::MatrixXd::Random(10, 10);//动态
Matrix Jacobian_i; //静态
Eigen::Matrix Jacobian_i;//静态

Eigen优化介绍

参考:
eigen_CGLibs_Giugno_Pisa_2013
官方文档
知乎回答

  1. lazy evalution,减少中间变量。其中的运算符重载,并不返回矩阵值,而是返回一个计算表示类。最终的运算是在赋值等号operator =中进行的,这里的重载符号解释了计算表示类,然后进行矩阵运算。缓式评估的优点是计算速度快,避免多次的临时变量的创建与析构。
  2. 用静态内存代替动态内存,静态内存分配在栈上,地址连续(可能触发SIMD),动态内存new在堆上,地址不连续
  3. SSE加速,内存对齐(internal里面自己分配内存),traits技术模板中获得数据类型

Eigen用法

常用语句-与matlab对应
常见用法
1.模块和头文件

  • Core #include,包含Matrix和Array类,基础的线性代数运算和数组操作。
  • Geometry #include,包含旋转,平移,缩放,2维和3维的各种变换。
  • LU #include,包含求逆,行列式,LU分解。
  • Cholesky #include,包含LLT和LDLT Cholesky分解。
  • SVD `#include,包含SVD分解。
  • QR `#include,包含QR分解。
  • Eigenvalues #include,包含特征值,特征向量分解。
  • Sparse #include,包含稀疏矩阵的存储和运算。
  • Dense #include,包含了Core/Geometry/LU/Cholesky/SVD/QR/Eigenvalues模块。
  • Eigen #include,包含Dense和Sparse。

普通矩阵运算,不包含Svd等,只需要包含:

#include

如果进行SVD,则加上

#include

如果不能进行求绝对值、逆矩阵运算,加上

#include

如果不嫌弃编译速度慢,就全加上

#include

还需要稀疏矩阵的话,使用

#include

这样,全部库都加进去了

2.混淆问题
Eigen库的优化技巧_第1张图片
3. Map类
定义:
Map >
Map
MapOptions标识指针是否是对齐的(Aligned),默认是Unaligned。
StrideType表示内存数组的组织方式:行列的步长。
Map没有默认的构造函数,你需要传递一个指针来初始化对象。

int array[8];
 
for(int i = 0; i < 8; ++i) array[i] = i;
 
cout << "Column-major:\n" << Map<Matrix<int,2,4> >(array) << endl;
 
cout << "Row-major:\n" << Map<Matrix<int,2,4,RowMajor> >(array) << endl;
 
cout << "Row-major using stride:\n" <<
 
Map<Matrix<int,2,4>, Unaligned, Stride<1,4> >(array) << endl;

输出:
Column-major:

0 2 4 6

1 3 5 7

Row-major:

0 1 2 3

4 5 6 7

Row-major using stride:

0 1 2 3

4 5 6 7

为了构建Map变量,我们需要其余的两个信息:一个指向元素数组的指针,Matrix/vector的尺寸。定义一个float类型的矩阵: Map mf(pf,rows,columns); pf是一个数组指针float *。
固定尺寸的整形vector声明: Map mi(pi);

int data[] = {1,2,3,4,5,6,7,8,9};
 
Map<RowVectorXi> v(data,4);
 
cout << "The mapped vector v is: " << v << "\n";
 
new (&v) Map<RowVectorXi>(data+4,5);
 
cout << "Now v is: " << v << "\n";

输出:
The mapped vector v is: 1 2 3 4
Now v is: 5 6 7 8 9
  1. 常用矩阵

单位矩阵:Matrix3d::Identity();

全1矩阵:Matrix3d::Ones();

零矩阵:Matrix3d::Zero();

随机矩阵:Matrix3d::Random();

内存对齐

参考:
内存对齐参考博客
对齐规则:
假设m= min(#pragma pack()指定的数,这个数据成员的自身长度)
#pragma pack(n) 表示设置为n字节对齐。 VC6默认8字节对齐
1、 对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是m的倍数。
2、 在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。必须是最小的倍数
3、结合1、2推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
4.各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。
5.各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节自动填充。
6.同时为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
7. sizeof(union),以结构里面size最大元素为union的size,因为在某一时刻,union只有一个成员真正存储于该地址。

优点:
1、 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2、 性能原因:经过内存对齐后,CPU的内存访问速度大大提升

布局技巧:
按数据类型的长度排序 ;把结构体的成员按照它们的类型长度排序,声明成员时把长的类型放在短的前面。编译器要求把长型数据类型存放在偶数地址边界。在申明一个复杂的数据类型 (既有多字节数据又有单字节数据) 时,应该首先存放多字节数据,然后再存放单字节数据,这样可以避免内存的空洞。
提高C++代码效率的一些技巧

你可能感兴趣的:(加速库)