矩阵乘法性能,int 与 double

Matrix multiplication performance, int vs double

我正在尝试使用 MPI 进行矩阵乘法,想寻求一些帮助来理解一个问题。该机拥有6个核心,32KB一级缓存,256KB二级缓存和15MB三级缓存。乘法是这样的:

vector<vector<double>> mult_mpi(vector<vector<double>> m, 
                                vector<vector<double>> n) { 
    int rows = m.size();
    int size = n.size();
    vector<vector<double>> r(rows, vector<double>(size));

    for (int i = 0; i < rows; ++i) 
        for (int k = 0; k < size; ++k) 
            for (int j = 0; j < size; ++j) 
                r[i][j] += m[i][k] * n[k][j];
    return r;
}

我对int也有同样的看法:

vector<vector<int>> mult_mpi(vector<vector<int>> m, vector<vector<int>> n);

然后我做了一些绘图,不同的线条颜色表示节点数。

下图显示了将两个 int 矩阵相乘所花费的时间:

下图显示了两个双精度矩阵相乘所花费的时间:

为什么在 double case 中 4 和 6 个节点的时间相同?我 运行 是否达到了内存带宽的限制?

我在过去一个小时内尝试了多次,结果相同。还用 top 检查了机器负载,但在我看来,只有我一个人在那里。

您确定您没有为 4K 矢量<>的分配计时吗...?

vector<vector< >> 不是挤压最佳性能的合适类型。矩阵乘法是关于可扩展性和 "computation density" 关于内存访问的最佳操作之一。事实上,操作数量为 O(N^3),而数据数量为 O(N^2)。

事实上,它用于基准测试 top500 fastest systems on earth: HPL 用于 "high performance linpack",是 linpack 线性代数的参考实现。你猜怎么着...基准测试中使用的操作是 DGEMM,即 "Double precision GEneral Matrix Matrix multiply".

DGEMM 是 BLAS 库中运算的名称,它是线性代数的实际标准。今天有许多本地优化的 BLAS 库,商业的(INTEL MKL,IBM ESSL,...)和开源的(ATLAS), but all of them use the same original (originally fortran, now C too) BLAS interface. (NOTE: the original implementation 未优化)

基于BLAS还有LAPACK库:system solver, eigensystems,... 还有优化的lapack库,但是通常90%的性能都被使用优化的BLAS库压榨了。

我非常了解一个(不是唯一的...HPL 是另一个)强大的基于 MPI 的并行库,它是 SCALAPACK,它包含 PBLAS(并行 BLAS),并且在其中。 .. DGEMM 的优化和并行版本等。

SCALAPACK附带了SLUG,在那里你可以找到块循环分布的一个很好的解释,这是用于在并行系统上压缩最优性能排列线性代数问题的数据分布策略。

然而,要获得最佳性能,您需要 link 您的 MPI 可执行文件具有本地优化的 BLAS 库。或者自己写,但你并不孤单,所以不要重新发明轮子。

局部优化不是按行,也不是按列,而是按块访问矩阵。调整块大小以优化 TLB 缓存 and/or 的使用(我记得刚才 libgoto,另一个 blas 库,它经过优化以最大程度地减少 TLB 未命中,在某些系统上达到并超过了英特尔MKL... 很久以前)。例如,在此 ATLAS paper 中查找更多信息。

无论如何,如果你真的想......在尝试制造我的之前,我会开始分析其他轮子是如何锻造的;)