当块数很大时,CUDA GPU的结果令人惊讶

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当块数很大时,CUDA GPU的结果令人惊讶相关的知识,希望对你有一定的参考价值。

最近我使用CUDA编程,当blockNum超过500时我遇到了一个不可思议的问题。为了简化模式,我编写了以下测试代码:

#include <assert.h>
#include <cuda.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <cuda_runtime.h>  
#include <device_launch_parameters.h>
/* Example from "Introduction to CUDA C" from NVIDIA website:
https://developer.nvidia.com/cuda-education

Compile with:
$ nvcc example_intro.cu */

#define num 1000
const int N = num*32*12;

__global__ void add_blocks (int *a,  int *c) {
   int threadId = blockIdx.x * blockDim.x * blockDim.y 
                + threadIdx.y * blockDim.x + threadIdx.x;
    int block_id = threadIdx.y;
    if(threadId % 2 == 0){
        c[threadId] =  1;
    }
}


int main(void) {

    int *a, *c; 
    int *d_a,  *d_c; /* Device (GPU) copies of a, b, c */
    size_t size = N * sizeof(int);

    /* Allocate memory in device */
    cudaMalloc((void **) &d_a, size);
    cudaMalloc((void **) &d_c, size);

    /* Allocate memory in host */
    a = (int *) malloc(size);
    c = (int *) malloc(size);

    /* Allocate random data in vectors a and b (inside host) */
    for (int i = 0; i < N; ++i) {
        a[i] = 0;
        c[i] = 0;
    }

    /* Copy data to device */
    cudaMemcpy(d_a, a, size, cudaMemcpyHostToDevice);

    dim3 threads_per_block(32, 12);
    add_blocks<<<num, threads_per_block>>>(d_a,d_c);
    cudaMemcpy(c, d_c, size, cudaMemcpyDeviceToHost);

    cudaError_t errSync  = cudaGetLastError();
    if (errSync != cudaSuccess) 
    printf("Sync kernel error: %s
", cudaGetErrorString(errSync));

    int counter = 0;
    for (int i = 0; i < N; ++i) {
        if(c[i] == 1){
            counter ++;
        }
    }
    printf("%d
",counter);

    /* Clean-up */
    free(a); 
    free(c);
    cudaFree(d_a);
    cudaFree(d_c);

    return 0;
  }

当线程数为2的倍数时,我将c数组设置为1,最后我计算数字1,我​​认为是N / 2。当块数低于500时,它运行良好,例如是num * 32 * 12/2 = 500 * 32 * 12/2 = 96 000.但是当num为1000时,结果是312846,应该是192000.任何人都可以帮助我?谢谢大家。

答案

问题出在这段代码中:

int counter = 0;
for (int i = 0; i < N; ++i) {
    if(c[i] == 1){
        counter ++;
    }
}
printf("%d
",counter);

您隐含地假设c中的每个值都必须由先前的GPU内核设置。但是,你根本没有在d_c中设置一半元素的值(因此在程序的这一点上都是c),因此无法保证其中一些元素的值也不会为1.读取和使用单一化记忆的价值并不惊人,这只是糟糕的编程实践。

以上是关于当块数很大时,CUDA GPU的结果令人惊讶的主要内容,如果未能解决你的问题,请参考以下文章

GPU/CUDA:网格的最大块数和每个多处理器的最大驻留块数

你能以编程方式知道 GPU 中每个块的最大块数和线程数吗?

通过更改线程数更改 CUDA 代码输出的说明

RuntimeError: CUDA out of memory. Tried to allocate 600.00 MiB (GPU 0; 23.69 GiB total capacity)(代码片

CUDA编程共享内存与Thread的同步

CUDA编程共享内存与Thread的同步