OpenMPI+;Infiniband性能

OpenMPI+;Infiniband性能,mpi,openmpi,infiniband,Mpi,Openmpi,Infiniband,我是HPC的新手,我很好奇MPI在Infiniband上的性能。作为参考,我在通过IB连接的两台不同机器上使用OpenMPI 我编写了一个非常简单的基准测试,以了解使用MPI调用通过IB传输数据的速度。下面您可以看到代码 问题是,当我运行它时,我的吞吐量约为1.4千兆字节/秒。然而,当我使用像ib_write_bw这样的标准ib基准测试时,我得到了接近6gb/s的速度。这一巨大差异的原因是什么?我是否对Gather很幼稚,或者这只是OpenMPI开销的结果,我无法克服 除了代码之外,我还提供了一

我是HPC的新手,我很好奇MPI在Infiniband上的性能。作为参考,我在通过IB连接的两台不同机器上使用OpenMPI

我编写了一个非常简单的基准测试,以了解使用MPI调用通过IB传输数据的速度。下面您可以看到代码

问题是,当我运行它时,我的吞吐量约为1.4千兆字节/秒。然而,当我使用像ib_write_bw这样的标准ib基准测试时,我得到了接近6gb/s的速度。这一巨大差异的原因是什么?我是否对Gather很幼稚,或者这只是OpenMPI开销的结果,我无法克服

除了代码之外,我还提供了一个图来显示我的简单基准测试的结果

提前谢谢

结果:

代码:

#包括
#包括
#包括
#包括
使用名称空间std;
无效服务器(无符号整数大小,无符号整数n){
uint8_t*recv=新的uint8_t[size*n];
uint8_t*发送=新的uint8_t[大小];
std::clock_t s=std::clock();
MPI_聚集(发送、大小、MPI_字符、接收、大小、MPI_字符、0、MPI_通信世界);
std::clock_t e=std::clock();

CUT

你必须考虑在等级0上接收到的集合调用的全部有效负载大小取决于等级的数量。因此,例如,4个进程发送1000个字节,实际上在根秩上接收到4000个字节。(可能需要绕道网络堆栈)。这是在添加MPI和较低网络协议的开销之前。

在您的代码中,您正在执行每个消息大小的单个集合操作。 与为性能度量而编写的测试(例如ib_write_bw)相比,这涉及到巨大的开销。 一般来说,将MPI集体与ib_write_bw进行比较不是苹果对苹果的比较:

  • RDMA操作码

    • ib_write_bw使用RDMA_写入操作,根本不使用CPU—一旦完成初始握手,它就是纯RDMA,仅受网络和PCIe功能的限制
    • MPI将为不同的集合和不同的消息大小使用不同的RDMA操作码,如果您像在代码中那样做,MPI会为每条消息做很多事情(因此会产生巨大的开销)
  • 数据开销

    • ib_write_bw传输几乎纯数据(有一个本地路由头和一个有效负载)
    • MPI向每个数据包添加了更多的数据(报头),以允许接收方识别消息
  • 零拷贝

    • ib_write_bw正在进行所谓的“零拷贝”——数据直接从用户缓冲区发送,并在接收端直接写入用户缓冲区,而不从/到缓冲区进行拷贝
    • MPI将消息从客户端的缓冲区复制到发送方的内部缓冲区,然后再从接收方的内部缓冲区复制到服务器的缓冲区。同样,此行为取决于消息大小、MPI配置和MPI实现,但您可以大致了解
  • 内存注册

    • ib_write_bw注册所需的内存区域,并在开始测量性能之前在客户端和服务器之间交换此信息
    • 如果MPI在集体执行期间需要注册一些内存区域,它将在您测量时间时注册
  • 还有很多

    • 即使是“小”事情,比如加热HCA上的缓存线
现在,我们已经讨论了为什么你不应该比较这些东西,下面是你应该做的:

有两个库被视为MPI性能度量的事实标准:

  • -上面说的是Intel,但它是作为标准MPI应用程序编写的,可以与任何MPI实现一起使用
  • -同样,它说的是MVAPICH,但它可以与任何MPI一起工作
  • 下载这些,用你的MPI编译,运行你的基准测试,看看你得到了什么。 这是MPI所能达到的最高值。 如果你得到的结果比你的小程序好得多(你肯定会得到)——这是开源的,看看专业人士是怎么做的:)


    玩得开心!

    我发布的图是针对两节点系统的,因此您的论点(通常是正确的)不应该影响当前的情况。您是否尝试过使用另一个已建立的基准测试来验证这些性能问题与代码无关?如果您可以访问英特尔编译器和MPI,“英特尔MPI基准测试”是一个很好的验证工具性能问题。您在基准测试中改变了负载大小还是使用了单一大小,预热如何,您运行了多少次?IMB PingPong将在多次迭代中运行各种负载大小,以测试预热后的带宽和吞吐量。
    #include<iostream>
    #include<mpi.h>
    #include <stdint.h>
    #include <ctime>
    using namespace std;
    
    
    void server(unsigned int size, unsigned int n) {
     uint8_t* recv = new uint8_t[size * n];
     uint8_t* send = new uint8_t[size];
     std::clock_t s = std::clock();
     MPI_Gather(send, size, MPI_CHAR, recv, size, MPI_CHAR, 0, MPI_COMM_WORLD);
     std::clock_t e = std::clock();
     cout<<size<<" "<<(e - s)/double(CLOCKS_PER_SEC)<<endl;
     delete [] recv;
     delete [] send;
    }
    
    void client(unsigned int size, unsigned int n) {
     uint8_t* send = new uint8_t[size];
     MPI_Gather(send, size, MPI_CHAR, NULL, 0, MPI_CHAR, 0, MPI_COMM_WORLD);
     delete [] send;
    }
    
    int main(int argc, char **argv) {
     int ierr, size, rank;
     MPI_Init(&argc, &argv);
     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
     MPI_Comm_size(MPI_COMM_WORLD, &size);
     cout<<"Rank "<<rank<<" of "<<size<<endl;
     unsigned int min = 1, max = (1 << 31), n = 1000;
     for (unsigned int i = 1; i < n; i++) {
      unsigned int s = i * ((max - min) / n);
      if(rank == 0) server(s, size); else client(s, size);
     }
    
     MPI_Finalize();
    }