[英]How to resolve Loop carried dependency preventing loop vectorization while using -fast in PGI compiler in OpenACC
我想使用 C 语言中的 OpenACC 并行化基于粒子方法的流体流动代码。 我对 OpenACC 还是很陌生,并试图在目前将其应用于多核计算机上的代码的同时了解其基础知识。 稍后,我将尝试将其卸载到 GPU。 我在代码中的 for 循环中添加了一些 #pragmas。 在一部分代码中,当我在没有 -fast 的情况下编译代码时,它编译没有任何问题,但仅并行化了外循环,但是,当我在编译代码期间包含 -fast 时,它给了我一些数据依赖消息和内循环( s) 未并行化。 在阅读了可用的文献后,我尝试了很多东西,包括使用限制指针声明以及使用原子和例程语句等,但到目前为止似乎没有任何效果。 部分代码的删节版在这里:
// 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]++;
}
编辑:
我在下面添加了一个伪代码,它与我的问题非常相似,以详细说明问题:
//This pseudo code intends to find the contiguous states from a given list for each state of US
count=0;
//state[] is a list of all the states of US
#pragma acc paralel loop gang
for(i=0;i<no_of_states_in_US;i++)
{
iState=state[i];
#pragma acc loop vector
for (j = 0; j < no_of_states_to_check_from_for[iState]; j++){ //no_of_states_to_check_from_for[iState] may be 5
jState = names_of_states_to_check_for_iState[j]; // for KS the given states to check from may be CO, NE, CA, UT and OK
// some logic to check whether jState is contiguous to iState
if(jState is_NOT_adjacent_to_iState) continue;
//race condition occurs below if inner loop is vectorized, but no race condition if outer loop is parallelized only
// Any suggestions / work around to vectorize the inner loop here and to avoid race condition would be helpful
contiguous_state[iState][count]=jState;
#pragma acc atomic //?? does not seem to work
count++;
}
}
我对向量化内循环很感兴趣,因为这部分代码属于计算密集型部分,并且在代码中重复了几次。 我在 Windows 10 上使用 PGI 19.4 社区版。请求这方面的帮助。 提前致谢。
请注意,这不是 OpenACC 问题,而是编译器只是告诉您,由于对particle.numberOfNeighborParticles 和particle.neighborTable 的潜在循环依赖性,它无法对循环进行矢量化(矢量化通过-fast 或-O2 启用)。 这不应影响您的结果或循环的 OpenACC 并行化,您只是无法获得矢量化的额外性能优势。
您可以尝试在向编译器断言没有指针别名的位置添加标志“-Msafeptr”,这通常会导致这些类型的问题。 需要注意的是,如果您确实有别名,则代码可能会得到不正确的结果。
对于第二个编辑过的问题,只要更新计数的顺序无关紧要,那么您就可以改用原子捕获。 这会将计数的值捕获到局部变量中,因此您无需担心它会发生变化。 就像是:
int cnt;
#pragma acc atomic capture
{
cnt = count;
count++;
}
contiguous_state[iState][cnt]=jState;
如果计数的顺序很重要,则循环不可并行化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.