Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 用于内部的openmp延迟_C++_Performance_Parallel Processing_Openmp - Fatal编程技术网

C++ 用于内部的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

我有一段代码要并行化,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.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
    语句将有意义。但特别是如果您必须进行原子更新,那么ally
    Chain::calForce001()
    将永远不值得

关于编程风格:你在C++中编程。请在任何地方使用本地范围变量——例如:代码>链::
,在内部循环中使用本地
双fij
。这样就不用编写
私有
子句。编译器非常聪明,可以对其进行优化。正确的作用域允许进行更好的优化。

有三个原因可以解释为什么您不能从任何加速中获益

  • 您的代码中到处都是
    #pragma omp parallel
    。这个pragma的作用是启动“线程团队”。在区块结束时,该团队被解散。这相当昂贵。移除这些并使用
    #pragma omp parallel for
    而不是
    #pragma omp for
    将在第一次遭遇时启动团队,并在每个区块后将其置于睡眠状态。这使应用程序比我快4倍
  • 您可以使用
    #pragma omp critical
    。在大多数平台上,这将强制使用互斥锁-这是一种激烈的竞争,因为所有线程都希望同时写入该变量。因此,不要在此处使用critical部分。您可以使用,但在这种情况下,这不会有太大区别-请参阅第三项。删除crit即可ical部分将速度提高了3倍
  • 只有当您有实际的工作负载时,并行性才有意义。您的所有代码都太小,无法从并行性中获益。工作负载太小,无法挽回启动/唤醒/销毁线程所损失的时间。如果您的工作负载是这十倍,则一些
    parallel for
    语句将有意义。但特别是如果您必须进行原子更新,那么ally
    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;
}