cuda 内核没有访问数组的所有元素

Posted

技术标签:

【中文标题】cuda 内核没有访问数组的所有元素【英文标题】:cuda kernel is not accessing all the element of an array 【发布时间】:2019-03-14 03:19:17 【问题描述】:

我编写了一个 cuda 程序来对大型数组进行一些操作。但是当我将该数组传递给 cuda 内核时,它的所有元素都不会被线程访问。下面,有一个简单的程序解释我的用例:

#include <stdio.h>
#include <stdlib.h>

__global__
void kernel(int n)
        int s = threadIdx.x + blockIdx.x*blockDim.x;
        int t = blockDim.x*gridDim.x;
        for(int i=s;i<n;i+=t)
        printf("%d\n",i);  //printing index of array which is being accessed
        


int main(void)
        int i,n = 10000; //array_size
        int blockSize = 64;
        int numBlocks = (n + blockSize - 1) / blockSize;
        kernel<<<numBlocks, blockSize>>>(n);
        cudaDeviceSynchronize();

我试过不同的blockSize = 256, 128, 64, etc,它没有打印数组的所有索引。理想情况下,它应该打印0 to n-1 的任何排列,但是它打印的是较小的(&lt;n) 数字。

如果numBlocksblockSize 都为1,那么它正在访问所有元素。如果数组大小小于 4096,那么它也正在访问所有元素。

【问题讨论】:

你是怎么数数的? 我将该程序的输出通过管道传输到文件然后cat filename | wc -l 如果有帮助,请考虑接受任何有效的答案。 【参考方案1】:

实际上,所有值都在当前情况下打印。但由于输出控制台的缓冲区限制,您可能无法看到所有这些。尝试增加输出控制台的缓冲区大小。

此外,请记住内核内部的printf 调用是乱序执行的。此外,设备上的printf 缓冲区存在限制,在documentation 中进行了说明。

【讨论】:

printf 出现故障,没关系。但它不应该打印n 数字的任何排列。 我猜,缓冲区没有被完全刷新。如文档中所述,尝试在代码末尾调用cudaDeviceReset() cudaDeviceReset() 没有帮助:(又是同样的问题。 增加输出控制台的缓冲区大小可以解决问题。 cudaDeviceSetLimit(cudaLimitPrintfFifoSize, size_t size) 是设置缓冲区大小的必要 API。缓冲区大小默认为1MB【参考方案2】:

使用更好的调试技术!您的代码功能正常

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>

#include <stdlib.h>

__global__
void kernel(int* in, int n)
    int s = threadIdx.x + blockIdx.x*blockDim.x;
    int t = blockDim.x*gridDim.x;
    for (int i = s; i<n; i += t)
        in[i] = 1;  //printing index of array which is being accessed
    


int main(void)
    int i, n = 10000; //array_size
    int blockSize = 64;
    int numBlocks = (n + blockSize - 1) / blockSize;
    int* d_res,*h_res;
    cudaMalloc(&d_res, n*sizeof(int));
    h_res = (int*)malloc(n*sizeof(int));

    kernel << <numBlocks, blockSize >> >(d_res, n);
    cudaDeviceSynchronize();
    cudaMemcpy(h_res, d_res, n*sizeof(int), cudaMemcpyDeviceToHost);

    int sum = 0;
    for (int i = 0; i < n; i++)
        sum += h_res[i];
    printf("%d", sum);

【讨论】:

@kayush206 printf 可以是一种调试方式,但肯定 100000 printf 不是一种调试方式!

以上是关于cuda 内核没有访问数组的所有元素的主要内容,如果未能解决你的问题,请参考以下文章

使用 CUDA Profiler nvprof 进行内存访问

优化 CUDA 二维数组访问

使用存储在另一个数组中的数组索引时,Cuda 非法内存访问错误

优化具有不规则内存访问的 CUDA 内核

CUDA 内核和内存访问(一个内核不完全执行,下一个不启动)

访问不同 CUDA 内核中的类成员