CUDA C:内核输出不良结果

Posted

技术标签:

【中文标题】CUDA C:内核输出不良结果【英文标题】:CUDA C: Kernel outputs bad results 【发布时间】:2013-06-12 09:14:34 【问题描述】:

首先我想说这不是家庭作业,我才刚刚开始使用 CUDA。

我正在尝试运行以下代码来添加 2 个向量...问题是每次运行后结果向量 (c_device) 保持不变并且不会得到两个向量相加的结果。

我尝试过更改向量的长度并使用整数和无符号整数,还尝试在 Visual Studio 中在 x64 和 win32 之间移动。

我已在此处附上代码:

这是.h文件

#ifndef ODINN_CUDA_MAIN_H
#define ODINN_CUDA_MAIN_H

#define ARR_SIZE 100
#define ITER_AMOUNT 1

typedef enum cudaError cudaError_t;

static void HandleError(cudaError_t err, const char *file, int line) 
    if (err != CUDA_SUCCESS) 
        printf("%s in %s at line %d\n", cudaGetErrorString(err), file, line);
        exit(EXIT_FAILURE);
    


#define HANDLE_ERROR(err) (HandleError(err, __FILE__, __LINE__))

#define GET_CURRENT_CLOCKS(var) (var = clock())
#define GET_CLOCK_INTERVAL_SEC(start, end, result) (result = ((double)((double)end - (double)start) / (double)CLOCKS_PER_SEC))

__host__ dim3 requestBlockSize(int x, int y=0, int z=0);
__host__ dim3 requestNumBlocks(int x, int y=0, int z=0);
__host__ void allocateVectors(unsigned int **a_host, unsigned int **b_host, unsigned int **c_host, unsigned int **a_device, unsigned int **b_device, unsigned int **c_device);
__global__ void addVectors(unsigned int* a, unsigned int* b, unsigned int* result, int n);
__host__ void cleanUp(unsigned int *a_host, unsigned int *b_host, unsigned int *c_host, unsigned int *a_device, unsigned int *b_device, unsigned int *c_device);

#endif

这是 .cu 文件:

#include <cuda.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#include "main.h"

static cudaDeviceProp prop;

int main(void) 
        // Start lazy init now so first cudaMallow will run faster.
        cudaSetDevice(0);
        cudaFree(0);

        unsigned int *a_host, *b_host, *c_host;
        unsigned int *a_device, *b_device, *c_device;
        double delta_in_sec;
        size_t size = sizeof(unsigned int) * ARR_SIZE;
        clock_t start_clock, end_clock;

        HANDLE_ERROR(cudaGetDeviceProperties(&prop, 0));

        dim3 block_size = requestBlockSize(1024);
        int blocks_requested = floor((double)(ARR_SIZE / block_size.x));
    dim3 n_blocks = requestNumBlocks(blocks_requested > 0 ? blocks_requested : 1);

        fprintf(stdout, "Allocating vectors ...\n");
        allocateVectors(&a_host, &b_host, &c_host, &a_device, &b_device, &c_device);

        fprintf(stdout, "Copying to device ...\n");
        HANDLE_ERROR(cudaMemcpy(a_device, a_host, size, cudaMemcpyHostToDevice));
        HANDLE_ERROR(cudaMemcpy(b_device, b_host, size, cudaMemcpyHostToDevice));

        fprintf(stdout, "Running kernel ...\n");
        GET_CURRENT_CLOCKS(start_clock);

        for(int i=0; i<ITER_AMOUNT; i++) \
                addVectors<<<n_blocks, block_size>>>(a_device, b_device, c_device, ARR_SIZE);
        

        GET_CURRENT_CLOCKS(end_clock);
        GET_CLOCK_INTERVAL_SEC(start_clock, end_clock, delta_in_sec);

        fprintf(stdout, "Runtime of kernel %d times on arrays in length %d took %f seconds\n"
                "Copying results back to host ...\n", ITER_AMOUNT, ARR_SIZE, delta_in_sec);

        HANDLE_ERROR(cudaMemcpy(c_host, c_device, size, cudaMemcpyDeviceToHost));;
        fprintf(stdout, "%u + %u != %u\n", a_host[0], b_host[0], c_host[0]);

        fprintf(stdout, "Cleaning up ...\n");
        cleanUp(a_host, b_host, c_host, a_device, b_device, c_device);

        fprintf(stdout, "Done!\n");


__host__ dim3 requestBlockSize(int x, int y, int z) 
        dim3 blocksize(
                x <= prop.maxThreadsDim[0] ? x : prop.maxThreadsDim[0],
                y <= prop.maxThreadsDim[1] ? y : prop.maxThreadsDim[1],
                z <= prop.maxThreadsDim[2] ? z : prop.maxThreadsDim[2]
        );

        return blocksize;


__host__ dim3 requestNumBlocks(int x, int y, int z) 
        dim3 numblocks(x, y, z);

        return numblocks;


__host__ void allocateVectors(unsigned int **a_host, unsigned int **b_host, unsigned int **c_host, unsigned int **a_device, unsigned int **b_device, unsigned int **c_device) 
        size_t size = sizeof(unsigned int) * ARR_SIZE;

        *a_host = (unsigned int *)malloc(size);
        *b_host = (unsigned int *)malloc(size);
        *c_host = (unsigned int *)malloc(size);

        HANDLE_ERROR(cudaMalloc((void **)a_device, size));
        HANDLE_ERROR(cudaMalloc((void **)b_device, size));
        HANDLE_ERROR(cudaMalloc((void **)c_device, size));

        srand(time(NULL));

        for(int i=0; i<ARR_SIZE; i++) 
                (*a_host)[i] = rand() % ARR_SIZE;
                (*b_host)[i] = rand() % ARR_SIZE;
        


__global__ void addVectors(unsigned int* a, unsigned int* b, unsigned int* result, int n) 
        int idx = blockIdx.x * blockDim.x + threadIdx.x;

        if(idx >= 0 && idx < n)
                result[idx] = a[idx] + b[idx];


__host__ void cleanUp(unsigned int *a_host, unsigned int *b_host, unsigned int *c_host, unsigned int *a_device, unsigned int *b_device, unsigned int *c_device) 
        free(a_host);
        free(b_host);
        free(c_host);

        HANDLE_ERROR(cudaFree(a_device));
        HANDLE_ERROR(cudaFree(b_device));
        HANDLE_ERROR(cudaFree(c_device));

如果您更喜欢查看那里的代码,这里是 pastebin 的链接:http://pastebin.com/04jy1CaB

我想提一下,将 a_device 复制到 c_host 时它可以工作。 我也尝试将 c_host 复制到 c_device 看看会发生什么,结果是一样的。

有什么建议吗?

【问题讨论】:

你还没有在这里问过问题(“有什么建议吗?”不是一个有效的问题),而且“不好的结果”是一个非常模糊的问题描述,我不知道什么样的答案你期待。您的 API 错误检查不完整,内核可能从未运行,但您没有检测到错误。有关如何在启动内核时正确检查运行时错误的详细信息,请参阅this answer。 好的,我明白你的意思了......我做了一些错误检查,就像你给我的链接一样,它说我正在将无效参数传递给内核调用......所以可能是原因...现在的问题是我传递的参数有什么问题...它们是常规的 DIM3 参数,在 x>0 和 y=z=0 中都存在。 【参考方案1】:

好的,感谢 talonmies 对我的问题的评论,我意识到我没有做足够的错误检查,当我进行额外的检查时,我发现我将错误的参数传递给内核调用。

我将无效的 dim3 y 和 z 值传递给内核线程数量和块数量参数。 如果你注意到我的默认值是 0,它们应该是 1。

调试器万岁:)

感谢您的帮助。

【讨论】:

以上是关于CUDA C:内核输出不良结果的主要内容,如果未能解决你的问题,请参考以下文章

简单cuda内核添加:2432内核调用后内存非法

CUDA 帮助实现具有 320*240 图像处理的内核函数

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

解释 NVIDIA Visual Profiler 输出

CUDA 内核可以调用 cublas 函数吗?

无法打印从 CUDA 内核返回的值 [关闭]