Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何优化C++;对于x86?_C++_Optimization_X86 64_Matrix Multiplication_Eigen - Fatal编程技术网

C++ 如何优化C++;对于x86?

C++ 如何优化C++;对于x86?,c++,optimization,x86-64,matrix-multiplication,eigen,C++,Optimization,X86 64,Matrix Multiplication,Eigen,我有一个关键算法,其中大部分运行时间用于计算密集矩阵积: A*A'*Y, where: A is an m-by-n matrix, A' is its conjugate transpose, Y is an m-by-k matrix Typical characteristics: - k is much smaller than both m or n (k is typically < 10) - m

我有一个关键算法,其中大部分运行时间用于计算密集矩阵积:

A*A'*Y, where: A is an m-by-n matrix, 
               A' is its conjugate transpose,
               Y is an m-by-k matrix

Typical characteristics:
    - k is much smaller than both m or n (k is typically < 10)
    - m in the range [500, 2000]
    - n in the range [100, 1000]
A*A'*Y,其中:A是m-x-n矩阵,
A'是它的共轭转置,
Y是m-x-k矩阵
典型特征:
-k远小于m或n(k通常小于10)
-m在[5002000]范围内
-n在[1001000]范围内
基于这些维度,根据问题的教训,很明显,在许多操作意义上,将计算结构为
a*(a'*Y)
是最佳的。我当前的实现就是这样做的,仅仅强制表达式具有这种关联性所带来的性能提升是显而易见的

我的应用程序是用C++编写的,用于X8664平台。我正在使用线性代数库,作为后端。Eigen能够使用IMKL的BLAS接口来执行乘法,从Eigen的本机SSE2实现到Intel在我的Sandy Bridge机器上优化的基于AVX的实现的提升也很重要

但是,表达式
A*(A.adjunction()*Y)
(用本征术语编写)被分解为两个通用矩阵乘积(调用
xGEMM
BLAS例程),并在其间创建一个临时矩阵。我想知道,通过一次对整个表达式求值的专门实现,我是否能够得到一个比我现在拥有的通用实现更快的实现。以下几点让我相信:

  • 使用上述典型维度,输入矩阵
    A
    通常不适合缓存。因此,用于计算三矩阵乘积的特定内存访问模式将是关键。显然,避免为部分产品创建临时矩阵也是有利的

  • A
    及其共轭转置显然有一个非常相关的结构,可以利用它来改善整个表达式的内存访问模式

是否有任何标准技术可以以缓存友好的方式实现这种表达式?我发现的大多数矩阵乘法优化技术都适用于标准的
A*B
情况,而不是更大的表达式。我对问题的微观优化方面很满意,例如转换成适当的SIMD指令集,但我正在寻找任何参考资料,以尽可能以最方便内存的方式分解此结构

编辑:根据到目前为止收到的回复,我认为上面我有点不清楚。事实上,从我对这个问题的观点来看,我使用C++/Eigen实际上只是一个实现细节。Eigen在实现表达式模板方面做得很好,但不支持将此类问题作为简单表达式进行评估(仅支持2个一般密集矩阵的乘积)


在比编译器对表达式求值更高的层次上,我正在寻找复合乘法运算的更有效的数学分解,并倾向于避免由于
a
的公共结构及其共轭转置而产生的不必要的冗余内存访问。结果可能很难在纯Eigen中有效地实现,因此我可能只在使用SIMD Intrinsic的专用例程中实现它。

使用临时矩阵来计算a'*Y,但请确保告诉Eigen没有出现混叠:
temp.noalias()=a.adjunct()*Y
。然后计算结果,再次告诉eigen对象没有别名:
result.noalias()=A*temp
只有在执行
(A*A')*Y
时才会有冗余计算,因为在这种情况下
(A*A')
是对称的,只需要一半的计算。但是,正如您所注意到的,执行
A*(A'*Y)
仍然要快得多,在这种情况下,没有冗余计算。我确认临时创建的成本完全可以忽略不计。

我想执行以下操作

result = A * (A.adjoint() * Y)
我也会那样做的

temp = A.adjoint() * Y
result = A * temp;

如果您的矩阵
Y
适合缓存,您可能可以利用这样做的优势

result = A * (Y.adjoint() * A).adjoint()
temp = Y.adjoint() * A
result = A * temp.adjoint();
或者,如果前面的符号是不允许的,像这样

result = A * (Y.adjoint() * A).adjoint()
temp = Y.adjoint() * A
result = A * temp.adjoint();
那么你不需要做矩阵A的伴随,并且为A存储临时伴随矩阵,这将比为Y存储的要昂贵得多

如果矩阵Y适合缓存,那么在第一次乘法中循环a的列,然后在第二次多重乘法中循环a的行(第一次乘法的缓存中有Y.adjoint(),第二次乘法的缓存中有temp.adjoint()),应该会快得多,但我想,艾根已经在处理这些事情了。

这还不是一个完整的答案(但我不确定它是否会成为一个完整的答案)

让我们先考虑一下数学。因为矩阵乘法是关联的,所以我们可以 (A*A')Y或A(A'*Y)

(A*A')*Y的浮点运算

A*(A'*Y)的浮点运算

因为k比m和n小得多,所以很清楚为什么第二种情况要快得多

但是,通过对称性,我们原则上可以将A*A'的计算数量减少2(尽管使用SIMD可能不容易),因此我们可以将(A*A')*Y的浮点运算数量减少到

我们知道m和n都大于k。让我们为m和n选择一个名为
z
的新变量,并找出情况1和情况2相等的地方:

z*z*z + 2*z*z*k = 4*z*z*k  //now simplify
z = 2*k.
因此,只要m和n都大于k的两倍,第二种情况下的浮点运算就会更少。在你的例子中,m和n都大于100,k都小于10,所以例子2使用的更少
z*z*z + 2*z*z*k = 4*z*z*k  //now simplify
z = 2*k.
frequency * number of physical cores * 8 (8-wide AVX SP) * 2 (addition + multiplication)