对CUDA内核中所有线程的变量求和并将其返回给Host

时间:2018-05-28 22:55:09

标签: cuda gpu-programming

我是cuda的新人,我试图实现一个内核来计算我的Metropolis Monte Carlo Simulation的能量。

我会把这个函数的线性版本放在这里:

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);

修改

我明白我需要使用还原方法。 CUB对我很有用。

继续执行代码,我意识到我有一个新问题,可能是因为我在这方面缺乏知识。

在我的嵌套循环中,变量(frm.natm)可以达到10 ^ 5的数量级。考虑到我的GPU(GTX 750ti),每个块的线程数是1024,每个网格的块数是1024.如果我理解正确,内核中的最大运行次数是1024x1024 = 1048576(小于实际值)。

因此,如果我需要在嵌套循环中进行10 ^ 5 x 10 ^ 5 = 10 ^ 10的计算,那么考虑算法的最佳方法是什么?选择一个固定数字(适合我的GPU)并拆分计算将是一个好主意?

2 个答案:

答案 0 :(得分:1)

  

我的主要问题是如何对每个线程中的变量E求和并将其返回给主机?

您需要首先使用某种形式的逐块并行缩减对级别的每个线程计算求和(我建议使用CUB block wise reduction implementation)。

一旦每个块的线程都有一个部分和,就需要组合块总和。这可以通过每个块的一个线程,通过第二个内核调用(使用一个块)或在主机上原子地完成。如何以及在何处使用最终总和将决定哪些选项最适合您的应用。

答案 1 :(得分:0)

#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/generate.h>
#include <thrust/reduce.h>
#include <thrust/functional.h>
#include <algorithm>
#include <cstdlib>

int main(void)
{
    thrust::host_vector<int> h_vec(100);
    std::generate(h_vec.begin(), h_vec.end(), rand);

    thrust::device_vector<int> d_vec = h_vec;
    int x = thrust::reduce(d_vec.begin(), d_vec.end(), 0, thrust::plus<int>());
    std::cout<< x<< std::endl;
    return 0;
}