【问题标题】:Matrix multiplication performance, int vs double矩阵乘法性能,int vs double
【发布时间】:2019-01-02 00:22:21
【问题描述】:

我正在尝试使用 MPI 进行矩阵乘法,并且想寻求一些帮助以了解一个问题。该机有6个核心,32KB L1缓存,256KB L2缓存和15MB L3缓存。乘法是这样的:

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;
}

我对@9​​87654327@也有同样的看法:

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

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

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

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

为什么在双重情况下,4 个节点和 6 个节点的时间相同?我是否遇到了内存带宽的限制?

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

【问题讨论】:

  • 我不知道您的问题的答案,但请注意,这是矩阵乘法的缓慢实现。
  • 你能给我推荐一个替代方案吗?因为我刚刚开始,我想越简单越好。你会说我得到的时间与硬件兼容吗?
  • 不幸的是,所有使矩阵乘法快速的东西也使它变得更复杂。作为参考,在 Sandy Bridge E 上(我猜你使用 i7-3960X?)你的 DP FPop/循环上限是 4 次乘法和4 补充,您可以根据时钟速度(取决于有多少内核处于活动状态)、内核数量和矩阵大小计算出最短时间,然后您可以看到您离该最短时间有多近
  • 我还建议Eigen,一个非常易于使用的矩阵代数库。
  • 作为比较,在我的 Haswell(4770K,3.9GHz)上,将两个 4096x4096 矩阵在一个内核上相乘大约需要 1.5 秒,这还不是最佳的。请注意,MMM 相当独特,因为它不需要受到内存带宽的限制,因为它有一个立方的算术量并且只有一个平方的数据量 - 但它受到内存带宽的限制如果你不实现平铺。

标签: c++ matrix mpi matrix-multiplication hpc


【解决方案1】:

你确定你没有计时分配 4K 矢量的...?

vector&lt;vector&lt; &gt;&gt; 不是挤压最佳性能的合适类型。矩阵乘法是关于内存访问的可扩展性和“计算密度”的最佳操作之一。实际上操作的数量为 O(N^3) 而数据的数量为 O(N^2)。

事实上,它用于对地球上的top500 fastest systems 进行基准测试:HPL 用于“高性能 linpack”,它是线性代数的参考实现。你猜怎么着...基准测试中使用的操作是 DGEMM,即“双精度 GEneral Matrix 矩阵乘法”。

DGEMM 是 BLAS 库中的操作名称,它是线性代数的事实标准。今天有许多本地优化的 BLAS 库,无论是商业的(INTEL MKL、IBM ESSL、...)还是开源的(ATLAS),但它们都使用相同的原始(最初是 fortran,现在也是 C)BLAS 接口。 (注意:the original implementation 未优化)

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

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

SCALAPACK 附带 SLUG,您可以在其中找到对块循环分布的极好解释,这是用于在并行系统上压缩线性代数问题的最佳性能的数据分布策略。

但是,为了获得最佳性能,您需要将 MPI 可执行文件与本地优化的 BLAS 库链接。或者自己写,但你并不孤单,所以不要重新发明轮子。

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

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

【讨论】:

  • 是的,我在下一行有时间,就在分配矩阵 auto v = mmi::gen_rand_matrix(size); double time = MPI_Wtime(); 之后。但我不明白这有多重要,包括它会影响所有案件,我认为。
  • SMP 系统上的分配可能/可能是序列化的,或者以任何方式不一定是独立的。无论如何,它们不打算在您的实验中进行测量:您只对内核计时感兴趣。哦,还有 SMP 版本(即分布式内存、节点内、OpenMP)线性代数库。我还记得现在的 essl_smp,几年前也是如此
猜你喜欢
  • 2018-03-24
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 2017-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多