我正在努力解决一些内存管理问题。我一直收到"未指定的发布失败"将结果复制到主持人时。
我的代码非常简单 - 它在每个线程中生成两个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;
}
一切都充满了魅力。有谁知道我做错了什么?我已经挣扎了几个小时。我认为它可能是内存管理或指针传递的东西,但我不知道它会是什么。
请帮助:)!
答案 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;
}
(我也删除了析构函数原型,因为它阻碍了。)