内部的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延迟的主要内容,如果未能解决你的问题,请参考以下文章

openMP 嵌套并行 for 循环与内部并行 for

OpenMP 性能影响:私有指令与在构造内部声明变量

使用 SSE 矢量化在 OpenMP 中将内部循环与残差计算并行化

在 OpenMP 中并行化嵌套循环并使用更多线程执行内部循环

从内部重新排队或评估延迟的工作?

如何在延迟着色中从灯光几何图形的内部绘制