Soy absolutamente novato en programación OpenCL. Para mi aplicación (simulaton molecular) Escribí un kernel para calcular el potencial intermolecular del líquido de lennard-jones. En este núcleo que necesito para calcular el valor acumulativo del potencial de todas las partículas con una:OpenCL - suma incremental durante el cálculo
__kernel void Molsim(__global const float* inmatrix, __global float* fi, const int c, const float r1, const float r2, const float r3, const float rc, const float epsilon, const float sigma, const float h1, const float h23)
{
float fi0;
float fi1;
float d;
unsigned int i = get_global_id(0); //number of particles (typically 2000)
if(c!=i) {
// potential before particle movement
d=sqrt(pow((0.5*h1-fabs(0.5*h1-fabs(inmatrix[c*3]-inmatrix[i*3]))),2.0)+pow((0.5*h23-fabs(0.5*h23-fabs(inmatrix[c*3+1]-inmatrix[i*3+1]))),2.0)+pow((0.5*h23-fabs(0.5*h23-fabs(inmatrix[c*3+2]-inmatrix[i*3+2]))),2.0));
if(d<rc) {
fi0=4.0*epsilon*(pow(sigma/d,12.0)-pow(sigma/d,6.0));
}
else {
fi0=0;
}
// potential after particle movement
d=sqrt(pow((0.5*h1-fabs(0.5*h1-fabs(r1-inmatrix[i*3]))),2.0)+pow((0.5*h23-fabs(0.5*h23-fabs(r2-inmatrix[i*3+1]))),2.0)+pow((0.5*h23-fabs(0.5*h23-fabs(r3-inmatrix[i*3+2]))),2.0));
if(d<rc) {
fi1=4.0*epsilon*(pow(sigma/d,12.0)-pow(sigma/d,6.0));
}
else {
fi1=0;
}
// cumulative difference of potentials
// fi[0]+=fi1-fi0; changed to full size vector
fi[get_global_id(0)]=fi1-fi0;
}
}
Mi problema está en la línea de: fi [0] + = fi1-fi0 ;. En el vector de un elemento fi [0] hay resultados incorrectos. Leí algo sobre la reducción de suma, pero no sé cómo hacerlo durante el cálculo.
¿Existe alguna solución simple a mi problema?
Aviso: He intentado añadir al lado del núcleo para la suma de las componentes del vector (véase el código de abajo), pero no hubo una desaceleración aún mayor que cuando suma vectorial utilizando la CPU.
__kernel void Arrsum(__global const float* inmatrix, __global float* outsum, const int inmatrixsize, __local float* resultScratch)
{
// načtení indexu
int gid = get_global_id(0);
int wid = get_local_id(0);
int wsize = get_local_size(0);
int grid = get_group_id(0);
int grcount = get_num_groups(0);
int i;
int workAmount = inmatrixsize/grcount;
int startOffest = workAmount * grid + wid;
int maxOffest = workAmount * (grid + 1);
if(maxOffest > inmatrixsize){
maxOffest = inmatrixsize;
}
resultScratch[wid] = 0.0;
for(i=startOffest;i<maxOffest;i+=wsize){
resultScratch[wid] += inmatrix[i];
}
barrier(CLK_LOCAL_MEM_FENCE);
if(gid == 0){
for(i=1;i<wsize;i++){
resultScratch[0] += resultScratch[i];
}
outsum[grid] = resultScratch[0];
}
}
Necesita reducción de suma aquí, probablemente; de lo contrario, es una suma atómica o de serie que va a apestar para las GPU. Es un poco difícil de comprender, pero es relativamente fácil de implementar (especialmente si la cantidad de elementos a sumar es una potencia de dos). – Thomas
Considere almacenar en caché en la memoria privada los valores de 'inmatrix [i * 3 + 0/1/2]', ya que lo usa más de una vez. Para la suma, solo usa un algoritmo de reducción. Eso hará el trabajo (como ya fue respondido por otros) – DarkZeros