繁体   English   中英

CUDA函数的条件编译

[英]Conditional Compilation of CUDA Function

我创建了一个 CUDA 函数,用于使用其直方图计算图像的总和。

我正在尝试为多种计算功能编译内核和包装函数。

核心:

__global__ void calc_hist(unsigned char* pSrc, int* hist, int width, int height, int pitch)
{
    int xIndex = blockIdx.x * blockDim.x + threadIdx.x;
    int yIndex = blockIdx.y * blockDim.y + threadIdx.y;

#if __CUDA_ARCH__ > 110   //Shared Memory For Devices Above Compute 1.1
    __shared__ int shared_hist[256];
#endif

    int global_tid = yIndex * pitch + xIndex;

    int block_tid = threadIdx.y * blockDim.x + threadIdx.x;

    if(xIndex>=width || yIndex>=height) return;

#if __CUDA_ARCH__ == 110 //Calculate Histogram In Global Memory For Compute 1.1

    atomicAdd(&hist[pSrc[global_tid]],1);   /*< Atomic Add In Global Memory */

#elif __CUDA_ARCH__ > 110   //Calculate Histogram In Shared Memory For Compute Above 1.1

    shared_hist[block_tid] = 0;   /*< Clear Shared Memory */
    __syncthreads();

    atomicAdd(&shared_hist[pSrc[global_tid]],1);    /*< Atomic Add In Shared Memory */
    __syncthreads();

    if(shared_hist[block_tid] > 0)  /* Only Write Non Zero Bins Into Global Memory */
        atomicAdd(&(hist[block_tid]),shared_hist[block_tid]);
#else 
    return;     //Do Nothing For Devices Of Compute Capabilty 1.0
#endif
}

包装功能:

int sum_8u_c1(unsigned char* pSrc, double* sum, int width, int height, int pitch, cudaStream_t stream = NULL)
{

#if __CUDA_ARCH__ == 100
    printf("Compute Capability Not Supported\n");
    return 0;

#else
    int *hHist,*dHist;
    cudaMalloc(&dHist,256*sizeof(int));
    cudaHostAlloc(&hHist,256 * sizeof(int),cudaHostAllocDefault);

    cudaMemsetAsync(dHist,0,256 * sizeof(int),stream);

    dim3 Block(16,16);
    dim3 Grid;

    Grid.x = (width + Block.x - 1)/Block.x;
    Grid.y = (height + Block.y - 1)/Block.y;

    calc_hist<<<Grid,Block,0,stream>>>(pSrc,dHist,width,height,pitch);

    cudaMemcpyAsync(hHist,dHist,256 * sizeof(int),cudaMemcpyDeviceToHost,stream);

    cudaStreamSynchronize(stream);

    (*sum) = 0.0;
    for(int i=1; i<256; i++)
        (*sum) += (hHist[i] * i);

    printf("sum = %f\n",(*sum));

    cudaFree(dHist);
    cudaFreeHost(hHist);

    return 1;
#endif

}

问题 1:

sm_10编译时,不应执行包装器和内核。 但事实并非如此。 整个包装函数执行。 输出显示sum = 0.0

我希望输出为Compute Capability Not Supported因为我在包装函数的开头添加了printf语句。

如何防止包装函数在sm_10执行? 我不想添加任何运行时检查,如 if 语句等。可以通过模板元编程来实现吗?

问题2:

当编译大于sm_10 ,只有在内核调用后添加cudaStreamSynchronize ,程序才能正确执行。 但是如果我不同步,输出是sum = 0.0 为什么会发生? 我希望该函数尽可能与主机异步。 是否可以移动内核内部的唯一循环?

我在 Windows 8 上使用 GTX460M、CUDA 5.0、Visual Studio 2008。

广告。 问题 1

正如罗伯特在评论中已经解释的那样 - __CUDA_ARCH__仅在编译设备代码时定义。 澄清一下:当您调用 nvcc 时,代码会被解析和编译两次 - 一次用于 CPU,一次用于 GPU。 __CUDA_ARCH__的存在可用于检查发生了这两个传递中的哪一个,然后对于设备代码 - 正如您在内核中所做的那样 - 可以检查您的目标 GPU。

然而,对于主机端来说,并不是全部丢失。 虽然您没有__CUDA_ARCH__ ,但您可以调用 API 函数cudaGetDeviceProperties ,它会返回有关您的 GPU 的大量信息。 特别是,您可能对表示计算能力的majorminor领域感兴趣。 注意 - 这是在运行时完成的,而不是预处理阶段,因此相同的 CPU 代码将适用于所有 GPU。

广告。 问题2

内核调用和cudaMemoryAsync是异步的。 这意味着如果您不调用cudaStreamSynchronize (或类似方法),即使您的 GPU 尚未完成您的工作,后续 CPU 代码也会继续运行。 这意味着,你从复制数据dHisthHist当你开始在工作可能还没到达那里hHist的循环。 如果你想处理内核的输出,你必须等到内核完成。

请注意, cudaMemcpy (没有Async )内部有一个隐式同步。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM