CUDA:模具代码不起作用

时间:2018-08-22 14:57:54

标签: c++ cuda

首先:很抱歉,如果这个主题做得不好(这是我的第一个主题) 我目前正在尝试在NVIDIA上学习GPU计算,但是  我对CUDA的__syncthreads()方法有问题,我认为它不起作用。我尝试在网络上进行搜索,但未找到解决方法。

__global__ void stencil_1d(int *in, int *out) {
    __shared__ int temp[BLOCK_SIZE + 2 * RADIUS];   // Création de la mémoire partagée avec tout les threads d'un même block

    int gindex = threadIdx.x + blockIdx.x * blockDim.x;
    int lindex = threadIdx.x + RADIUS;

    /*for (int i = 0; i < N*sizeof(int); i++)
        printf("%i ---i=%i \n", in[i], i);*/

    // Déplacer les éléments d'entrées sur la mémoire partagée
    temp[lindex] = in[gindex];
    if (threadIdx.x < RADIUS) {
        temp[lindex - RADIUS] = in[gindex - RADIUS]; // Récuprère le Halo avant les valeurs du block
        temp[lindex + BLOCK_SIZE] = in[gindex + BLOCK_SIZE]; // Récupère le Halo après les valeurs du block
    }

    __syncthreads(); // Synchronisation des Threads d'un même Block

    int result = 0;
    for (int offset = -RADIUS; offset <= RADIUS ; offset++)
        result += temp[lindex + offset];

    out[gindex] = result;
}

当我取消对for的注释时,程序可以正常运行,但是目前for变量中没有out我的图表返回-842150451。

主要代码:

int main()
{
    int size = N * sizeof(int);

    /******************** Utilisation de la fonction GPU stencil_1d ********************/

    int *in, *out; // Variable sur la mémoire Host
    int *d_in, *d_out;  //Variable sur la mémoire Device

    // Allocation de la mémore aux variables sur le Device
    cudaMalloc((void**)&d_in, size);
    cudaMalloc((void**)&d_out, size);

    // Allocation de la mémoire aux variables de Host
    in = (int*)malloc(size); random_ints(in, N);
    out = (int*)malloc(size);

    // Copie des valeurs des variables de Host vers Device
    cudaMemcpy(d_in, in, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_out, out, size, cudaMemcpyHostToDevice);

    // Exécution de la fonction sur le Device (ici 3 Blocks, 10 Threads)
    stencil_1d <<<N/THREADS_PER_BLOCK, THREADS_PER_BLOCK>>>(d_in, d_out);

    // Récupération de la variable out de Device vers Host
    cudaMemcpy(out, d_out, size, cudaMemcpyDeviceToHost);

    // Affichage du résultat
    for(int i=0; i<size; i++)
        printf("%i ---i=%i \n", out[i], i);

    // Libération de la mémoire prise par les variables sur Host
    free(in); free(out);

    // Libération de la mémoire prise par les variables sur le Device
    cudaFree(d_in); cudaFree(d_out);

    return 0;
}

如果忘记了: 定义:

#define N 30
#define THREADS_PER_BLOCK 10
#define BLOCK_SIZE (N/THREADS_PER_BLOCK)
#define RADIUS 3

random_ints代码:

void random_ints(int *var, int n) // Attribue une valeur à toutes le composantes des variables
{
    int i;
    for (i = 0; i < n; i++)
        var[i] = 1;
}

在此先感谢您的回答。

1 个答案:

答案 0 :(得分:2)

This code最初是为教学而设计的;它有一些缺陷。

首先,每当遇到CUDA代码问题时,我建议使用proper CUDA error checking并使用cuda-memcheck运行代码(请参阅下面的示例cuda-memcheck)。如果您在寻求他人帮助之前进行了此操作,并在问题中提供了错误信息,则可能会帮助其他人帮助您。

如果使用cuda-memcheck运行此代码,它将指示访问全局内存和共享内存时均出现错误。

  1. 您选择的BLOCK_SIZE不正确。应将其设置为等于THREADS_PER_BLOCK,而不是(N/THREADS_PER_BLOCK)。看来您打算以3个块(每个块10个线程)运行此内核,因此我们将对其进行处理。

  2. 这些行将越界索引:

    if (threadIdx.x < RADIUS) {
        temp[lindex - RADIUS] = in[gindex - RADIUS]; // Récuprère le Halo avant les valeurs du block
        temp[lindex + BLOCK_SIZE] = in[gindex + BLOCK_SIZE]; // Récupère le Halo après les valeurs du block
    

    例如,在第一个块中,第一个线程(threadIdx.x为0),gindex为0,因此计算gindex - RADIUS将为-3。那是不正确的。

  3. 此for循环不正确:

    for(int i=0; i<size; i++)
    

    应该是:

    for(int i=0; i<N; i++)
    

当我修复这些问题时,您的代码会正确运行,并为我带来明智的结果:

$ cat t280.cu
#define N 30
#define THREADS_PER_BLOCK 10
#define BLOCK_SIZE THREADS_PER_BLOCK
#define RADIUS 3

#include <stdio.h>

void random_ints(int *var, int n) // Attribue une valeur à toutes le composantes des variables
{
    int i;
    for (i = 0; i < n; i++)
        var[i] = 1;
}

__global__ void stencil_1d(int *in, int *out) {
    __shared__ int temp[BLOCK_SIZE + 2 * RADIUS];   // Création de la mémoire partagée avec tout les threads d'un même block

    int gindex = threadIdx.x + blockIdx.x * blockDim.x;
    int lindex = threadIdx.x + RADIUS;

    /*for (int i = 0; i < N*sizeof(int); i++)
        printf("%i ---i=%i \n", in[i], i);*/

    // Déplacer les éléments d'entrées sur la mémoire partagée
    temp[lindex] = in[gindex];
    if (threadIdx.x < RADIUS) {
        temp[lindex - RADIUS] = (gindex >= RADIUS)?in[gindex - RADIUS]:0; // Récuprère le Halo avant les valeurs du block
        temp[lindex + BLOCK_SIZE] = ((gindex + BLOCK_SIZE)<N)?in[gindex + BLOCK_SIZE]:0; // Récupère le Halo après les valeurs du block
    }

    __syncthreads(); // Synchronisation des Threads d'un même Block

    int result = 0;
    for (int offset = -RADIUS; offset <= RADIUS ; offset++)
        result += temp[lindex + offset];

    out[gindex] = result;
}

int main()
{
    int size = N * sizeof(int);

    /******************** Utilisation de la fonction GPU stencil_1d ********************/

    int *in, *out; // Variable sur la mémoire Host
    int *d_in, *d_out;  //Variable sur la mémoire Device

    // Allocation de la mémore aux variables sur le Device
    cudaMalloc((void**)&d_in, size);
    cudaMalloc((void**)&d_out, size);

    // Allocation de la mémoire aux variables de Host
    in = (int*)malloc(size); random_ints(in, N);
    out = (int*)malloc(size);

    // Copie des valeurs des variables de Host vers Device
    cudaMemcpy(d_in, in, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_out, out, size, cudaMemcpyHostToDevice);

    // Exécution de la fonction sur le Device (ici 3 Blocks, 10 Threads)
    stencil_1d <<<N/THREADS_PER_BLOCK, THREADS_PER_BLOCK>>>(d_in, d_out);

    // Récupération de la variable out de Device vers Host
    cudaMemcpy(out, d_out, size, cudaMemcpyDeviceToHost);

    // Affichage du résultat
    for(int i=0; i<N; i++)
        printf("%i ---i=%i \n", out[i], i);

    // Libération de la mémoire prise par les variables sur Host
    free(in); free(out);

    // Libération de la mémoire prise par les variables sur le Device
    cudaFree(d_in); cudaFree(d_out);

    return 0;
}
$ nvcc -o t280 t280.cu
$ cuda-memcheck ./t280
========= CUDA-MEMCHECK
4 ---i=0
5 ---i=1
6 ---i=2
7 ---i=3
7 ---i=4
7 ---i=5
7 ---i=6
7 ---i=7
7 ---i=8
7 ---i=9
7 ---i=10
7 ---i=11
7 ---i=12
7 ---i=13
7 ---i=14
7 ---i=15
7 ---i=16
7 ---i=17
7 ---i=18
7 ---i=19
7 ---i=20
7 ---i=21
7 ---i=22
7 ---i=23
7 ---i=24
7 ---i=25
7 ---i=26
6 ---i=27
5 ---i=28
4 ---i=29
========= ERROR SUMMARY: 0 errors
$

我们在模版输出的每一端得到4,5,6的原因是由于我们在内核中对上面第2项的限制,以避免越界索引。您可以根据需要更改此边界行为。

另外一条评论:现在,您的代码选择NTHREADS_PER_BLOCK以便它们可以被整除。只要您这样做(并遵守其他限制,例如每块最大线程数为1024),就可以使用此代码。为了获得other changes should be made的充分灵活性,但是我在这里描述的内容应该足以使您克服这些错误。