使用CUB :: DeviceScan

时间:2014-04-29 04:59:41

标签: cuda cub

我正在尝试在CUDA中进行独家总和削减。我正在使用CUB库,并决定尝试CUB :: DeviceReduce。但是,我的结果是NaN,我无法弄清楚为什么。

代码是:

#include <cub/cub.cuh>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::endl;
#define DSIZE 512

void dev_cumsum( const float *dev_inData, float *dev_outData ) {
    int n = 512;
    void* dev_temp_storage = NULL;
    size_t temp_storage_bytes = 0;
    cub::DeviceScan::ExclusiveSum(dev_temp_storage,temp_storage_bytes,const_cast<float*>(dev_inData),dev_outData,n);
    cudaMalloc(&dev_temp_storage,temp_storage_bytes);
    cub::DeviceScan::ExclusiveSum(dev_temp_storage,temp_storage_bytes,const_cast<float*>(dev_inData),dev_outData,n);
}

int main(){
    float h_data[512];
    float* d_data;
    float* d_result;
    float h_result[512];
    cudaMalloc(&d_data, DSIZE*sizeof(float));
    cudaMalloc(&d_result, DSIZE*sizeof(float));
    h_data[0] = rand()%10;
    h_result[0] = 0;
    for (int i=1; i<DSIZE; i++) {
        h_data[i] = rand()%10;
        h_result[i] = h_data[i-1]+h_result[i-1];
    }
    cudaMemcpy(d_data, h_data, DSIZE*sizeof(float), cudaMemcpyHostToDevice);
    dev_cumsum(d_data, d_result);
    printf("CPU result = %f\n", h_result[511]);
    cudaMemcpy(h_result, d_result, DSIZE*sizeof(float), cudaMemcpyDeviceToHost);
    printf("GPU result = %f\n", h_result[511]);
    for( int i = 0; i < DSIZE; i++ ) {cout << h_result[i] << " ";}
    cout << endl;
    return 0;
}

此代码为我提供了设备结果的最后8个元素的NaN。

此代码在Linux Mint15中的GTX650 Ti Boost上运行。我正在使用NSight,控制台输出编译命令是:

Invoking: NVCC Compiler
/usr/local/cuda-5.5/bin/nvcc -G -g -O0 -gencode arch=compute_30,code=sm_30 -odir "" -M -o "main.d" "../main.cu"
/usr/local/cuda-5.5/bin/nvcc --device-c -G -O0 -g -gencode arch=compute_30,code=compute_30 -gencode arch=compute_30,code=sm_30  -x cu -o  "main.o" "../main.cu"

Cuda版本是5.5 CUB版本1.0.2

这是在使用Cuda 6,OSX10.9.2,CUB 1.2.3和运行GT750M的另一台计算机上测试的,并且再现了最后8个数字为NaN的错误

编辑:代码使用int和double正常工作,但不能浮动。

编辑:感谢Robert Crovella,这个问题最初是关于DeviceReduce的。该代码有效,它正在抛出NaN,因为使用DeviceScan的早期代码将NaN作为输入。问题经过修订以适应

2 个答案:

答案 0 :(得分:1)

编辑: cub 1.3.0最近发布了,我相信它包含了解决此问题的方法。


我会对您的代码进行一些更改,我认为这些更改是错误,但我不知道它们是否会影响您所看到的内容。在以下代码部分中,您使用的是h_result[0]而未初始化它,因此请添加标记为注释的行:

h_data[0] = rand()%10;
h_result[0] = 0;    // ADD THIS LINE
for (int i=1; i<DSIZE; i++) {
    h_data[i] = rand()%10;
    h_result[i] = h_data[i-1]+h_result[i-1];
}

(显然,不应该影响你的GPU结果。)此外,你的最终cudaMemcpy操作不太正确:

cudaMemcpy(&h_result, d_result, DSIZE*sizeof(float), cudaMemcpyDeviceToHost);
           ^
           delete this ampersand

由于h_result已经是您公式中的指针,因此我们无需将其地址传递给cudaMemcpy

您可以尝试进行这些更改,看看您获得了哪种结果?

我一直在苦苦挣扎。如果您仍然可以重现错误,我将非常感激,如果您可以:

  1. 重新启动计算机,然后重试
  2. 回复您正在运行的实际更新代码,您正在使用的编译命令,CUDA版本,CUB版本以及您运行的GPU以及系统操作系统。 (使用此信息编辑原始问题)

答案 1 :(得分:1)

当我运行代码时,我发现它不是设置为NaN的最后8个值,但事实上,它是自72的最后一个整数倍以来设置为NaN的所有值。在您的示例中,有512个值:这意味着前504(7 * 72)是正确的,后面的8个值是NaN。

此行为似乎一直持续到568(8 * 72)值,此后它似乎正常工作。

我用来测试此代码的代码是:http://pastebin.com/kXVvuKAN

我使用以下命令编译代码:

nvcc --relocatable-device-code = true -gencode arch = compute_30,code = compute_30 -G -o main main.cu

注意:如果我没有使用-G参数,结果会更随机。但是,使用-G命令,它给出了上面提到的清晰模式。