ODE 函数中带有 ODEINT 的 OpenMP
OpenMP with ODEINT in ODE function
我正在尝试在内部并行化由 ODEINT 集成的 ODE 函数。
我做了下面的小例子
#include <iostream>
#include <chrono>
#include <Eigen/Dense>
#include <omp.h>
#include <boost/numeric/odeint.hpp>
#include <boost/numeric/odeint/external/openmp/openmp.hpp>
#include <boost/numeric/odeint/external/eigen/eigen.hpp>
using namespace boost::numeric::odeint;
class System {
private:
Eigen::VectorXd _input_data;
public:
System( Eigen::VectorXd &input_data ) { _input_data = input_data; };
void operator() ( const Eigen::VectorXd &x , Eigen::VectorXd &dxdt , const double t ) {
double _sum = 0.;
#pragma omp parallel for reduction(+:_sum)
for(int k = 0; k < _input_data.size(); ++k) {
_sum += _input_data(k);
};
dxdt(0) = _sum;
};
};
int main() {
omp_set_num_threads(1);
Eigen::VectorXd input_data = Eigen::VectorXd::Zero(100);
System ode(input_data);
runge_kutta_dopri5<Eigen::VectorXd> rk5_stepper;
Eigen::VectorXd x = Eigen::VectorXd::Zero(1);
auto start = std::chrono::high_resolution_clock::now();
size_t steps = integrate_const(rk5_stepper, ode, x, 0., 1., 0.01);
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
std::cout << "Execution time: " << duration.count() / 1000000. << " sec" << std::endl;
return 0;
}
使用 CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_COMPILER /usr/local/bin/gcc-9)
set(CMAKE_CXX_COMPILER /usr/local/bin/g++-9)
project(ODEINT_OPENMP_TEST)
set(CMAKE_CXX_STANDARD 14)
include_directories("/usr/local/include")
find_package(OpenMP REQUIRED)
add_executable(ODEINT_OPENMP_TEST main.cpp)
target_link_libraries(ODEINT_OPENMP_TEST PRIVATE OpenMP::OpenMP_CXX)
当我尝试通过 omp_set_num_threads(N)
使用更多线程时,与仅使用单个线程 omp_set_num_threads(1)
相比,程序始终在变慢。选择 N=2,程序变得大约慢 x3(在我的机器上)。
直觉上,右边的函数应该 运行 并行更快?我做错了什么吗?
首先,您的循环太小,无法从在此特定示例中使用多线程中获益(在我的机器上按顺序大约 3.5 毫秒,在 6 个内核上使用 6 个线程大约 1.8 毫秒)。
此外,您的基准测试时间太短,您可能会测量意想不到的影响(缓存、页面错误、处理器频率缩放问题等)。考虑将其置于循环中以减轻大部分影响(如果这在现实世界条件下有意义)。
此外,某些 OpenMP 运行时会在执行并行部分时创建线程。这个操作相当慢。由于指令 #pragma omp parallel
包含在计时中,您还可以测量线程创建。
以下是我的 6 核机器的结果,尺寸大 1000 倍:
1 thread: 2.330 sec
2 threads: 1.212 sec
3 threads: 0.813 sec
4 threads: 0.649 sec
5 threads: 0.532 sec
6 threads: 0.459 sec
6线程加速5.1,不错
请注意,由于您的循环似乎受内存限制(内存吞吐量不随使用的内核数量而缩放),因此缩放比例可能会更差。
我正在尝试在内部并行化由 ODEINT 集成的 ODE 函数。
我做了下面的小例子
#include <iostream>
#include <chrono>
#include <Eigen/Dense>
#include <omp.h>
#include <boost/numeric/odeint.hpp>
#include <boost/numeric/odeint/external/openmp/openmp.hpp>
#include <boost/numeric/odeint/external/eigen/eigen.hpp>
using namespace boost::numeric::odeint;
class System {
private:
Eigen::VectorXd _input_data;
public:
System( Eigen::VectorXd &input_data ) { _input_data = input_data; };
void operator() ( const Eigen::VectorXd &x , Eigen::VectorXd &dxdt , const double t ) {
double _sum = 0.;
#pragma omp parallel for reduction(+:_sum)
for(int k = 0; k < _input_data.size(); ++k) {
_sum += _input_data(k);
};
dxdt(0) = _sum;
};
};
int main() {
omp_set_num_threads(1);
Eigen::VectorXd input_data = Eigen::VectorXd::Zero(100);
System ode(input_data);
runge_kutta_dopri5<Eigen::VectorXd> rk5_stepper;
Eigen::VectorXd x = Eigen::VectorXd::Zero(1);
auto start = std::chrono::high_resolution_clock::now();
size_t steps = integrate_const(rk5_stepper, ode, x, 0., 1., 0.01);
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
std::cout << "Execution time: " << duration.count() / 1000000. << " sec" << std::endl;
return 0;
}
使用 CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_COMPILER /usr/local/bin/gcc-9)
set(CMAKE_CXX_COMPILER /usr/local/bin/g++-9)
project(ODEINT_OPENMP_TEST)
set(CMAKE_CXX_STANDARD 14)
include_directories("/usr/local/include")
find_package(OpenMP REQUIRED)
add_executable(ODEINT_OPENMP_TEST main.cpp)
target_link_libraries(ODEINT_OPENMP_TEST PRIVATE OpenMP::OpenMP_CXX)
当我尝试通过 omp_set_num_threads(N)
使用更多线程时,与仅使用单个线程 omp_set_num_threads(1)
相比,程序始终在变慢。选择 N=2,程序变得大约慢 x3(在我的机器上)。
直觉上,右边的函数应该 运行 并行更快?我做错了什么吗?
首先,您的循环太小,无法从在此特定示例中使用多线程中获益(在我的机器上按顺序大约 3.5 毫秒,在 6 个内核上使用 6 个线程大约 1.8 毫秒)。
此外,您的基准测试时间太短,您可能会测量意想不到的影响(缓存、页面错误、处理器频率缩放问题等)。考虑将其置于循环中以减轻大部分影响(如果这在现实世界条件下有意义)。
此外,某些 OpenMP 运行时会在执行并行部分时创建线程。这个操作相当慢。由于指令 #pragma omp parallel
包含在计时中,您还可以测量线程创建。
以下是我的 6 核机器的结果,尺寸大 1000 倍:
1 thread: 2.330 sec
2 threads: 1.212 sec
3 threads: 0.813 sec
4 threads: 0.649 sec
5 threads: 0.532 sec
6 threads: 0.459 sec
6线程加速5.1,不错
请注意,由于您的循环似乎受内存限制(内存吞吐量不随使用的内核数量而缩放),因此缩放比例可能会更差。