为什么mpi_bcast比mpi_reduce慢这么多
why is mpi_bcast so much slower than mpi_reduce?
使用MPI,我们可以进行广播,将数组发送到多个节点,或者将多个节点的数组组合到一个节点上。
我想实现这些的最快方法将是使用二叉树,其中每个节点要么发送到两个节点(bcast),要么减少两个节点(reduce),这将在节点数量上给出时间对数。
似乎没有任何理由说明哪个broadcast会特别慢于reduce?
我在一个4台计算机集群上运行了下面的测试程序,其中每台计算机有12个核心。奇怪的是,广播比减少慢得多。为什么?我能做点什么吗?
结果如下:
inited mpi: 0.472943 seconds
N: 200000 1.52588MB
P = 48
did alloc: 0.000147641 seconds
bcast: 0.349956 seconds
reduce: 0.0478526 seconds
bcast: 0.369131 seconds
reduce: 0.0472673 seconds
bcast: 0.516606 seconds
reduce: 0.0448555 seconds
代码是:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <sys/time.h>
using namespace std;
#include <mpi.h>
class NanoTimer {
public:
struct timespec start;
NanoTimer() {
clock_gettime(CLOCK_MONOTONIC, &start);
}
double elapsedSeconds() {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
double time = (now.tv_sec - start.tv_sec) + (double) (now.tv_nsec - start.tv_nsec) * 1e-9;
start = now;
return time;
}
void toc(string label) {
double elapsed = elapsedSeconds();
cout << label << ": " << elapsed << " seconds" << endl;
}
};
int main( int argc, char *argv[] ) {
if( argc < 2 ) {
cout << "Usage: " << argv[0] << " [N]" << endl;
return -1;
}
int N = atoi( argv[1] );
NanoTimer timer;
MPI_Init( &argc, &argv );
int p, P;
MPI_Comm_rank( MPI_COMM_WORLD, &p );
MPI_Comm_size( MPI_COMM_WORLD, &P );
MPI_Barrier(MPI_COMM_WORLD);
if( p == 0 ) timer.toc("inited mpi");
if( p == 0 ) {
cout << "N: " << N << " " << (N*sizeof(double)/1024.0/1024) << "MB" << endl;
cout << "P = " << P << endl;
}
double *src = new double[N];
double *dst = new double[N];
MPI_Barrier(MPI_COMM_WORLD);
if( p == 0 ) timer.toc("did alloc");
for( int it = 0; it < 3; it++ ) {
MPI_Bcast( src, N, MPI_DOUBLE, 0, MPI_COMM_WORLD );
MPI_Barrier(MPI_COMM_WORLD);
if( p == 0 ) timer.toc("bcast");
MPI_Reduce( src, dst, N, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD );
MPI_Barrier(MPI_COMM_WORLD);
if( p == 0 ) timer.toc("reduce");
}
delete[] src;
MPI_Finalize();
return 0;
}
集群节点运行64位ubuntu 12.04。我尝试了openmpi和mpich2,得到了非常相似的结果。网络是千兆以太网,不是最快的,但我最好奇的不是绝对速度,而是广播和减少之间的差距。
我不认为这很好地回答了你的问题,但我希望它能提供一些见解。
MPI只是一个标准。它没有定义每个函数应该如何实现。因此,MPI中某些任务的性能(在您的示例中是MPI_Bcast和MPI_Reduce)严格基于您正在使用的实现。你可以设计一个使用点对点通信方法的广播,它比给定的MPI_Bcast性能更好。
无论如何,你必须考虑这些函数在做什么。广播是从一个进程中获取信息并将其发送给所有其他进程;Reduce是从每个进程中获取信息并将其减少到一个进程中。根据(最新的)标准,MPI_Bcast被认为是一个One-to-All集体操作,而MPI_Reduce被认为是一个All-to-One集体操作。因此,您对MPI_Reduce使用二叉树的直觉可能在两种实现中都能找到。然而,它很可能在MPI_Bcast中找不到。MPI_Bcast可能是使用非阻塞点对点通信实现的(从包含信息的进程发送到所有其他进程),在通信后等待所有。在任何情况下,为了弄清楚这两个函数是如何工作的,我建议深入研究OpenMPI和MPICH2实现的源代码。
正如Hristo提到的,这取决于缓冲区的大小。如果你发送一个大的缓冲区,广播将不得不做很多大的发送,而接收在缓冲区上做一些本地操作,将其减少到一个值,然后只发送一个值,而不是整个缓冲区。
- 用MacOS Mojave编译C++:致命错误:mpi.h:没有这样的文件或目录
- MPI突然停止了对多个核心的操作
- 设置 Visual Studio for MPI: 找不到标识符错误
- 使用 make 编译 MPI,几个命名空间错误,例如"错误:未知类型名称'使用'?
- 如何使用 MPI 的远程内存访问 (RMA) 功能并行化数据聚合?
- 重载 MPI 中的运算符 ()
- MPI:检查是否有任何进程已终止
- 使用 pybind11 共享 MPI 通信器
- 使用 CMake,Microsoft MPI 和 Visual Studio 2017 找不到 mpi.h
- 在具有 MPI 的超立方体中广播
- 通过 mpi 发送 c++ 标准::矢量<bool>
- 使用 MPI 的 C++ 中的并行 for 循环
- 如何将 OpenMP 和 MPI 导入到大型 CLion CMake 项目中?
- 如何通过Boost.MPI发送2d Boost.MultiArray的子阵列?
- HDF5 构建了并行支持,但找不到特定于 mpi 的功能
- MPI 集合通信中的指针分配
- 仅特定内核计数上的 MPI 内存损坏
- 使用动态分配的 Bcast、分散和收集时出现 MPI 隔离错误
- structs的std::vector的MPI BCast(广播)
- 具有线程支持和Bcast调用的MPI