首页 > 解决方案 > 进程数量增加导致 MPI 性能损失

问题描述

我使用 C++ 和 MPI 来执行一些线性代数计算,比如特征值分解。这些计算对每个进程来说完全是本地的,所以我认为单进程性能应该不受我运行的进程总数的影响,只要有足够的计算资源。

然而,事实证明,随着进程总数的增加,每个进程的性能都会下降。在一个由 2 个 Intel Xeon Gold 6132 CPU(总共 28 个物理内核或 56 个线程)组成的节点上,我的测试发现,单个进程的 2000×2000 对称矩阵的特征分解大约需要 1.1 秒, 4 个独立进程(使用 mpirun -np 4 ./test)为 1.3 秒,12 个进程为 1.8 秒。

我想知道,这是 MPI 的预期行为,还是我错过了一些绑定选项?我试过“mpirun -np 12 --bind-to core:12 ./test”,但没有帮助。我正在使用 Armadillo 库,它与 Intel MKL 链接。环境变量MKL_NUM_THREADS设置为1。附上源码。

#include <mpi.h>
#include <armadillo>
#include <chrono>
#include <sstream>

using namespace arma;
using iclock = std::chrono::high_resolution_clock;

int main(int, char**argv) {

    ////////////////////////////////////////////////////
    //              MPI Initialization
    ////////////////////////////////////////////////////
    int id, nprocs;
    MPI_Init(nullptr, nullptr);
    MPI_Comm_rank(MPI_COMM_WORLD, &id);
    MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

    ////////////////////////////////////////////////////
    //              parse arguments
    ////////////////////////////////////////////////////
    int sz = 0, nt = 0;
    std::stringstream ss; 

    if (id == 0) {
        ss << argv[1];
        ss >> sz; 
        ss.clear();
        ss.str("");

        ss << argv[2];
        ss >> nt; 
        ss.clear();
        ss.str("");
    }   

    MPI_Bcast(&sz, 1, MPI_INT, 0, MPI_COMM_WORLD);
    MPI_Bcast(&nt, 1, MPI_INT, 0, MPI_COMM_WORLD);

    ////////////////////////////////////////////////////
    //                test and timing
    ////////////////////////////////////////////////////
    mat a = randu(sz, sz);
    a += a.t();

    mat evec(sz, sz);
    vec eval(sz);

    iclock::time_point start = iclock::now();

    for (int i = 0; i != nt; ++i) {
        //evec = a*a;
        eig_sym(eval, evec, a); // <-------here
    }   

    std::chrono::duration<double> dur = iclock::now() - start;

    double t = dur.count() / nt;

    ////////////////////////////////////////////////////
    //               collect timing
    ////////////////////////////////////////////////////
    vec durs(nprocs);
    MPI_Gather(&t, 1, MPI_DOUBLE, durs.memptr(), 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);

    if (id == 0) {
        std::cout << "average time elapsed of each proc:" << std::endl;
        durs.print();
    }

    MPI_Finalize();

    return 0;
}

标签: c++performancempiarmadillointel-mkl

解决方案


这是预期的行为。要获得 MPI 的性能,您必须执行数据分解(负载平衡)、通信优化(阻塞与非阻塞)等。

正如我从问题中了解到的那样,12 个进程正在对 12 个2000X2000矩阵进行计算,平均时间为 1.8 秒,而单个进程执行计算的平均时间仅为 1.2 秒。

是的,对于上述场景,MPI 性能不会比单个进程更好,并且由于以下原因必须更高(其中一些是Hristo Iliev在评论中提到的):

  1. MPI 引起的开销
  2. MPI 中最慢的进程所花费的时间
  3. 内存带宽(每个进程需要访问 2000*2000 矩阵,可能会导致争用)。
  4. 缓存(更高级别的缓存在处理器之间共享,多个进程的频繁缓存访问等可能会影响整体应用程序性能)

此外,性能改进(加速)将基于应用程序的并行部分,并且由于您的应用程序中没有并行部分,因此您不会观察到并行化的任何好处。

此外,如果一个 2000X2000 的矩阵分布在 12 个进程中,我们不能保证 MPI 的性能会优于单个进程。这将取决于实现。


推荐阅读