内部的openmp延迟
Posted
技术标签:
【中文标题】内部的openmp延迟【英文标题】:openmp latency for inside for 【发布时间】:2016-03-21 00:30:25 【问题描述】:我有一段代码要并行化,而 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 ch(N);
ch.initCond();
for (int t=0; t<timeSteps; t++)
ch.changeQ(delta*t);
ch.calMag_i();
ch.calForce001();
ch.printSomething();
Chain.h 是
class Chain
public:
int N;
double *q;
double *mx;
double *my;
double *force;
Chain(int const Np);
void initCond();
void changeQ(double delta);
void calMag_i();
void calForce001();
;
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;
所以 changeQ() 和 calMag_i() 方法实际上比串行代码快,但我的问题是 calForce001()。执行时间为:
使用 openMP 3.939s 没有 openMP 0.217s现在,很明显我做错了什么,或者代码无法并行化。请任何有用的帮助。 提前致谢。 卡洛斯
编辑: 为了澄清这个问题,我添加了函数 omp_get_wtime() 来计算函数 calForce001() 的执行时间,并且一次执行的时间是
带 omp :0.0376656 没有 omp:0.00196766所以使用 omp 方法会慢 20 倍。
否则,我还要计算 calMag_i() 方法的时间
带 omp:3.3845e-05 没有 omp:9.9516e-05对于这种方法,omp 快了 3 倍。
我希望这能确认延迟问题出在 calForce001() 方法中。
【问题讨论】:
你没有显示 calForce001,但你可能想看看这个并分析你的代码:***.com/questions/7181078/… 我显示 calForce 是 Chain.cpp 中的最终方法(有一个滚动条) 现在我添加函数来计算使用#pragma omp 并行之前和之后的时间。因此,一次执行的时间如下:有 omp 的时间是 0.0376656,没有编译指示(无 omp)的时间是 0.00196766 也许你可以have a look here 看看你的一些选项来使算法扩展...... 【参考方案1】:您没有从任何加速中受益的三个原因。
您的代码中到处都是#pragma omp parallel
。这个 pragma 的作用是启动“线程团队”。在区块结束时,这个团队被解散。这是相当昂贵的。删除这些并使用#pragma omp parallel for
而不是#pragma omp for
将在第一次遇到时启动团队并在每个块后使其进入睡眠状态。这让我的应用程序速度提高了 4 倍。
你使用#pragma omp critical
。在大多数平台上,这将强制使用互斥锁——这是因为所有线程都想同时写入该变量而引起的激烈争论。所以,不要在这里使用关键部分。您可以使用atomic updates,但在这种情况下,这不会有太大的不同 - 请参阅第三项。仅删除关键部分即可将速度提高 3 倍。
只有当您有实际工作负载时,并行性才有意义。您的所有代码都太小而无法从并行性中受益。工作量太少,无法赢回在启动/唤醒/销毁线程时损失的时间。如果您的工作量是这个的十倍,一些 parallel for
语句将是有意义的。但特别是如果您必须进行原子更新,Chain::calForce001()
将永远不值得。
关于编程风格:您正在使用 C++ 编程。请尽可能使用本地范围变量 - 例如Chain::calForce001()
,在内部循环中使用本地 double fij
。这使您不必编写private
子句。编译器足够聪明,可以优化它。正确的范围界定可以实现更好的优化。
【讨论】:
@alfaceor 可能会从 OpenMP SIMD 矢量化中获得一些不错的加速,如果编译器尚未自动矢量化。calForce001
的内部循环看起来是可向量化的,不需要向量内的水平操作。它甚至可能在没有-ffast-math
的情况下自动矢量化,在这种情况下,与-O3
的普通编译器输出相比,OpenMP simd pragma 可能无济于事以上是关于内部的openmp延迟的主要内容,如果未能解决你的问题,请参考以下文章
使用 SSE 矢量化在 OpenMP 中将内部循环与残差计算并行化