【问题标题】:Cuda not giving correct answer when array size is larger than 1,000,000当数组大小大于 1,000,000 时,Cuda 未给出正确答案
【发布时间】:2013-04-24 23:42:23
【问题描述】:

我已经编写了一个简单的求和代码,在我将数组大小增加到 100 万之前它似乎工作得很好,这可能是问题所在。

#define BLOCK_SIZE 128
#define ARRAY_SIZE 10000

cudaError_t addWithCuda(const long *input, long *output, int totalBlocks, size_t size);

__global__ void sumKernel(const long *input, long *output)
{
    int tid = threadIdx.x;
    int bid = blockDim.x * blockIdx.x;

    __shared__ long data[BLOCK_SIZE];

    if(bid+tid < ARRAY_SIZE)
           data[tid] = input[bid+tid];
    else
           data[tid] = 0;

     __syncthreads();

    for(int i = BLOCK_SIZE/2; i >= 1; i >>= 1)
    {
        if(tid < i)
        data[tid] += data[tid + i];
        __syncthreads(); 
    }

    if(tid == 0)
        output[blockIdx.x] = data[0];
}

int main()
{    
    int totalBlocks = ARRAY_SIZE/BLOCK_SIZE;

    if(ARRAY_SIZE % BLOCK_SIZE != 0)
        totalBlocks++;

    long *input = (long*) malloc(ARRAY_SIZE * sizeof(long) );
    long *output = (long*) malloc(totalBlocks * sizeof(long) );

    for(int i=0; i<ARRAY_SIZE; i++)
    {
        input[i] = i+1 ;
    }
// Add vectors in parallel.
        cudaError_t cudaStatus = addWithCuda(input, output, totalBlocks, ARRAY_SIZE);
        if (cudaStatus != cudaSuccess) {
             fprintf(stderr, "addWithCuda failed!");
             return 1;
        }

    long ans = 0;
    for(int i =0 ; i < totalBlocks ;i++)
    {
        ans = ans + output[i];
    }

    printf("Final Ans : %ld",ans);

// cudaDeviceReset must be called before exiting in order for profiling and
// tracing tools such as Nsight and Visual Profiler to show complete traces.
cudaStatus = cudaDeviceReset();
        if (cudaStatus != cudaSuccess) {
              fprintf(stderr, "cudaDeviceReset failed!");
              return 1;
         }

     getchar();

      return 0;
}

     // Helper function for using CUDA to add vectors in parallel.
     cudaError_t addWithCuda(const long *input, long *output, int totalBlocks, size_t size)
     {
          long *dev_input = 0;
          long *dev_output = 0;

          cudaError_t cudaStatus;

// Choose which GPU to run on, change this on a multi-GPU system.
           cudaStatus = cudaSetDevice(0);
         if (cudaStatus != cudaSuccess) {
             fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");
             goto Error;
     }

// Allocate GPU buffers for two vectors (one input, one output)    .

     cudaStatus = cudaMalloc((void**)&dev_input, size * sizeof(long));
     if (cudaStatus != cudaSuccess) {
         fprintf(stderr, "cudaMalloc failed!");
         goto Error;
         }

cudaStatus = cudaMalloc((void**)&dev_output, totalBlocks * sizeof(long));
if (cudaStatus != cudaSuccess) {
    fprintf(stderr, "cudaMalloc failed!");
    goto Error;
}

// Copy input vectors from host memory to GPU buffers.
cudaStatus = cudaMemcpy(dev_input, input, size * sizeof(long), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
    fprintf(stderr, "cudaMemcpy failed!");
    goto Error;
}

cudaStatus = cudaMemcpy(dev_output, output, (totalBlocks) * sizeof(long), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
    fprintf(stderr, "cudaMemcpy failed!");
    goto Error;
}

// Launch a kernel on the GPU with one thread for each element.
sumKernel<<<totalBlocks, BLOCK_SIZE>>>(dev_input, dev_output);

// cudaDeviceSynchronize waits for the kernel to finish, and returns
// any errors encountered during the launch.
cudaStatus = cudaDeviceSynchronize();
if (cudaStatus != cudaSuccess) {
    fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
    goto Error;
}

// Copy output vector from GPU buffer to host memory.
cudaStatus = cudaMemcpy(output, dev_output, totalBlocks * sizeof(long), cudaMemcpyDeviceToHost);
if (cudaStatus != cudaSuccess) {
    fprintf(stderr, "cudaMemcpy failed!");
    goto Error;
}

Error:
cudaFree(dev_input);
cudaFree(dev_output);

return cudaStatus;
}

如果它与我的 GPU 设备有关,仅供参考,我的 GPU 是 GTXX 650ti。 以下是有关 GPU 的信息:

每个多处理器的最大线程数:2048

每个块的最大线程数:1024

块的每个维度的最大尺寸:1024 x 1024 x 64

网格每个维度的最大尺寸:2147483647 x 65535 x 65535

最大内存间距:2147483647 字节

纹理对齐:512 字节

【问题讨论】:

  • 它为 100 万个附加值给出了错误的答案。
  • @RobertHarvey 删除了所有第三方链接 :)
  • 请正确处理所有 cuda API 调用和内核调用的cuda error checking。然后,如果没有报告错误,请通过 cuda-memcheck 运行您的代码,即cuda-memcheck myapp,并确定 cuda-memcheck 是否报告了任何错误。还请正确缩进和格式化您的代码,使其更具可读性。

标签: c++ c visual-studio cuda


【解决方案1】:

实际上,答案 =could not fit in long 所以在对数据类型使用 long double 后,这个问题得到了解决。谢谢大家!

【讨论】:

    【解决方案2】:

    您的代码中的一个问题是您的最后一个 cudaMemcpy 设置不正确:

    cudaMemcpy(output, dev_output, totalBlocks * sizeof(int), cudaMemcpyDeviceToHost);
    

    您的所有数据都是 long 数据,因此您应该使用 sizeof(long) 而不是 sizeof(int) 进行复制

    代码中的另一个问题是 long 数据类型使用了错误的 printf 格式标识符:

    printf("\n %d \n",output[i]);
    

    改用这样的东西:

    printf("\n %ld \n",output[i]);
    

    如果您不是针对 sm_30 架构进行编译,您也可能会遇到块数较大的问题。在这种情况下,正确的cuda error checking 会发现问题。

    【讨论】:

    • 我做了错误检查,没有报告并将所有输入数据转换为长数据类型,现在答案已更改但仍然不正确。
    • 您是否进行了我在上面的回答中建议的更改?如果是这样,您可以使用修改后的代码更新您的问题。我已经用我的更改测试了您的代码,并且对于至少高达 5,000,000 的数组大小,一切似乎都有效
    • 您没有做出我在回答中建议的更改。请阅读我的回答。您需要更改最终的 cudaMemcpyprintf 声明。
    • 我已经做了 cudaMemcpy,对 printf 声明很抱歉,但现在更正了。
    • 在您的代码中查找sizeof(int)。将其更改为sizeof(long)
    【解决方案3】:

    sumKernel&lt;&lt;&lt;totalBlocks, BLOCK_SIZE&gt;&gt;&gt;(dev_input, dev_output); 之后不会检查错误。通常,如果您要检查最后发生的错误,它应该给出错误invalid configuration argument。尝试在sumKernel 行之后添加以下内容。

    cudaStatus = cudaGetLastError();
    if (cudaStatus != cudaSuccess) {
        printf(stderr, "sumKernel failed: %s\n", cudaGetErrorString(cudaStatus));
        goto Error;
    }
    

    有关错误的更多信息,请参阅this question

    【讨论】:

      猜你喜欢
      • 2018-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多