如何解决OpenACC中PGI编译器中使用-fast时阻止循环矢量化的循环携带依赖
我想用C语言中的OpenACC并行化一个基于粒子方法的流体流代码。我是OpenACC的新手,目前正在将其应用到多核计算机上的代码中,并试图理解其基础知识。稍后,我将尝试将其卸载到GPU。我在代码中的for循环中添加了一些#pragma。在部分代码中,当我编译没有-fast的代码时,它编译没有任何问题,但只并行化外部循环,然而,当我在编译代码时包含-fast时,它会给我一些数据依赖性消息,而内部循环不会并行化。在阅读了现有的文献之后,我尝试了很多事情,包括使用带有指针声明的restrict,以及使用原子和例程语句等,但到目前为止似乎没有任何效果。守则部分的摘要如下:如何解决OpenACC中PGI编译器中使用-fast时阻止循环矢量化的循环携带依赖,c,for-loop,openacc,pgi,C,For Loop,Openacc,Pgi,我想用C语言中的OpenACC并行化一个基于粒子方法的流体流代码。我是OpenACC的新手,目前正在将其应用到多核计算机上的代码中,并试图理解其基础知识。稍后,我将尝试将其卸载到GPU。我在代码中的for循环中添加了一些#pragma。在部分代码中,当我编译没有-fast的代码时,它编译没有任何问题,但只并行化外部循环,然而,当我在编译代码时包含-fast时,它会给我一些数据依赖性消息,而内部循环不会并行化。在阅读了现有的文献之后,我尝试了很多事情,包括使用带有指针声明的restrict,以及使
// the code intends to compute the total number of neighbour particles of "iParticle" in
// particle.numberOfNeighborParticles[iParticle] and saves the list of these neighbour particles in
// particle.neighborTable[iParticle][Neigh]
int iX, iY;
#pragma acc parallel loop private(iX, iY) //line 98
for (iParticle = 0; iParticle < particle.totalNumber; iParticle++)
{
BUCKET_findBucketWhereParticleIsStored(&iX, &iY, iParticle, position);
#pragma acc loop seq // line 133
for (jX = iX - 1; jX <= iX + 1; jX++)
{
.....
#pragma acc loop seq // line 179
for (jY = iY - 1; jY <= iY + 1; jY++)
{
......
#pragma acc loop // line 186
for (iStoredParticle = 0; iStoredParticle < domain.bucket[jX][jY].count; iStoredParticle++)
{
jParticle = domain.bucket[jX][jY].list[iStoredParticle];
xij = (position[XDIM][jParticle] - position[XDIM][iParticle]);
distanceIJ_squared = xij * xij;
yij = (position[YDIM][jParticle] - position[YDIM][iParticle]);
distanceIJ_squared += yij * yij;
if (distanceIJ_squared > parameter.maxRadius_squared)
continue;
NEIGH_addParticleInNeighborTable(iParticle, jParticle, particle.numberOfNeighborParticles, particle.neighborTable);
}
}
}
}
//The *NEIGH_addParticleInNeighborTable()* function is as under:
void
NEIGH_addParticleInNeighborTable(
int iParticle
,int jParticle
,int *restrict numberOfNeighborParticles
,int **restrict neighborTable
){
int iNeigh;
iNeigh = numberOfNeighborParticles[iParticle];
neighborTable[iParticle][iNeigh] = jParticle;
#pragma acc atomic
numberOfNeighborParticles[iParticle]++;
}
//该代码打算计算中“iParticle”的相邻粒子总数
//particle.numberOfNeighborParticles[iParticle]并将这些相邻粒子的列表保存在中
//particle.neightable[iParticle][Neigh]
int iX,iY;
#pragma acc并行环路专用(iX,iY)//第98行
对于(iParticle=0;iParticle 对于(jX=iX-1;jX请注意,这不是OpenACC的问题,编译器只是告诉您它无法对循环进行矢量化(矢量化是通过-fast或-O2启用的)由于潜在的循环依赖于particle.numberOfNeighborParticles和particle.neighborTable。这不会影响您的结果,也不会影响循环的OpenACC并行化,您将无法获得矢量化带来的额外性能好处
您可以尝试添加标志“-Msafeptr”您向编译器声明没有指针别名,这通常会导致这些类型的问题。警告是,如果您有别名,代码可能会得到不正确的结果。对于第二个已编辑的问题,只要更新计数的顺序无关紧要,就可以使用原子捕获instead。这将把count的值捕获到一个局部变量中,这样您就不必担心它的变化。例如:
int cnt;
#pragma acc atomic capture
{
cnt = count;
count++;
}
contiguous_state[iState][cnt]=jState;
如果计数顺序确实重要,则循环不可并行。感谢您的宝贵见解和建议。NEIGH_addParticleInNeighborTable()函数中似乎存在竞争条件,这会在内部循环的矢量化中产生问题。NumberOfNeigorParticles[iParticle]的初始值对于所有导致争用条件的“向量线程”都将为零。OpenACC中是否有任何函数可用于获取内环的“向量线程”的数字ID,该ID可用于初始化iNeigh变量?OpenACC标准没有“线程ID”,主要是因为枚举取决于目标设备。We(PGI)提供扩展名“uu pgi_vectoridx”来获取向量id,但是如果我们忽略“vector”而只在目标多核时使用“gang”,那么它在这里就没有多大用处了。此外,它返回一个gang中的向量id,而不是枚举的全局向量id。要获取该扩展名,需要使用“id=(u pgi_gangidx()*num_gangs)+u pgi_vectoridx()”“num_gangs”将是一个用户变量,也用于通过“num_gangs”来固定帮派数量“子句。我不想在这里使用它。虽然我不知道您是代码,但从您描述的情况来看,这种竞争条件是否会阻止外循环的并行化?@Mat Colgrove很抱歉,我之前添加的代码非常复杂。现在我编辑了这个问题,并添加了一个伪代码(有点)详细阐述这个问题。希望它能澄清外环没有种族条件,并解释手头的问题。请您提出解决这个问题的建议/意见。谢谢
int cnt;
#pragma acc atomic capture
{
cnt = count;
count++;
}
contiguous_state[iState][cnt]=jState;