内核同步

时间:2019-06-27 07:45:18

标签: c++ cuda

我是Cuda编程的新手,并且正在实现经典的Floyd APSP算法。该算法包含3个嵌套循环,两个内部循环内的所有代码都可以并行执行。

作为我代码的主要部分,这是内核代码:

__global__ void dfloyd(double *dM, size_t k, size_t n)
{
    unsigned int x = threadIdx.x + blockIdx.x * blockDim.x;
    unsigned int y = threadIdx.y + blockIdx.y * blockDim.y;
    unsigned int index = y * n + x;
    double d;

    if (x < n && y < n)
    {
        d=dM[x+k*n] + dM[k+y*n];
        if (d<dM[index])
            dM[index]=d;
    }
}

这是启动内核的主要功能部分(出于可读性,我省略了错误处理代码):

double *dM;
cudaMalloc((void **)&dM, sizeof_M);
cudaMemcpy(dM, hM, sizeof_M, cudaMemcpyHostToDevice);

int dimx = 32;
int dimy = 32;
dim3 block(dimx, dimy);
dim3 grid((n + block.x - 1) / block.x, (n + block.y - 1) / block.y);

for (size_t k=0; k<n; k++)
{
    dfloyd<<<grid, block>>>(dM, k, n);
    cudaDeviceSynchronize();
}

cudaMemcpy(hM, dM, sizeof_M, cudaMemcpyDeviceToHost);

[为了理解,dM是指存储在设备侧的距离矩阵,hM是在主机侧的距离,n是指节点数。]

k循环中的内核必须串行执行,这解释了为什么我在每次内核执行后都写cudaDeviceSynchronize()指令。 但是,我注意到,将此同步指令放在循环的外部之外会导致相同的结果。

现在,我的问题。执行以下两段代码

for (size_t k=0; k<n; k++)
{
    dfloyd<<<grid, block>>>(dM, k, n);
    cudaDeviceSynchronize();
}

for (size_t k=0; k<n; k++)
{
    dfloyd<<<grid, block>>>(dM, k, n);
}
cudaDeviceSynchronize();

等价吗?

1 个答案:

答案 0 :(得分:4)

它们不是等效的,但是会给出相同的结果。第一个将使主机在每次内核调用之后等待,直到内核返回为止,而另一个将使主机仅等待一次。 可能令人困惑的部分是它为什么起作用;在CUDA中,保证对同一流(在您的情况下为默认流)的两个连续内核调用可以串行执行。

在性能方面,建议使用第二个版本,因为与主机的同步会增加开销。

编辑:在这种特定情况下,您甚至不需要调用cudaDeviceSynchronize(),因为cudaMemcpy将同步。