C++ 用于内部的openmp延迟
我有一段代码要并行化,openmp程序比串行版本慢得多,那么我的实现有什么问题呢?。这是程序的代码C++ 用于内部的openmp延迟,c++,performance,parallel-processing,openmp,C++,Performance,Parallel Processing,Openmp,我有一段代码要并行化,openmp程序比串行版本慢得多,那么我的实现有什么问题呢?。这是程序的代码 #include <iostream> #include <gsl/gsl_math.h> #include "Chain.h" using namespace std; int main(){ int const N=1000; int timeSteps=100; double delta=0.0001; double qq[N]; Chain c
#include <iostream>
#include <gsl/gsl_math.h>
#include "Chain.h"
using namespace std;
int main(){
int const N=1000;
int timeSteps=100;
double delta=0.0001;
double qq[N];
Chain ch(N);
ch.initCond();
for (int t=0; t<timeSteps; t++){
ch.changeQ(delta*t);
ch.calMag_i();
ch.calForce001();
}
ch.printSomething();
}
而Chain.cpp是
Chain::Chain(int const Np){
this->N = Np;
this->q = new double[Np];
this->mx = new double[Np];
this->my = new double[Np];
this->force = new double[Np];
}
void Chain::initCond(){
for (int i=0; i<N; i++){
q[i] = 0.0;
force[i] = 0.0;
}
}
void Chain::changeQ(double delta){
int i=0;
#pragma omp parallel
{
#pragma omp for
for (int i=0; i<N; i++){
q[i] = q[i] + delta*i + 1.0*i/N;
}
}
}
void Chain::calMag_i(){
int i =0;
#pragma omp parallel
{
#pragma omp for
for (i=0; i<N; i++){
mx[i] = cos(q[i]);
my[i] = sin(q[i]);
}
}
}
void Chain::calForce001(){
int i;
int j;
double fij =0.0;
double start_time = omp_get_wtime();
#pragma omp parallel
{
#pragma omp for private(j, fij)
for (i=0; i<N; i++){
force[i] = 0.0;
for (j=0; j<i; j++){
fij = my[i]*mx[j] - mx[i]*my[j];
#pragma omp critical
{
force[i] += fij;
force[j] += -fij;
}
}
}
}
double time = omp_get_wtime() - start_time;
cout <<"time = " << time <<endl;
}
Chain::Chain(int const Np){
这->N=Np;
这->q=新的双精度[Np];
this->mx=新双[Np];
这->我的=新的双[Np];
此->力=新双[Np];
}
void Chain::initCond(){
对于(inti=0;i,有三个原因说明您没有从任何加速中获益
- 您的代码中到处都是
#pragma omp parallel
。这个pragma的作用是启动“线程团队”。在区块结束时,该团队被解散。这相当昂贵。移除这些并使用#pragma omp parallel for
而不是#pragma omp for
将在第一次遭遇时启动团队,并在每个区块后将其置于睡眠状态。这使应用程序比我快4倍
- 您可以使用
#pragma omp critical
。在大多数平台上,这将强制使用互斥锁-这是一种激烈的竞争,因为所有线程都希望同时写入该变量。因此,不要在此处使用critical部分。您可以使用,但在这种情况下,这不会有太大区别-请参阅第三项。删除crit即可ical部分将速度提高了3倍
- 只有当您有实际的工作负载时,并行性才有意义。您的所有代码都太小,无法从并行性中获益。工作负载太小,无法挽回启动/唤醒/销毁线程所损失的时间。如果您的工作负载是这十倍,则一些
parallel for
语句将有意义。但特别是如果您必须进行原子更新,那么allyChain::calForce001()
将永远不值得
关于编程风格:你在C++中编程。请在任何地方使用本地范围变量——例如:代码>链::
,在内部循环中使用本地双fij
。这样就不用编写私有
子句。编译器非常聪明,可以对其进行优化。正确的作用域允许进行更好的优化。有三个原因可以解释为什么您不能从任何加速中获益
- 您的代码中到处都是
。这个pragma的作用是启动“线程团队”。在区块结束时,该团队被解散。这相当昂贵。移除这些并使用#pragma omp parallel
而不是#pragma omp parallel for
将在第一次遭遇时启动团队,并在每个区块后将其置于睡眠状态。这使应用程序比我快4倍#pragma omp for
- 您可以使用
。在大多数平台上,这将强制使用互斥锁-这是一种激烈的竞争,因为所有线程都希望同时写入该变量。因此,不要在此处使用critical部分。您可以使用,但在这种情况下,这不会有太大区别-请参阅第三项。删除crit即可ical部分将速度提高了3倍#pragma omp critical
- 只有当您有实际的工作负载时,并行性才有意义。您的所有代码都太小,无法从并行性中获益。工作负载太小,无法挽回启动/唤醒/销毁线程所损失的时间。如果您的工作负载是这十倍,则一些
语句将有意义。但特别是如果您必须进行原子更新,那么allyparallel for
将永远不值得Chain::calForce001()
关于编程风格:你在C++中编程。请在任何地方使用本地范围变量——例如:代码>链::,在内部循环中使用本地
双fij
。这样可以避免编写私有
子句。编译器足够聪明,可以对其进行优化。正确的作用域允许进行更好的优化。您不显示calForce001,但您可能希望查看此内容并分析您的代码:我显示calForce是最终的方法d在Chain.cpp(有一个滚动条)中,现在我添加了一个函数来计算在#pragma omp parallel之前和之后使用的时间。因此,一次执行的时间如下:有omp的时间是0.0376656,没有pragma(没有omp)时间是0.00196766您可能会看到一些使算法缩放的选项…您不显示calForce001,但您可能希望查看此选项并分析代码:我显示calForce是Chain.cpp中的最终方法(有一个滚动条)现在我添加了一个函数来计算在#pragma omp parallel之前和之后使用的时间。因此,一次执行的时间如下:有omp的时间是0.0376656,没有pragma(没有omp)时间是0.00196766,您可能会看到一些使算法缩放的选项…@alfaceor可能会从OpenMP SIMD矢量化中获得一些不错的加速,如果编译器还没有自动矢量化的话。calForce001
的内部循环看起来可以矢量化,而不需要在矢量内部进行水平操作。它可以ght甚至在没有-ffast math
的情况下自动矢量化,在这种情况下,OpenMP simd pragma可能对-O3
@alfaceor的正常编译器输出没有帮助。如果编译器还没有自动矢量化,calForce001
的内部循环看起来是可矢量化的不需要在向量内进行水平操作。它甚至可能在没有-ffast math
的情况下自动进行向量化,在这种情况下,OpenMP simd pragma可能对-O3
的正常编译器输出没有帮助
Chain::Chain(int const Np){
this->N = Np;
this->q = new double[Np];
this->mx = new double[Np];
this->my = new double[Np];
this->force = new double[Np];
}
void Chain::initCond(){
for (int i=0; i<N; i++){
q[i] = 0.0;
force[i] = 0.0;
}
}
void Chain::changeQ(double delta){
int i=0;
#pragma omp parallel
{
#pragma omp for
for (int i=0; i<N; i++){
q[i] = q[i] + delta*i + 1.0*i/N;
}
}
}
void Chain::calMag_i(){
int i =0;
#pragma omp parallel
{
#pragma omp for
for (i=0; i<N; i++){
mx[i] = cos(q[i]);
my[i] = sin(q[i]);
}
}
}
void Chain::calForce001(){
int i;
int j;
double fij =0.0;
double start_time = omp_get_wtime();
#pragma omp parallel
{
#pragma omp for private(j, fij)
for (i=0; i<N; i++){
force[i] = 0.0;
for (j=0; j<i; j++){
fij = my[i]*mx[j] - mx[i]*my[j];
#pragma omp critical
{
force[i] += fij;
force[j] += -fij;
}
}
}
}
double time = omp_get_wtime() - start_time;
cout <<"time = " << time <<endl;
}