繁体   English   中英

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

[英]Accessing Class Member in different CUDA kernels

我有一个仅在GPU上创建的类T ,我想在GPU上创建它,但在CPU上有一个对它的引用,因此我可以将链接作为参数发送给不同的CUDA内核。

class T
{
public:
    int v;
public:
    __device__ T() { v = 10; }
    __device__ ~T() {}
    __device__ int compute() { return v; }
};

这是我要创建类实例并调用compute()函数的内核。

__global__ void kernel(T* obj, int* out)
{
    if(blockIdx.x * blockDim.x + threadIdx.x == 0) {
        out[0] = obj->compute(); // no kernel error, but it returns garbage
    }
}

__global__ void cudaAllocateGPUObj(T* obj)
{
    if(blockIdx.x * blockDim.x + threadIdx.x == 0) {
        obj = new T;
        // if I call `out[0] = obj->compute();` here, everything works fine
    }
}

main函数只是为类型T*的指针分配内存,该指针随后用作cudaAllocateGPUObj的参数。

int main()
{
    int cpu, *gpu;
    cudaMalloc((void**)&gpu, sizeof(int));
    T* obj;
    cudaMalloc((void**)&obj, sizeof(T*));
    cudaAllocateGPUObj<<<1,1>>>(obj);
    kernel<<<1,1>>>(obj, gpu);
    cudaMemcpy(&cpu, gpu, sizeof(int), cudaMemcpyDeviceToHost);
    cudaDeviceSynchronize();
    printf("cudaMemcpy\nresult: %d\n", cpu);
    return 0;
}

这段代码的问题(在代码的注释中指定)是当我调out[0] = obj->compute(); cudaAllocateGPUObj内核中并将获取的值传输到CPU,一切都正确。 但是,如果我想在另一个内核中获取成员值,它将变成垃圾,尽管如果我将返回值从v变量更改为常量,则一切正常。

您能告诉我这段代码有什么问题吗?

当您将参数传递给CUDA内核时,它是一种按值传递机制。 您已经从指向对象的指针开始:

T* obj;

然后,不为该对象分配存储,而是为另一个指针分配存储:

cudaMalloc((void**)&obj, sizeof(T*));

所以我们在这里走错了路。 (这是逻辑C编程错误。)接下来,在分配内核中, obj参数(现在指向GPU内存空间中的某个位置)通过传递:

__global__ void cudaAllocateGPUObj(T* obj)
                                      ^^^ pass-by-value: local copy is made

现在,当您执行此操作时:

        obj = new T;

您创建一个新的指针 ,并用该新指针覆盖obj的本地副本。 因此,当然可以在本地工作,但是调用环境中的obj副本不会使用该新指针进行更新。

解决此问题的一种可能方法是创建正确的指针对指针方法:

$ cat t5.cu
#include <stdio.h>

class T
{
public:
    int v;
public:
    __device__ T() { v = 10; }
    __device__ ~T() {}
    __device__ int compute() { return v; }
};

__global__ void kernel(T** obj, int* out)
{
    if(blockIdx.x * blockDim.x + threadIdx.x == 0) {
        out[0] = (*obj)->compute(); 
    }
}

__global__ void cudaAllocateGPUObj(T** obj)
{
    if(blockIdx.x * blockDim.x + threadIdx.x == 0) {
        *obj = new T;
    }
}

int main()
{
    int cpu, *gpu;
    cudaMalloc((void**)&gpu, sizeof(int));
    T** obj;
    cudaMalloc(&obj, sizeof(T*));
    cudaAllocateGPUObj<<<1,1>>>(obj);
    kernel<<<1,1>>>(obj, gpu);
    cudaMemcpy(&cpu, gpu, sizeof(int), cudaMemcpyDeviceToHost);
    cudaDeviceSynchronize();
    printf("cudaMemcpy\nresult: %d\n", cpu);
    return 0;
}

$ nvcc -arch=sm_35 -o t5 t5.cu
$ cuda-memcheck ./t5
========= CUDA-MEMCHECK
cudaMemcpy
result: 10
========= ERROR SUMMARY: 0 errors
$

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM