一个简单的CUDA减少计划

时间:2015-06-29 15:00:41

标签: c visual-studio-2010 cuda

在下面的代码中,我试图实现一个简单的并行缩减,其中块大小和每个块的线程数为1024.但是,在实现部分缩减之后,我希望看看我的实现是否正确并且在进程我使程序打印主机内存的第一个元素(数据从设备内存复制到主机内存后)。 我的主机内存初始化为'1'并被复制到设备内存以进行缩减。还原过程之后的printf语句仍然在数组的第一个元素处给出'1'。

我要打印的内容是否存在问题,或者在实施缩减方面是否合乎逻辑? 此外,内核中的printf语句不会打印任何内容。我的语法或对printf语句的调用有什么问题吗? 我的代码如下:

    ifndef CUDACC
define CUDACC
endif
include "cuda_runtime.h"
include "device_launch_parameters.h"
include
include
ifndef THREADSPERBLOCK
define THREADSPERBLOCK 1024
endif
ifndef NUMBLOCKS
define NUMBLOCKS 1024
endif

global void reduceKernel(int *c)
{
extern shared int sh_arr[];

int index = blockDim.x*blockIdx.x + threadIdx.x;
int sh_index = threadIdx.x;

// Storing data from Global memory to shared Memory
sh_arr[sh_index] = c[index];
__syncthreads();

for(unsigned int i = blockDim.x/2; i>0 ; i>>=1)
{
    if(sh_index < i){
        sh_arr[sh_index] += sh_arr[i+sh_index];
    }
    __syncthreads();
}

if(sh_index ==0)
    c[blockIdx.x]=sh_arr[sh_index];
printf("value stored at %d is %d \n", blockIdx.x, c[blockIdx.x]);
return;

}

int main()
{
int *h_a;
int *d_a;
int share_memSize, h_memSize;
size_t d_memSize;

share_memSize = THREADSPERBLOCK*sizeof(int);
h_memSize = THREADSPERBLOCK*NUMBLOCKS;

h_a = (int*)malloc(sizeof(int)*h_memSize);

d_memSize=THREADSPERBLOCK*NUMBLOCKS;
cudaMalloc( (void**)&d_a, h_memSize*sizeof(int));

for(int i=0; i<h_memSize; i++)
{
    h_a[i]=1;    
};

//printf("last element of array %d \n", h_a[h_memSize-1]);

cudaMemcpy((void**)&d_a, (void**)&h_a, h_memSize, cudaMemcpyHostToDevice);
reduceKernel<<<NUMBLOCKS, THREADSPERBLOCK, share_memSize>>>(d_a);
cudaMemcpy((void**)&h_a, (void**)&d_a, d_memSize, cudaMemcpyDeviceToHost);

printf("sizeof host memory %d \n", d_memSize); //sizeof(h_a));
printf("sum after reduction %d \n", h_a[0]);

}

1 个答案:

答案 0 :(得分:1)

此代码存在许多问题。

  1. 您发布的大部分内容都不是有效代码。仅举几个示例,您的globalshared关键字应该在之前和之后都有双重下划线,例如:__global____shared__。我认为这是某种复制粘贴错误或格式错误。您的define语句也存在问题。您应该努力发布没有这些问题的代码。

  2. 每当您遇到CUDA代码时遇到问题,都应该使用proper cuda error checking并在寻求帮助之前使用cuda-memcheck 运行代码。如果你这样做了,那么你就会把注意力集中在下面的第3项上。

  3. 您的cudaMemcpy操作有两种方式破坏:

    cudaMemcpy((void**)&d_a, (void**)&h_a, h_memSize, cudaMemcpyHostToDevice);
    

    首先,与cudaMalloc不同,但与memcpy类似,cudaMemcpy只需要普通的指针参数。其次,转移的大小(如memcpy)位于字节中,因此您的尺寸需要按sizeof(int)放大:

    cudaMemcpy(d_a, h_a, h_memSize*sizeof(int), cudaMemcpyHostToDevice);
    

    ,类似于内核之后的那个。

  4. 来自大内核中每个线程的
  5. printf(就像这个拥有1048576个线程的那个)可能不是一个好主意。你实际上并没有得到你期望的所有输出,并且在Windows上(看起来你在Windows上运行),由于内核执行时间太长,你可能会遇到WDDM看门狗超时。如果您需要来自大型内核的printf,请选择并在threadIdx.xblockIdx.x

  6. 上调整您的printf
  7. 上面的内容可能足以得到一些合理的打印输出,正如你指出的那样,你还没有完成:“我希望看看我的实现是否正确”。但是,这个内核,如精心设计,用输出数据覆盖其输入数据:

    __global__ void reduceKernel(int *c)
    ...
        c[blockIdx.x]=sh_arr[sh_index];
    

    这会导致竞争状况。我建议您将输出数据与输入数据分开,而不是尝试为您排序。更好的是,你应该研究cuda reduction sample code,它也有一个关联的presentation

  8. 以下是您的代码的修改版本,其中修复了上述大多数问题。 它仍然不正确。它仍然有上面的缺陷5. 我不会完全重写您的代码来修复缺陷5,而是指导您使用上面提到的cuda示例代码。

    $ cat t820.cu
    #include <stdio.h>
    
    #ifndef THREADSPERBLOCK
    #define THREADSPERBLOCK 1024
    #endif
    #ifndef NUMBLOCKS
    #define NUMBLOCKS 1024
    #endif
    
    __global__ void reduceKernel(int *c)
    {
    extern __shared__ int sh_arr[];
    
    int index = blockDim.x*blockIdx.x + threadIdx.x;
    int sh_index = threadIdx.x;
    
    // Storing data from Global memory to shared Memory
    sh_arr[sh_index] = c[index];
    __syncthreads();
    
    for(unsigned int i = blockDim.x/2; i>0 ; i>>=1)
    {
        if(sh_index < i){
            sh_arr[sh_index] += sh_arr[i+sh_index];
        }
        __syncthreads();
    }
    
    if(sh_index ==0)
        c[blockIdx.x]=sh_arr[sh_index];
    // printf("value stored at %d is %d \n", blockIdx.x, c[blockIdx.x]);
    return;
    
    }
    
    int main()
    {
    int *h_a;
    int *d_a;
    int share_memSize, h_memSize;
    size_t d_memSize;
    
    share_memSize = THREADSPERBLOCK*sizeof(int);
    h_memSize = THREADSPERBLOCK*NUMBLOCKS;
    
    h_a = (int*)malloc(sizeof(int)*h_memSize);
    
    d_memSize=THREADSPERBLOCK*NUMBLOCKS;
    cudaMalloc( (void**)&d_a, h_memSize*sizeof(int));
    
    for(int i=0; i<h_memSize; i++)
    {
        h_a[i]=1;
    };
    
    //printf("last element of array %d \n", h_a[h_memSize-1]);
    
    cudaMemcpy(d_a, h_a, h_memSize*sizeof(int), cudaMemcpyHostToDevice);
    reduceKernel<<<NUMBLOCKS, THREADSPERBLOCK, share_memSize>>>(d_a);
    cudaMemcpy(h_a, d_a, d_memSize*sizeof(int), cudaMemcpyDeviceToHost);
    
    printf("sizeof host memory %d \n", d_memSize); //sizeof(h_a));
    printf("first block sum after reduction %d \n", h_a[0]);
    }
    $ nvcc -o t820 t820.cu
    $ cuda-memcheck ./t820
    ========= CUDA-MEMCHECK
    sizeof host memory 1048576
    first block sum after reduction 1024
    ========= ERROR SUMMARY: 0 errors
    $