逐元素矩阵乘法的并行化

计算科学 并行计算 C++ 矩阵 量子力学 密集矩阵
2021-12-13 19:49:42

我使用 Armadillo 作为 OpenBLAS 的接口。在我当前的程序中,我有一个循环,我在其中进行形式的乘法

for(long t = t0; t < t1; t+=tStep)
{
    stateMatrix %= elementWiseEvolutionMatrix;
}

该运算符%是逐元素乘法运算符。这里的问题是,对于边长为 500+ 的矩阵(我手头的矩阵),我可以看到没有任何并行化。现在我想指出,普通矩阵乘法是并行化的。但是这种逐元素乘法不是并行的。

我怎么知道?因为我进入htop我的 linux 系统,我看到只有一个核心很忙,而如果我对普通矩阵乘法做同样的事情,我看到所有核心都忙。

现在我尝试使用 OpenMP 手动并行化它,但没有运气。我试过了:

for(long t = t0; t < t1; t+=tStep)
{
    #pragma omp parallel for
    for(long i = 0; i < static_cast<long>(stateMatrix.n_rows); i++)
    {
        stat1eMatrix.row(i) %= elementWiseEvolutionMatrix.row(i);
    }
}

但这让所有的核心都忙起来了,但程序变得慢了大约 10 倍。

我的问题:如何通过并行化使逐元素乘法尽可能快?

谢谢。

编辑:我想指出,如果有必要,我很乐意使用另一个库进行元素乘法。

2个回答

BLAS 库中没有元素乘法运算。您最好的方法可能是使用(例如)OpenMP 线程自己实现操作。

在你这样做之前,你应该考虑阿姆达尔定律以及加速你的这部分代码是否真的有帮助 - 这些元素乘法可能不是你的代码花费大部分时间的地方,因此你可能赢了并行化这部分代码不会有太大的加速。

首先,我同意 Brian Borchers 关于分析的评论,以确保这些元素乘法是您的性能问题所在。但是,既然您确信这是您的问题,这里有另一个建议。

在尝试利用多个 CPU 之前,我会确保您有一个利用矢量化的实现。SSE2 指令集(在大多数现代处理器中可用)具有将双精度浮点数向量相乘的操作。您的代码可能会或可能不会允许您的编译器利用此指令。

据我所知,犰狳没有对 SSE2 的任何直接支持。但由于您表示愿意切换库,Eigen 库 ( http://eigen.tuxfamily.org/index.php?title=Main_Page ) 肯定会使用 SSE2 指令生成代码。这可以使单精度乘法提高 4 倍,双精度提高 2 倍。如果您有幸拥有支持 AVX 指令集的 CPU,Eigen 的开发版本支持此功能以提供额外的加速。