Я новичок в cuda, и я пытаюсь реализовать Ядро для расчета энергии моего Метрополиса Монте-Карло.
Я положу здесь линейную версию этой функции:
float calc_energy(struct frame frm, float L, float rc){
int i,j;
float E=0, rij, dx, dy, dz;
for(i=0; i<frm.natm; i++)
{
for(j=i+1; j<frm.natm; j++)
{
dx = fabs(frm.conf[j][0] - frm.conf[i][0]);
dy = fabs(frm.conf[j][1] - frm.conf[i][1]);
dz = fabs(frm.conf[j][2] - frm.conf[i][2]);
dx = dx - round(dx/L)*L;
dy = dy - round(dy/L)*L;
dz = dz - round(dz/L)*L;
/*rij*/
rij = sqrt(dx*dx + dy*dy + dz*dz);
if (rij <= rc)
{
E = E + (4*((1/pow(rij,12))-(1/pow(rij,6))));
}
}
}
return E;
Затем я попытаюсь распараллелить это с помощью Cuda: Это моя идея:
void calc_energy(frame* s, float L, float rc)
{
extern __shared__ float E;
int i = blockDim.x*blockIdx.x + threadIdx.x;
int j = blockDim.y*blockIdx.y + threadIdx.y;
float rij, dx, dy, dz;
dx = fabs(s->conf[j][0] - s->conf[i][0]);
dy = fabs(s->conf[j][1] - s->conf[i][1]);
dz = fabs(s->conf[j][2] - s->conf[i][2]);
dx = dx - round(dx/L)*L;
dy = dy - round(dy/L)*L;
dz = dz - round(dz/L)*L;
rij = sqrt(dx*dx + dy*dy + dz*dz);
if (rij <= rc)
{
E += (4*((1/pow(rij,12))-(1/pow(rij,6)))); //<- here is the big problem
}
}
Мой главный вопрос - как суммировать переменную E из каждого потока и возвращать ее хосту?Я намереваюсь использовать как можно больше потоков и блоков.
Очевидно, что при вычислении переменной E часть кода отсутствует.
Я прочитал несколько вещей о методах сокращения, ноЯ хотел бы знать, если это необходимо здесь.
Я вызываю ядро, используя следующий код:
calc_energy<<<dimGrid,dimBlock>>>(d_state, 100, 5);
edit :
Я понял, что мне нужно использовать методы сокращения. CUB отлично работает для меня.
Продолжая реализацию кода, я понял, что у меня возникла новая проблема, возможно, из-за недостатка знаний в этой области.
В моем вложенном цикле переменная (frm.natm
) может достигать значений порядка 10 ^ 5.думая о моем графическом процессоре (GTX 750ti), число потоков на блок равно 1024, а количество блоков на сетку - 1024. Если я правильно понял, максимальное количество запусков в ядре равно 1024x1024 = 1048576 (меньше, чем на самом деле).
Так что, если мне нужно выполнить 10 ^ 5 x 10 ^ 5 = 10 ^ 10 вычислений в моем вложенном цикле, что будет лучшим способом придумать алгоритм?Выберите фиксированное число (которое подходит для моего графического процессора) и разделите вычисления, было бы хорошей идеей?