c++ - 进程数量增加导致 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;
}
解决方案
这是预期的行为。要获得 MPI 的性能,您必须执行数据分解(负载平衡)、通信优化(阻塞与非阻塞)等。
正如我从问题中了解到的那样,12 个进程正在对 12 个2000X2000
矩阵进行计算,平均时间为 1.8 秒,而单个进程执行计算的平均时间仅为 1.2 秒。
是的,对于上述场景,MPI 性能不会比单个进程更好,并且由于以下原因必须更高(其中一些是Hristo Iliev在评论中提到的):
- MPI 引起的开销
- MPI 中最慢的进程所花费的时间
- 内存带宽(每个进程需要访问 2000*2000 矩阵,可能会导致争用)。
- 缓存(更高级别的缓存在处理器之间共享,多个进程的频繁缓存访问等可能会影响整体应用程序性能)
此外,性能改进(加速)将基于应用程序的并行部分,并且由于您的应用程序中没有并行部分,因此您不会观察到并行化的任何好处。
此外,如果一个 2000X2000 的矩阵分布在 12 个进程中,我们不能保证 MPI 的性能会优于单个进程。这将取决于实现。
推荐阅读
- javascript - Amcharts 4:如何组合 LineSeries 的工具提示
- c# - C# 代码在遇到断点时有效,否则在我禁用所有断点时无效 [Winforms]
- android - 无法解析地图
在 Kotlin 中使用 Moshi - 出乎意料的原始双精度 - shell - msiexec 上的多个转换
- java - Java 8中列表为空时如何返回null?
- android - 为什么我的 recyclerView 不显示任何数据?
- django - 卖家对象没有属性配置文件
- scala - 尝试从 Actor 中获取响应时收到死信
- path-finding - 如何阻止 AStar 改变方向
- sql-server - 设置另一个营业时间,而不是实际时间