运行 与 OpenMPI 的专有并行
Run Eigen Parallel with OpenMPI
我是 Eigen 的新手,正在编写一些简单的代码来测试它的性能。我使用的是 M1 Pro 芯片 的 MacBook Pro(不知道是不是 ARM 架构导致的问题)。代码是一个简单的拉普拉斯方程求解器
#include <iostream>
#include "mpi.h"
#include "Eigen/Dense"
#include <chrono>
using namespace Eigen;
using namespace std;
const size_t num = 1000UL;
MatrixXd initilize(){
MatrixXd u = MatrixXd::Zero(num, num);
u(seq(1, fix<num-2>), seq(1, fix<num-2>)).setConstant(10);
return u;
}
void laplace(MatrixXd &u){
setNbThreads(8);
MatrixXd u_old = u;
u(seq(1,last-1),seq(1,last-1)) =
(( u_old(seq(0,last-2,fix<1>),seq(1,last-1,fix<1>)) + u_old(seq(2,last,fix<1>),seq(1,last-1,fix<1>)) +
u_old(seq(1,last-1,fix<1>),seq(0,last-2,fix<1>)) + u_old(seq(1,last-1,fix<1>),seq(2,last,fix<1>)) )*4.0 +
u_old(seq(0,last-2,fix<1>),seq(0,last-2,fix<1>)) + u_old(seq(0,last-2,fix<1>),seq(2,last,fix<1>)) +
u_old(seq(2,last,fix<1>),seq(0,last-2,fix<1>)) + u_old(seq(2,last,fix<1>),seq(2,last,fix<1>)) ) /20.0;
}
int main(int argc, const char * argv[]) {
initParallel();
setNbThreads(0);
cout << nbThreads() << endl;
MatrixXd u = initilize();
auto start = std::chrono::high_resolution_clock::now();
for (auto i=0UL; i<100; i++) {
laplace(u);
}
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
// cout << u(seq(0, fix<10>), seq(0, fix<10>)) << endl;
cout << "Execution time (ms): " << duration.count() << endl;
return 0;
}
编译 gcc
并启用 OpenMPI
james@MBP14 tests % g++-11 -fopenmp -O3 -I/usr/local/include -I/opt/homebrew/Cellar/open-mpi/4.1.3/include -o test4 test.cpp
直接运行二进制文件
james@MBP14 tests % ./test4
8
Execution time (ms): 273
运行 与 mpirun
并指定 8 个线程
james@MBP14 tests % mpirun -np 8 test4
8
8
8
8
8
8
8
8
Execution time (ms): 348
Execution time (ms): 347
Execution time (ms): 353
Execution time (ms): 356
Execution time (ms): 350
Execution time (ms): 353
Execution time (ms): 357
Execution time (ms): 355
所以显然矩阵运算不是 运行 并行的,相反,每个线程都 运行 是相同的代码副本。
应该怎么做才能解决这个问题?我对使用 OpenMPI
有什么误解吗?
您将 OpenMPI 与 OpenMP 混淆了。
- gcc 标志
-fopenmp
启用 OpenMP。这是通过在代码中使用特殊的 #pragma omp
语句来并行化应用程序的一种方法。并行化发生在 单个 CPU(或者,准确地说,计算节点,如果计算节点有多个 CPU)。这允许使用 CPU 的所有核心。 OpenMP 不能用于在多个计算节点上并行化应用程序。
- 另一方面,MPI (where OpenMPI 是一个特定的实现)可用于在 多个计算节点 上并行化代码(即,粗略地说,在多台计算机上连接)。它还可用于在单台计算机的多个内核上并行化某些代码。所以 MPI 更通用,但也更难使用。
要使用 MPI,您需要调用“特殊”函数并自己完成分发数据的艰苦工作。如果不这样做,使用 mpirun
调用应用程序只会创建几个相同的进程(不是线程!),它们执行完全相同的计算。您还没有并行化您的应用程序,您只是执行了 8 次。
没有启用 MPI 的编译器标志。 MPI 没有内置到任何编译器中。相反,MPI 是一种标准,而 OpenMPI 是一个实现该标准的特定库。您应该阅读有关 MPI 和 OpenMPI 的教程或书籍(例如 google 出现 this one)。
注意:通常,MPI 库(例如 OpenMPI)附带 executables/scripts(例如 mpicc
),其行为类似于编译器。但它们只是编译器的薄包装,例如 gcc
。这些包装器用于自动告诉实际编译器包含目录和库 link 。但同样,编译器本身对 MPI 一无所知。
我是 Eigen 的新手,正在编写一些简单的代码来测试它的性能。我使用的是 M1 Pro 芯片 的 MacBook Pro(不知道是不是 ARM 架构导致的问题)。代码是一个简单的拉普拉斯方程求解器
#include <iostream>
#include "mpi.h"
#include "Eigen/Dense"
#include <chrono>
using namespace Eigen;
using namespace std;
const size_t num = 1000UL;
MatrixXd initilize(){
MatrixXd u = MatrixXd::Zero(num, num);
u(seq(1, fix<num-2>), seq(1, fix<num-2>)).setConstant(10);
return u;
}
void laplace(MatrixXd &u){
setNbThreads(8);
MatrixXd u_old = u;
u(seq(1,last-1),seq(1,last-1)) =
(( u_old(seq(0,last-2,fix<1>),seq(1,last-1,fix<1>)) + u_old(seq(2,last,fix<1>),seq(1,last-1,fix<1>)) +
u_old(seq(1,last-1,fix<1>),seq(0,last-2,fix<1>)) + u_old(seq(1,last-1,fix<1>),seq(2,last,fix<1>)) )*4.0 +
u_old(seq(0,last-2,fix<1>),seq(0,last-2,fix<1>)) + u_old(seq(0,last-2,fix<1>),seq(2,last,fix<1>)) +
u_old(seq(2,last,fix<1>),seq(0,last-2,fix<1>)) + u_old(seq(2,last,fix<1>),seq(2,last,fix<1>)) ) /20.0;
}
int main(int argc, const char * argv[]) {
initParallel();
setNbThreads(0);
cout << nbThreads() << endl;
MatrixXd u = initilize();
auto start = std::chrono::high_resolution_clock::now();
for (auto i=0UL; i<100; i++) {
laplace(u);
}
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
// cout << u(seq(0, fix<10>), seq(0, fix<10>)) << endl;
cout << "Execution time (ms): " << duration.count() << endl;
return 0;
}
编译 gcc
并启用 OpenMPI
james@MBP14 tests % g++-11 -fopenmp -O3 -I/usr/local/include -I/opt/homebrew/Cellar/open-mpi/4.1.3/include -o test4 test.cpp
直接运行二进制文件
james@MBP14 tests % ./test4
8
Execution time (ms): 273
运行 与 mpirun
并指定 8 个线程
james@MBP14 tests % mpirun -np 8 test4
8
8
8
8
8
8
8
8
Execution time (ms): 348
Execution time (ms): 347
Execution time (ms): 353
Execution time (ms): 356
Execution time (ms): 350
Execution time (ms): 353
Execution time (ms): 357
Execution time (ms): 355
所以显然矩阵运算不是 运行 并行的,相反,每个线程都 运行 是相同的代码副本。
应该怎么做才能解决这个问题?我对使用 OpenMPI
有什么误解吗?
您将 OpenMPI 与 OpenMP 混淆了。
- gcc 标志
-fopenmp
启用 OpenMP。这是通过在代码中使用特殊的#pragma omp
语句来并行化应用程序的一种方法。并行化发生在 单个 CPU(或者,准确地说,计算节点,如果计算节点有多个 CPU)。这允许使用 CPU 的所有核心。 OpenMP 不能用于在多个计算节点上并行化应用程序。 - 另一方面,MPI (where OpenMPI 是一个特定的实现)可用于在 多个计算节点 上并行化代码(即,粗略地说,在多台计算机上连接)。它还可用于在单台计算机的多个内核上并行化某些代码。所以 MPI 更通用,但也更难使用。
要使用 MPI,您需要调用“特殊”函数并自己完成分发数据的艰苦工作。如果不这样做,使用 mpirun
调用应用程序只会创建几个相同的进程(不是线程!),它们执行完全相同的计算。您还没有并行化您的应用程序,您只是执行了 8 次。
没有启用 MPI 的编译器标志。 MPI 没有内置到任何编译器中。相反,MPI 是一种标准,而 OpenMPI 是一个实现该标准的特定库。您应该阅读有关 MPI 和 OpenMPI 的教程或书籍(例如 google 出现 this one)。
注意:通常,MPI 库(例如 OpenMPI)附带 executables/scripts(例如 mpicc
),其行为类似于编译器。但它们只是编译器的薄包装,例如 gcc
。这些包装器用于自动告诉实际编译器包含目录和库 link 。但同样,编译器本身对 MPI 一无所知。