我正在研究加速大部分 C++ 代码的方法,该代码具有用于计算雅可比的自动导数。这涉及在实际残差中做一些工作,但大部分工作(基于分析的执行时间)是计算雅可比。
这让我很惊讶,因为大多数雅可比是从 0 和 1 向前传播的,所以工作量应该是函数的 2-4 倍,而不是 10-12 倍。为了模拟大量的 jacobian 工作是什么样的,我做了一个超级最小的例子,只有一个点积(而不是真实情况下的 sin、cos、sqrt 等),编译器应该能够优化为单个返回值:
#include <Eigen/Core>
#include <Eigen/Geometry>
using Array12d = Eigen::Matrix<double,12,1>;
double testReturnFirstDot(const Array12d& b)
{
Array12d a;
a.array() = 0.;
a(0) = 1.;
return a.dot(b);
}
应该是一样的
double testReturnFirst(const Array12d& b)
{
return b(0);
}
我很失望地发现,在没有启用快速数学的情况下,GCC 8.2、Clang 6 或 MSVC 19 都无法对充满 0 的矩阵的天真点积进行任何优化。即使使用快速数学(https://godbolt.org/z/GvPXFy),GCC 和 Clang 的优化也很差(仍然涉及乘法和加法),并且 MSVC 根本不做任何优化。
我没有编译器的背景,但这有什么原因吗?我相当肯定,在大部分科学计算中,能够进行更好的常数传播/折叠将使更多优化变得明显,即使常数折叠本身并没有导致加速。
虽然我对解释为什么不在编译器方面这样做很感兴趣,但我也对我可以在实际方面做些什么来使我自己的代码在面对这些类型的模式时变得更快感兴趣。