C 开MP点积

C 开MP点积,c,openmp,C,Openmp,我正在OpenMP中实现并行点积 我有以下代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <math.h> #include <omp.h> #define SIZE 1000 int main (int argc, char *argv[]) { float u[SIZE], v[SI

我正在OpenMP中实现并行点积

我有以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <omp.h>
#define SIZE 1000

int main (int argc, char *argv[]) {

  float u[SIZE], v[SIZE], dp,dpp;
  int i, j, tid;

  dp=0.0;
  for(i=0;i<SIZE;i++){
      u[i]=1.0*(i+1);
      v[i]=1.0*(i+2);
  }
  printf("\n values of u and v:\n");

  for (i=0;i<SIZE;i++){
      printf(" u[%d]= %.1f\t v[%d]= %.1f\n",i,u[i],i,v[i]);
  }
  #pragma omp parallel shared(u,v,dp,dpp) private (tid,i)
  {
      tid=omp_get_thread_num();

      #pragma omp for private (i)
      for(i=0;i<SIZE;i++){
          dpp+=u[i]*v[i];
          printf("thread: %d\n", tid);
      }
      #pragma omp critical
      {
          dp=dpp;
          printf("thread %d\n",tid);
      }


  }

  printf("\n dot product is %f\n",dp);

 }
我做错了什么


从我的角度来看,一切看起来都很正常。

首先,一个简单的1000元素点积没有足够的计算成本来证明多线程的合理性——您将在通信和同步成本上付出比您在性能上获得的要多得多的代价,这是不值得的

其次,看起来您正在计算每个线程中的完整点积,而不是将计算划分到多个线程中,并在最后合并结果

下面是一个如何从中进行矢量点积的示例

#包括
主要()
{
inti,n,chunk;
浮点a[100],b[100],结果;
/*一些初始化*/
n=100;
区块=10;
结果=0.0;
对于(i=0;i

基本上,当您有大而昂贵的循环时,OpenMP非常适合进行粗粒度并行。通常,在执行并行编程时,在重新同步之前可以执行的计算“块”越大越好。特别是随着内核数量的增加,通信和同步成本将增加。假设每次同步(获取一个新的索引或索引块以执行,输入一个关键部分等)都需要10毫秒或1百万条指令才能更好地了解何时/何地/如何并行化代码。

首先,一个简单的1000元素点积并没有足够的计算成本来证明多线程的合理性——您将在通信和同步方面付出比您在性能方面获得的更多的成本,这是不值得的

其次,看起来您正在计算每个线程中的完整点积,而不是将计算划分到多个线程中,并在最后合并结果

下面是一个如何从中进行矢量点积的示例

#包括
主要()
{
inti,n,chunk;
浮点a[100],b[100],结果;
/*一些初始化*/
n=100;
区块=10;
结果=0.0;
对于(i=0;i

基本上,当您有大而昂贵的循环时,OpenMP非常适合进行粗粒度并行。通常,在执行并行编程时,在重新同步之前可以执行的计算“块”越大越好。特别是随着内核数量的增加,通信和同步成本将增加。假设每次同步(获取一个新的索引或索引块以执行,输入一个关键部分等)都需要10毫秒或1百万条指令才能更好地了解何时/何地/如何并行化代码。

问题仍然与您最近的问题相同。您正在变量中累积值,必须告诉OpenMp如何进行此操作:

#pragma omp for reduction(+: dpp)
for(size_t i=0; i<SIZE; i++){
  dpp += u[i]*v[i];
}
#pragma omp用于缩减(+:dpp)

对于(size_t i=0;i而言,问题仍然与您最近的问题相同。您正在变量中累积值,您必须告诉OpenMp如何执行此操作:

#pragma omp for reduction(+: dpp)
for(size_t i=0; i<SIZE; i++){
  dpp += u[i]*v[i];
}
#pragma omp用于缩减(+:dpp)

对于(size_t i=0;i您什么意思不对,它编译成功了?调用似乎是
printf
。您看到的消息不是OpenMP信息性消息。您使用了-Mconcur,这意味着您希望编译器自动并行化(或自动并行化)代码。要使用OpenMP,正确的选项是-mp。错误是什么意思,它编译成功了?调用似乎是
printf
。您看到的消息不是OpenMP信息性消息。您使用了-Mconcur,这意味着您希望编译器自动并行化(或自动并行化)代码。要使用OpenMP,正确的选项是-mp。您不必使用循环局部变量。它可以在for指令的一个子句中声明为private,或者就此而言,如果workshare for循环为规范格式,则默认情况下循环索引将为private。此外,除非您使用的是OpenMP V3.0,否则不能将大小变量用作循环索引。@ejd,我没有说“他必须”。我给出的表单只是最简单的表单,简洁易读。如果他不能使用
size\t
,编译器会告诉他,但这是C的语义正确的索引类型。虽然我不知道pgcc编译器,但大多数编译器在谈到工作共享的规范形式时都不会给出很好的错误消息OpenMP的r。用户很有可能看到的只是一条消息,说明循环的初始化、条件和增量有问题-让用户自行决定循环迭代变量不能无符号。您不必使用循环局部变量。它可以在fo上的一个子句中声明为privater指令,或者如果循环的工作共享为规范形式,则默认情况下循环索引将是私有的。此外,除非使用OpenMP V3.0,否则不能使用大小变量作为循环索引。@ejd,我没有说“他必须”。我给出的表单只是最简单的表单,简洁易读。如果他不能使用
size\t
,编译器会告诉他,但这是C的语义正确的索引类型。虽然我不知道pgcc编译器,但大多数编译器在谈到工作共享的规范形式时都不会给出很好的错误消息OpenMP的r。很有可能所有用户都会看到