【发布时间】:2018-11-16 12:57:55
【问题描述】:
我正在尝试优化依赖 Eigen3 的 C++ 中的关键操作。我不清楚哪种类型的系数访问操作会导致运行时性能成本,或者编译器什么时候会做得很好。为了找出我困惑的根源,我在下面发布了一个以几种不同方式实现的示例,以及每种方式的一些假设。
这里有更多细节:
- 矩阵 M 将在大部分程序中保持不变
- critical_function 确实被调用了很多次,这就是它被内联的原因
有人能澄清一下哪种方法在性能方面最好吗?我可能对引用、取消引用等的影响成本感到困惑。
选项 1:直接访问矩阵系数
#include <Eigen/Dense>
class A{
A(){
// Assume M has the right numbers
}
// This function will be called many many times, inside loops
inline void critical_function()
{
// Do many operations using M(1, 1), for example:
double y = 1 / M(1, 1);
// ... some more code using M(1, 1)
}
private:
Eigen::Matrix3d M;
};
假设:
- M(1,1) 会导致不断的取消引用,从而产生成本,因为计算偏移量时会添加循环(这不是数组,但不清楚编译器如何管理它)
选项 2:创建我们关心的系数的副本
#include <Eigen/Dense>
class A{
A(){
// Assume M has the right numbers
x = M(1, 1);
}
// This function will be called many many times, inside loops
inline void critical_function()
{
// Do many operations using x, for example:
double y = 1 / x;
// ... some more code using x
}
private:
double x;
Eigen::Matrix3d M;
};
假设:
- 访问 x 生成的周期比访问 M(1, 1) 少,因此它比选项 1 更可取。
- x 确实包含与 M(1,1) 相同的值,但存在确保此数据重复的重要风险,因此代码维护需要避免这种情况。
选项 3:利用引用
#include <Eigen/Dense>
class A{
A(){
// Assume M has the right numbers
}
// This function will be called many many times, inside loops
inline void critical_function()
{
auto & x = M(1, 1);
// Do many operations using x, for example:
double y = 1 / x;
// ... some more code using x
}
private:
Eigen::Matrix3d M;
};
假设:
- 与在函数范围内不断引用 M(1,1) 相比,使用单个引用 x 将产生更少的循环。
- 此潜在优化仅在 critical_function 内部产生影响,但不会在外部范围内延续,例如多次调用函数的循环。
编辑
类型已更正为 double(从 int 或 float),以与 Matrix3d 保持一致。
【问题讨论】:
-
您很可能看不到任何差异,因为
M(1, 1)无论如何都会在缓存中。 假设:您试图在不知道代码在哪里花费最多时间的情况下进行过早优化。 -
换句话说:您的问题没有 100% 通用的答案。您将总是必须分析自己的代码,以找出最适合您的情况的代码。在您的情况下,它可能根本没有区别,因为编译器无论如何都会在幕后转换事物。这里有一个提示:一个部门花费的 CPU 时间比您现在担心的要多一到两个数量级。
-
感谢两位的回答。确实,缓存会产生积极的影响,但是,在缓存中访问系数仍然会产生比访问缓存中的标量(例如浮点数)更多的周期?或不?我同意分析是正确的方法,是的,也许我很挑剔并且有更多有影响力的操作,我只是想很好地理解这些概念,以便我可以使用最佳实践。正如我所提到的,critical_function 被多次调用。您能否参考我所说的假设并确认或纠正我的理解?
-
在选项 2 中,
x是否有意使用int而不是double?选项 3 不太可能有所作为,因为M(1,1)将在编译时简化为等同于((double*)(this))[4] -
不,这是一个错误,感谢您指出这一点。我已将代码更正为始终加倍。使用
x(选项2)的操作是否比访问((double*)(this))[4](选项1)更快?
标签: c++ optimization compiler-optimization eigen3