CUDA内存管理/类中的指针问题

时间:2014-12-07 22:05:44

标签: c++ c class cuda

我正在努力解决一些内存管理问题。我一直收到"未指定的发布失败"将结果复制到主持人时。

我的代码非常简单 - 它在每个线程中生成两个uint并将它们相乘。 我有提供随机数的课程:

class CuRandCuRandomNumberProvider :
{  
public:
    CuRandCuRandomNumberProvider(dim3 numBlocks, dim3 threadsPerBlock);
    CuRandCuRandomNumberProvider(dim3 numBlocks, dim3 threadsPerBlock, unsigned int seed);
    __device__ unsigned int GetRandomNumber();
    ~CuRandCuRandomNumberProvider();
protected:
     curandState * states;
    __device__ bool IsPrime(unsigned int number);
};

CuRandCuRandomNumberProvider::CuRandCuRandomNumberProvider(dim3 numBlocks, dim3 threadsPerBlock)
{
    int numberOfThreads = threadsPerBlock.x * threadsPerBlock.y * numBlocks.x * numBlocks.y;
    std::cout << numberOfThreads << std::endl;
    cudaMalloc ( &this->states, numberOfThreads*sizeof( curandState ) );
    setup_kernel <<< numBlocks, threadsPerBlock >>> ( this->states, time(NULL) );
}

__device__ unsigned int CuRandCuRandomNumberProvider::GetRandomNumber()
{
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;
    register float r =  curand_uniform(&this->states[offset]);
    return 0 + ((double)UINT_MAX) * r;
}

setup_kernel存储在头文件中,如下所示:

__global__ void setup_kernel ( curandState * state, unsigned long seed )
{
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;
    curand_init ( seed, offset, 0, &state[offset] );
}

我的主要内核很简单,看起来像这样:

__global__  void InitKernel(uint3 * ptr, CuRandCuRandomNumberProvider * provider)
{
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;

    ptr[offset].x = provider->GetRandomNumber();
    ptr[offset].y = provider->GetRandomNumber();
    ptr[offset].z = ptr[offset].x * ptr[offset].y;
}

最后一个cudaMemcpy导致问题的主要执行是:

uint3 * pqnD;

uint3 * pqnH = (uint3*)malloc(sizeof(uint3) * numberOfThreads );
memset(pqnH,0,sizeof(uint3) * numberOfThreads );

HANDLE_ERROR( cudaMalloc( (void**)&pqnD, sizeof(uint3) * numberOfThreads ));

CuRandCuRandomNumberProvider * provider = new CuRandCuRandomNumberProvider(numBlocks, threadsPerBlock);

InitKernel<<<numBlocks, threadsPerBlock>>>(pqnD, provider);

HANDLE_ERROR( cudaMemcpy( pqnH, pqnD, sizeof(uint3) * numberOfThreads, cudaMemcpyDeviceToHost ) ); // this line causes error

HANDLE_ERROR( cudaFree( pqnD ) );

如果我明确地做了一切,比如:

uint3 * pqnD;

uint3 * pqnH = (uint3*)malloc(sizeof(uint3) * numberOfThreads );

memset(pqnH,0,sizeof(uint3) * numberOfThreads );

HANDLE_ERROR( cudaMalloc( (void**)&pqnD, sizeof(uint3) * numberOfThreads ));

curandState * states;

cudaMalloc ( &states, numberOfThreads*sizeof( curandState ) );

setup_kernel <<< numBlocks, threadsPerBlock >>> ( states, time(NULL) );

CuRandCuRandomNumberProvider * provider = new CuRandCuRandomNumberProvider(numBlocks, threadsPerBlock, states);


InitKernel2<<<numBlocks, threadsPerBlock>>>(pqnD, states);

HANDLE_ERROR( cudaMemcpy( pqnH, pqnD, sizeof(uint3) * numberOfThreads, cudaMemcpyDeviceToHost ) );

HANDLE_ERROR( cudaFree( pqnD ) );

setup_kernel完全相同,而InitKernel2如下:

__global__  void InitKernel2(uint3 * ptr, curandState * states)
{
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;

    ptr[offset].x = GetRandomNumber(states);
    ptr[offset].y = GetRandomNumber(states);
    ptr[offset].z =     ptr[offset].x *     ptr[offset].y;
}

和GetRandomNumber是:

__device__ unsigned int GetRandomNumber(curandState * states)
{
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;
    register float r =  curand_uniform(&states[offset]);
    return 0 + ((double)UINT_MAX) * r;

}

一切都充满了魅力。有谁知道我做错了什么?我已经挣扎了几个小时。我认为它可能是内存管理或指针传递的东西,但我不知道它会是什么。

请帮助:)!

1 个答案:

答案 0 :(得分:1)

这是非法的:

CuRandCuRandomNumberProvider * provider = new CuRandCuRandomNumberProvider(numBlocks, threadsPerBlock);

InitKernel<<<numBlocks, threadsPerBlock>>>(pqnD, provider);

provider是您在主机上分配的变量。将该指针传递给设备并在设备代码中取消引用它:

ptr[offset].x = provider->GetRandomNumber();

(最终导致:)

register float r =  curand_uniform(&this->states[offset]);

是非法的。

由于您似乎想在主机上设置对象(类CuRandCuRandomNumberProvider)并将其传递给设备,因此一种可能的解决方法是按值传递对象,而不是通过指针传递。这需要进行一些更改,主要是:

CuRandCuRandomNumberProvider provider(numBlocks, threadsPerBlock);
在InitKernel中

__global__  void InitKernel(uint3 * ptr, CuRandCuRandomNumberProvider provider) // change
{
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;

    ptr[offset].x = provider.GetRandomNumber();  // change
    ptr[offset].y = provider.GetRandomNumber();  // change
    ptr[offset].z = ptr[offset].x * ptr[offset].y;
}
CuRandCuRandomNumberProvider :: GetRandomNumber()中的

__device__ unsigned int CuRandCuRandomNumberProvider::GetRandomNumber()
{
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;
    register float r =  curand_uniform(&(states[offset])); // change
    return 0 + ((double)UINT_MAX) * r;
}

(我也删除了析构函数原型,因为它阻碍了。)