您好我正在尝试使用openMP来计算此代码的计算。用有限差分implicite方法计算流体动力学涡度。我正在使用Alternating direction隐式方法来执行此操作。
我想加快执行速度。 (这里Nx = Ny = 100)
问题在于,以这种方式使用openMp可以减慢代码速度,而不是加快速度。我试图指定共享变量,但这没有多大帮助。 有什么想法吗?
一切顺利
void ADI(double vort[][Ny], double psi[][Ny], double n[][Ny],
double cls[][Ny],double AAx[], double BBx[], double CCx[], double DDx[],
double AAy[], double BBy[], double CCy[], double DDy[],
double cx[][Ny], double cy[][Ny], double epsx[][Ny], double epsy[][Ny],
double vortx[], double vorty[Ny-2], double dx, double Dxs, double coefMass,
double coefMasCls)
{
////////////calcul sur y////////////
//calcul coef ADI
int i=0, j=0;
#pragma omp parallel for private(Dxs,i) shared(psi,vort)
for (i=0; i<Nx; i++) //Boundary condition sur x
{
vort[i][0]=(psi[i][0]-psi[i][1])*2/Dxs;
vort[i][Ny-1] = (psi[i][Ny-1]-psi[i][Ny-2])*2/Dxs;
}
#pragma omp parallel for private(Dxs,j) shared(psi,vort)
for (j=0; j<Ny; j++) //Boundary condition
{
vort[0][j] = (psi[0][j]-psi[1][j])*2/Dxs;
vort[Nx-1][j] = (psi[Nx-1][j]-psi[Nx-2][j])*2/Dxs;
}
for (j=1; j<Ny-1; j++) //interior points
{
#pragma omp parallel for private(coefMasCls,coefMasCls,i) shared(psi,vort,n,cls)
for (i=1; i<Nx-1; i++) //interior points
{
vort[i][j] = vort[i][j] - coefMass * (n[i+1][j]-n[i-1][j])- coefMasCls * (cls[i+1][j]-cls[i-1][j]);;
}
//i=0;
//vort[i][j] = vort[i][j] + coefMass*(n[1][j]-n[1][j]);
//i=Nx-1;
//vort[i][j] = vort[i][j] + coefMass*(n[Nx-2][j]-n[Nx-2][j]);
}
for (i=1; i<Nx-1; i++) //interior points
{
for (j=1; j<Ny-1; j++) //interior points
{
AAy[j] = -.5 * ( .5 * (1 + epsy[i][j]) * cy[i][j-1] + dx);
BBy[j] = 1 + dx + .5 * epsy[i][j] * cy[i][j];
CCy[j] = .5 * ( .5 * ( 1 - epsy[i][j] ) * cy[i][j+1] - dx);
DDy[j] = .5 * (.5 * ( 1 + epsx[i][j] ) * cx[i-1][j] + dx ) * vort[i-1][j]
+ ( 1 - dx - .5 * epsx[i][j] * cx[i][j] ) * vort[i][j]
+ .5 * (- .5 * ( 1 - epsx[i][j] ) * cx[i+1][j] + dx ) * vort[i+1][j];
vorty[j] = vort[i][j];
}
DDy[1]=DDy[1] - AAy[1] * vort[i][0]; //the AA[0] are not taken into account in the tridiag methode. Include it in the second hand
DDy[Ny-2]=DDy[Ny-2] - CCy[Ny-2]* vort[i][Ny-1]; //moving boundary condition
//DDy[Ny-3]= DDy[Ny-3]; //vorticity nul on the free slip boundary condition
tridiag(AAy, BBy, CCy, DDy, vorty, Ny-1); //ne calcul pas le point en 0 et en Ny-1
for (j=1; j<Ny-1; j++)
{
vort[i][j]=vorty[j];
}
}
////////////calcul sur x //////////
//calcul coef ADI
for (j=1; j<Ny-1; j++)
{
for (i=1; i<Nx-1; i++)
{
AAx[i] = -.5* ( .5 * ( 1 + epsx[i][j] ) * cx[i-1][j] + dx );
BBx[i] = 1 + dx + .5 * epsx[i][j] * cx[i][j];
CCx[i] = .5 * ( .5 * ( 1 - epsx[i][j] ) * cx[i+1][j] - dx) ;
DDx[i]= .5 * ( .5 * ( 1 + epsy[i][j] ) * cy[i][j-1] + dx ) * vort[i][j-1]
+ ( 1 - dx - .5 * epsy[i][j] * cy[i][j] ) * vort[i][j]
+ .5 * (-.5 * ( 1 - epsy[i][j] ) * cy[i][j+1] + dx ) * vort[i][j+1];
vortx[i]=vort[i][j];
}
DDx[1] = DDx[1] - AAx[1]* vort[0][j];
DDx[Nx-2] = DDx[Nx-2] - CCx[Nx-2] * vort[Nx-1][j];
tridiag(AAx, BBx, CCx, DDx, vortx, Nx-1); //ne calcul pas le point en 0 et en Nx-1
for (i=1; i<Nx-1; i++)
{
vort[i][j]=vortx[i];
}
}
}
答案 0 :(得分:0)
首先要做的是确定哪个循环并行化具有最严重的影响,但最后一个循环看起来非常像您将遇到缓存抖动。稍微简化结构:
double vort[Nx][Ny];
// ...
for (int j=1; j<Ny-1; ++j) {
#pragma omp parallel for
for (int i=1; i<Nx-1; ++i) {
vort[i][j] -= f(i, j);
}
}
任何给定的线程将依次读取和更新vort中的值,在偏移量j + k * Ny,j +(k + 1)* Ny,j +(k + 2)* Ny等取决于for的方式循环遍历线程。这些访问中的每一个都将引入缓存行的数据以更新8个字节。当外部循环再次启动时,您刚刚访问的数据可能仍然不在缓存中。
在所有条件相同的情况下,如果你可以安排你的数组访问,以便你朝着最小步幅的方向移动(对于C数组,这是最后一个索引),你的缓存行为会好得多。对于尺寸为100的尺寸,阵列可能不会那么大,这会产生巨大的差异。对于例如Nx,Ny = 1000,以“错误的方式”访问阵列可能是毁灭性的。
这会使串行代码的性能更差,但我认为添加线程会使情况变得更糟。
总而言之,在每个内环中完成的计算量非常小;无论如何,你很可能会受到内存带宽的限制。
<强>附录强>
为了明确,'正确'的循环访问看起来像:
for (int i=1; i<Nx-1; ++i) {
for (int j=1; j<Ny-1; ++j) {
vort[i][j] -= f(i, j);
}
}
要并行化,您可以允许编译器使用collapse
指令更好地跨线程分块数据:
#pragma omp parallel for collapse(2)
for (int i=1; i<Nx-1; ++i) {
for (int j=1; j<Ny-1; ++j) {
vort[i][j] -= f(i, j);
}
}
最后,为了避免错误共享(线程踩在彼此的缓存行上),最好确保数组的两个相邻行不共享同一缓存行中的数据。可以确保每行与内存中缓存行大小的倍数对齐,或者更简单地只是在每行的末尾添加填充。
double vort[Nx][Ny+8]; // 8 doubles ~ 64 bytes
(假设一个64字节的缓存行,这应该足够了。)