为什么我的OpenMP C++代码比串行代码慢?
我写了一段代码来解一个非常简单的二维拉普拉斯方程。尝试比较串行代码和OpenMP代码 我试着用 g++tmp.cpp-fopenmp 得到了非常奇怪的结果 输出: 串行时间=1.620000 Omp时间=9.820000为什么我的OpenMP C++代码比串行代码慢?,c++,openmp,C++,Openmp,我写了一段代码来解一个非常简单的二维拉普拉斯方程。尝试比较串行代码和OpenMP代码 我试着用 g++tmp.cpp-fopenmp 得到了非常奇怪的结果 输出: 串行时间=1.620000 Omp时间=9.820000 有没有人可以帮我找出这背后的原因以及如何更正OpenMP代码。我遇到了有趣的结果 #include <iostream> #include <iomanip> #include <fstream> #include <sstream&
有没有人可以帮我找出这背后的原因以及如何更正OpenMP代码。我遇到了有趣的结果
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
using namespace std;
void output(float a[], float X[], float Y[], int I, int J)
{
ofstream ft;
int i;
ft.open("flow.dat");
ft<<"variables=\"x\",\"y\",\"a\""<<"\n"
<<"zone f=point"<<"\n"
<<"I="<<I<<",J="<<J<<"\n"
<<endl;
for(int i=0;i<I*J;i++)
{
ft<<setiosflags(ios::scientific)
<<X[i]<<" "<<Y[i]<<" "<<a[i]<<endl;
}
ft.close();
}
void set(float a[], float X[], float Y[], int I, int J, float hx, float hy)
{
for(int j=0;j<J;j++)
for(int i=0;i<I;i++)
{
int iC=j*I+i;
X[iC]=i*hx;
Y[iC]=j*hy;
a[iC]=0.0;
if(j==J-1) a[iC]=1.0;
}
}
void difference_serial(float a[], int I, int J, const float hx, const float hy)
{
const float aC=(hx*hx+hy*hy)*2;
const float aX=hy*hy;
const float aY=hx*hx;
for(int j=1;j<J-1;j++)
for(int i=1;i<I-1;i++)
{
int iC=j*I+i;
int iL=iC-1;
int iR=iC+1;
int iU=iC+I;
int iD=iC-I;
a[iC]=(aX*(a[iL]+a[iR])+aY*(a[iU]+a[iD]))/aC;
}
}
void difference_omp(float a[], int I, int J, const float hx, const float hy)
{
const float aC=(hx*hx+hy*hy)*2;
const float aX=hy*hy;
const float aY=hx*hx;
int i,j,iC,iL,iR,iU,iD;
#pragma omp parallel for private(i,j,iC,iL,iR,iU,iD) shared(a,I,J) schedule(dynamic)
for( j=1;j<J-1;j++)
for( i=1;i<I-1;i++)
{
iC=j*I+i;
iL=iC-1;
iR=iC+1;
iU=iC+I;
iD=iC-I;
a[iC]=(aX*(a[iL]+a[iR])+aY*(a[iU]+a[iD]))/aC;
}
}
int main()
{
const int I=129;
const int J=129;
const int N=I*J;
const float hx=1.0/(I-1);
const float hy=1.0/(J-1);
float *a=new float[N];
float *X=new float[N];
float *Y=new float[N];
//set the grid and flow
set(a,X,Y,I,J,hx,hy);
//iteation
clock_t start=clock();
for(int it=0;it<10000;it++)
difference_serial(a,I,J,hx,hy);
clock_t end=clock();
printf("Serial time=%f\n",(float)(end-start)/CLOCKS_PER_SEC);
set(a,X,Y,I,J,hx,hy);
clock_t start2=clock();
for(int it2=0;it2<10000;it2++)
difference_omp(a,I,J,hx,hy);
clock_t end2=clock();
printf("Omp time=%f\n",(float)(end2-start2)/CLOCKS_PER_SEC);
//output
output(a,X,Y,I,J);
//free memory
delete[] a;
delete[] X;
delete[] Y;
}
因此,使用O3时,OpenMP的时间缩短,而串行版本的时间缩短。我的猜测是,问题实例太小了,调用并行区域的实际开销就体现在这里
您正在尝试在PC上并行化需要1.5s/10k=0.15毫秒的时间。初始化线程池和调度有其开销,尤其是scheduledynamic
我会尝试做一些测试来确认。不确定随机碰撞I和J是否合法
测试后:
正常,I开关J=I=10240;并设置为int it=0;我遇到了有趣的结果
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
using namespace std;
void output(float a[], float X[], float Y[], int I, int J)
{
ofstream ft;
int i;
ft.open("flow.dat");
ft<<"variables=\"x\",\"y\",\"a\""<<"\n"
<<"zone f=point"<<"\n"
<<"I="<<I<<",J="<<J<<"\n"
<<endl;
for(int i=0;i<I*J;i++)
{
ft<<setiosflags(ios::scientific)
<<X[i]<<" "<<Y[i]<<" "<<a[i]<<endl;
}
ft.close();
}
void set(float a[], float X[], float Y[], int I, int J, float hx, float hy)
{
for(int j=0;j<J;j++)
for(int i=0;i<I;i++)
{
int iC=j*I+i;
X[iC]=i*hx;
Y[iC]=j*hy;
a[iC]=0.0;
if(j==J-1) a[iC]=1.0;
}
}
void difference_serial(float a[], int I, int J, const float hx, const float hy)
{
const float aC=(hx*hx+hy*hy)*2;
const float aX=hy*hy;
const float aY=hx*hx;
for(int j=1;j<J-1;j++)
for(int i=1;i<I-1;i++)
{
int iC=j*I+i;
int iL=iC-1;
int iR=iC+1;
int iU=iC+I;
int iD=iC-I;
a[iC]=(aX*(a[iL]+a[iR])+aY*(a[iU]+a[iD]))/aC;
}
}
void difference_omp(float a[], int I, int J, const float hx, const float hy)
{
const float aC=(hx*hx+hy*hy)*2;
const float aX=hy*hy;
const float aY=hx*hx;
int i,j,iC,iL,iR,iU,iD;
#pragma omp parallel for private(i,j,iC,iL,iR,iU,iD) shared(a,I,J) schedule(dynamic)
for( j=1;j<J-1;j++)
for( i=1;i<I-1;i++)
{
iC=j*I+i;
iL=iC-1;
iR=iC+1;
iU=iC+I;
iD=iC-I;
a[iC]=(aX*(a[iL]+a[iR])+aY*(a[iU]+a[iD]))/aC;
}
}
int main()
{
const int I=129;
const int J=129;
const int N=I*J;
const float hx=1.0/(I-1);
const float hy=1.0/(J-1);
float *a=new float[N];
float *X=new float[N];
float *Y=new float[N];
//set the grid and flow
set(a,X,Y,I,J,hx,hy);
//iteation
clock_t start=clock();
for(int it=0;it<10000;it++)
difference_serial(a,I,J,hx,hy);
clock_t end=clock();
printf("Serial time=%f\n",(float)(end-start)/CLOCKS_PER_SEC);
set(a,X,Y,I,J,hx,hy);
clock_t start2=clock();
for(int it2=0;it2<10000;it2++)
difference_omp(a,I,J,hx,hy);
clock_t end2=clock();
printf("Omp time=%f\n",(float)(end2-start2)/CLOCKS_PER_SEC);
//output
output(a,X,Y,I,J);
//free memory
delete[] a;
delete[] X;
delete[] Y;
}
因此,使用O3时,OpenMP的时间缩短,而串行版本的时间缩短。我的猜测是,问题实例太小了,调用并行区域的实际开销就体现在这里
您正在尝试在PC上并行化需要1.5s/10k=0.15毫秒的时间。初始化线程池和调度有其开销,尤其是scheduledynamic
我会尝试做一些测试来确认。不确定随机碰撞I和J是否合法
测试后:
正常,I开关J=I=10240;并设置为int it=0;你是在测量CPU时间,而不是挂钟时间这是一个问题,但不是原来的问题。我将代码和时间测量值更改为omp_get_____________________________________________________。我将代码和时间测量值更改为omp_get_,但我的电脑仍然显示omp时间13s和串行3s。我猜这是并行区域的安装开销。+1-“您的示例问题太小,OpenMP无法发挥效率”。这是大约90%的“多线程版本较慢”帖子的答案。虽然并行性很低,但它的可伸缩性很好。它也可能是错误的代码,以及代码中的冗余内容。我在这件事上也很迟钝。顺便说一句,在我自己执行了10k循环之后,我看到了10k循环。10kx10k已经接近大小溢出。这段代码的问题是,即使是大型实例也需要几秒钟才能执行。输出比50倍的计算时间长100倍。问题是一个人是否应该把时间放在第一位,把它并行化。你不能并行化需要1s才能执行的东西。顺便说一句,想象一下这里的MPI=+1-“您的示例问题太小,OpenMP无法发挥作用”。这是大约90%的“多线程版本较慢”帖子的答案。虽然并行性很低,但它的可伸缩性很好。它也可能是错误的代码,以及代码中的冗余内容。我在这件事上也很迟钝。顺便说一句,在我自己执行了10k循环之后,我看到了10k循环。10kx10k已经接近大小溢出。这段代码的问题是,即使是大型实例也需要几秒钟才能执行。输出比50倍的计算时间长100倍。问题是一个人是否应该把时间放在第一位,把它并行化。你不能并行化需要1s才能执行的东西。顺便说一句,想象一下这里的MPI=
Serial time=58.982189
Omp time=9.158118
luk32:~/projects/tests$ diff laplace.orig.cpp laplace.cpp
88,89c88,89
< const int I=129;
< const int J=129;
---
> const int I=10000;
> const int J=10000;
102,103c102,103
< clock_t start=clock();
< for(int it=0;it<10000;it++)
---
> double start=omp_get_wtime();
> for(int it=0;it<50;it++)
105,106c105,106
< clock_t end=clock();
< printf("Serial time=%f\n",(float)(end-start)/CLOCKS_PER_SEC);
---
> double end=omp_get_wtime();
> printf("Serial time=%f\n",(float)(end-start));
110,111c110,111
< clock_t start2=clock();
< for(int it2=0;it2<10000;it2++)
---
> double start2=omp_get_wtime();
> for(int it2=0;it2<50;it2++)
113,114c113,114
< clock_t end2=clock();
< printf("Omp time=%f\n",(float)(end2-start2)/CLOCKS_PER_SEC);
---
> double end2=omp_get_wtime();
> printf("Omp time=%f\n",(float)(end2-start2));