C++ 中 OpenMPI 的成本
Cost of OpenMPI in C++
我有以下程序 C++ 程序,它不使用通信,并且在所有内核上完成相同的相同工作,我知道这根本不使用并行处理:
unsigned n = 130000000;
std::vector<double>vec1(n,1.0);
std::vector<double>vec2(n,1.0);
double precision :: t1,t2,dt;
t1 = MPI_Wtime();
for (unsigned i = 0; i < n; i++)
{
// Do something so it's not a trivial loop
vec1[i] = vec2[i]+i;
}
t2 = MPI_Wtime();
dt = t2-t1;
我运行这个程序在一个节点上有两个
英特尔® 至强® 处理器 E5-2690 v3,所以我总共有 24 个内核。这是一个专用节点,没有其他人使用它。
由于没有通信,并且每个处理器都在做相同数量的(相同的)工作,运行 它在多个处理器上应该给出相同的时间。但是,我得到以下时间(所有核心的平均时间):
1 core: 0.237
2 cores: 0.240
4 cores: 0.241
8 cores: 0.261
16 cores: 0.454
什么会导致时间增加?特别适用于 16 核。
我有 运行 callgrind,并且我在所有内核上得到大致相同的 data/instruction 未命中(未命中百分比相同)。
我在具有两个英特尔® 至强® 处理器 E5-2628L v2(总共 16 个内核)的节点上重复了相同的测试,我观察到执行时间同样增加。这与 MPI 实现有关吗?
我怀疑有公共资源应该被你的程序使用,所以当它们的数量增加时,有延迟,以便释放资源,以便其他进程可以使用它。
您知道,您可能有 24 个核心,但这并不意味着您的所有系统都允许每个核心同时执行所有操作。如评论中所述,内存访问 是可能导致延迟(由于流量)的一件事,磁盘也是如此。
还要考虑互联网络,同样会受到很多访问的困扰。总之,请注意这些硬件延迟足以压倒处理时间。
一般说明:记住程序的效率是如何定义的:
E = S/p, where S is the speedup and p the number of nodes/processes/threads
现在考虑可扩展性。通常程序是弱可扩展的,即你必须以相同的速率增加问题的大小和 p。通过只增加 p 的数量,同时保持问题的大小(n
在你的情况下)不变,同时保持效率不变,产生一个强可扩展的程序。
您的程序根本没有使用并行处理。仅仅因为您使用 OpenMP 编译它并不能使它 parallel.
例如,要并行化 for 循环,您需要使用不同的 #pragma OpenMP 提供。
unsigned n = 130000000;
std::vector<double>vec1(n,1.0);
std::vector<double>vec2(n,1.0);
double precision :: t1,t2,dt;
t1 = MPI_Wtime();
#pragma omp parallel for
for (unsigned i = 0; i < n; i++)
{
// Do something so it's not a trivial loop
vec1[i] = vec2[i]+i;
}
t2 = MPI_Wtime();
dt = t2-t1;
但是,请考虑到对于较大的 n 值,缓存未命中的影响可能会掩盖多核获得的性能。
考虑到您每个等级使用约 2 GiB 的内存,您的代码受内存限制。除了预取器之外,您不是在缓存中而是在主内存中操作。您只是在一定数量的活动内核上达到内存带宽。
另一方面可以是 turbo 模式(如果启用)。如果使用较少的内核,Turbo 模式可以将内核频率提高到更高的水平。只要内存带宽不饱和,turbo 核心的更高频率就会增加每个核心获得的带宽。 This paper 根据活动内核的数量和频率讨论 Haswell 处理器上可用的总内存带宽(图 7./8.)
请注意,这与 MPI / OpenMPI 无关。您也可以通过任何其他方式启动同一个程序 X 次。
我有以下程序 C++ 程序,它不使用通信,并且在所有内核上完成相同的相同工作,我知道这根本不使用并行处理:
unsigned n = 130000000;
std::vector<double>vec1(n,1.0);
std::vector<double>vec2(n,1.0);
double precision :: t1,t2,dt;
t1 = MPI_Wtime();
for (unsigned i = 0; i < n; i++)
{
// Do something so it's not a trivial loop
vec1[i] = vec2[i]+i;
}
t2 = MPI_Wtime();
dt = t2-t1;
我运行这个程序在一个节点上有两个 英特尔® 至强® 处理器 E5-2690 v3,所以我总共有 24 个内核。这是一个专用节点,没有其他人使用它。 由于没有通信,并且每个处理器都在做相同数量的(相同的)工作,运行 它在多个处理器上应该给出相同的时间。但是,我得到以下时间(所有核心的平均时间):
1 core: 0.237
2 cores: 0.240
4 cores: 0.241
8 cores: 0.261
16 cores: 0.454
什么会导致时间增加?特别适用于 16 核。 我有 运行 callgrind,并且我在所有内核上得到大致相同的 data/instruction 未命中(未命中百分比相同)。
我在具有两个英特尔® 至强® 处理器 E5-2628L v2(总共 16 个内核)的节点上重复了相同的测试,我观察到执行时间同样增加。这与 MPI 实现有关吗?
我怀疑有公共资源应该被你的程序使用,所以当它们的数量增加时,有延迟,以便释放资源,以便其他进程可以使用它。
您知道,您可能有 24 个核心,但这并不意味着您的所有系统都允许每个核心同时执行所有操作。如评论中所述,内存访问 是可能导致延迟(由于流量)的一件事,磁盘也是如此。
还要考虑互联网络,同样会受到很多访问的困扰。总之,请注意这些硬件延迟足以压倒处理时间。
一般说明:记住程序的效率是如何定义的:
E = S/p, where S is the speedup and p the number of nodes/processes/threads
现在考虑可扩展性。通常程序是弱可扩展的,即你必须以相同的速率增加问题的大小和 p。通过只增加 p 的数量,同时保持问题的大小(n
在你的情况下)不变,同时保持效率不变,产生一个强可扩展的程序。
您的程序根本没有使用并行处理。仅仅因为您使用 OpenMP 编译它并不能使它 parallel.
例如,要并行化 for 循环,您需要使用不同的 #pragma OpenMP 提供。
unsigned n = 130000000;
std::vector<double>vec1(n,1.0);
std::vector<double>vec2(n,1.0);
double precision :: t1,t2,dt;
t1 = MPI_Wtime();
#pragma omp parallel for
for (unsigned i = 0; i < n; i++)
{
// Do something so it's not a trivial loop
vec1[i] = vec2[i]+i;
}
t2 = MPI_Wtime();
dt = t2-t1;
但是,请考虑到对于较大的 n 值,缓存未命中的影响可能会掩盖多核获得的性能。
考虑到您每个等级使用约 2 GiB 的内存,您的代码受内存限制。除了预取器之外,您不是在缓存中而是在主内存中操作。您只是在一定数量的活动内核上达到内存带宽。
另一方面可以是 turbo 模式(如果启用)。如果使用较少的内核,Turbo 模式可以将内核频率提高到更高的水平。只要内存带宽不饱和,turbo 核心的更高频率就会增加每个核心获得的带宽。 This paper 根据活动内核的数量和频率讨论 Haswell 处理器上可用的总内存带宽(图 7./8.)
请注意,这与 MPI / OpenMPI 无关。您也可以通过任何其他方式启动同一个程序 X 次。