【问题标题】:How to load balance a simple loop using MPI in C++如何在 C++ 中使用 MPI 对简单循环进行负载平衡
【发布时间】:2019-04-07 19:45:46
【问题描述】:

我正在编写一些计算量很大但高度可并行化的代码。并行化后,我打算在 HPC 上运行它,但是为了将运行时间控制在一周内,问题需要随着处理器的数量很好地扩展。

下面是我试图实现的一个简单而可笑的例子,它足够简洁,可以编译和演示我的问题;

#include <iostream>
#include <ctime>
#include "mpi.h"

using namespace std;

double int_theta(double E){
    double result = 0;
    for (int k = 0; k < 20000; k++)
        result += E*k;
    return result;
}

int main() 
{
    int n = 3500000;
    int counter = 0;
    time_t timer;
    int start_time = time(&timer);
    int myid, numprocs;
    int k;
    double integrate, result;
    double end = 0.5;
    double start = -2.;
    double E;
    double factor = (end - start)/(n*1.);
    integrate = 0;
    MPI_Init(NULL,NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    for (k = myid; k<n+1; k+=numprocs){
        E = start + k*(end-start)/n;
        if (( k == 0 ) || (k == n))
            integrate += 0.5*factor*int_theta(E);
        else
            integrate += factor*int_theta(E);
        counter++;
    }
    cout<<"process "<<myid<<" took "<<time(&timer)-start_time<<"s"<<endl;
    cout<<"process "<<myid<<" performed "<<counter<<" computations"<<endl;
    MPI_Reduce(&integrate, &result, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    if (myid == 0)
        cout<<result<<endl;
    MPI_Finalize();
    return 0;
}

我已经在我的四核笔记本电脑上编译了这个问题

mpiicc test.cpp -std=c++14 -O3 -DMKL_LP64 -lmkl_intel_lp64 - lmkl_sequential -lmkl_core -lpthread -lm -ldl

我得到以下输出;

$ mpirun -np 4 ./a.out
process 3 took 14s
process 3 performed 875000 computations
process 1 took 15s
process 1 performed 875000 computations
process 2 took 16s
process 2 performed 875000 computations
process 0 took 16s
process 0 performed 875001 computations
-3.74981e+08

$ mpirun -np 3 ./a.out 
process 2 took 11s
process 2 performed 1166667 computations
process 1 took 20s
process 1 performed 1166667 computations
process 0 took 20s
process 0 performed 1166667 computations
-3.74981e+08

$ mpirun -np 2 ./a.out 
process 0 took 16s
process 0 performed 1750001 computations
process 1 took 16s
process 1 performed 1750000 computations
-3.74981e+08

在我看来,在我不知道的地方一定有一个障碍。使用 2 个处理器而不是 3 个处理器,我可以获得更好的性能。有人可以提供任何建议吗?谢谢

【问题讨论】:

  • 在代码中我没有看到任何明显的问题 - 看起来像是令人尴尬的并行。您的笔记本电脑真的有四个硬件核心(而不是四个逻辑核心,即两个硬件核心和超线程)吗?您使用的是哪个操作系统?四个独立的 MPI 进程是固定在它们各自的核心上还是可能在四处移动?后台还有其他工作吗?
  • @dasmy 感谢您的快速回复。为了回答你的问题,lscpu 告诉我CPU(s): 4 On-line CPU(s) list: 0-3 Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 1 我正在使用 64 位 Linux Mint。我相信 MPI 进程已固定,因为我没有更改默认行为(已固定)。除了通常的系统工作外,没有其他工作。我认为有些奇怪,因为 2 个进程的运行时间等于 4 个进程的运行时间,而 3 的表现最差,但您的回复表明这是由于我使用的硬件造成的?

标签: c++ mpi intel-mpi


【解决方案1】:

如果我正确读取了lscpu 的输出(例如,在https://unix.stackexchange.com/a/218081 的帮助下),您将拥有 4 个逻辑 CPU,但只有 2 个硬件核心(1 个插槽 x 每个插槽 2 个核心)。 使用cat /proc/cpuinfo,您可以找到 CPU 的品牌和型号,以便了解更多信息。

四个逻辑 CPU 可能来自超线程,这意味着一些硬件资源(例如 FPU 单元,但我不是这方面的专家)在两个内核之间共享。因此,我不希望在两个进程之外有任何好的并行扩展。

对于可扩展性测试,您应该尝试使用可能有 6 个或更多硬件内核的机器,这样可以得到更好的估计。

通过查看您的代码,我希望可以完美地扩展到任意数量的内核 - 至少只要您不包括进程启动和最终 MPI_Reduce 所需的时间。随着涉及的进程越多,这些肯定会变得更慢。

【讨论】:

  • 非常感谢您的回答,我已经在集群上运行了上述代码,发现我在一个核心(具有 32 个进程)上获得了良好的可扩展性。由于某种原因,使用多个节点时代码似乎挂起,但我已与管理员联系,希望这是由于代码需要以某种方式编译,或提交到 bsub 队列中具体的办法。大概不是我写代码的方式吧?
  • 是的,这可能是特定于机器的问题。原因很难猜测,但可以肯定的是,您的管理员可以为您提供帮助。
猜你喜欢
  • 2017-02-05
  • 1970-01-01
  • 2016-05-09
  • 1970-01-01
  • 1970-01-01
  • 2019-02-02
  • 2020-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多