分配2D数组时在cudaMalloc上崩溃



我正在尝试为gPb算法实现构建与图像中每个像素相对应的无符号字符的直方图阵列。我在一个cudaMalloc电话上崩溃了,我无法解决。我看过其他类似的问题,我总是测试之前的操作是否返回cudaSuccess。这是我的代码:

首先,我在类CudaImage:的构造函数中分配这个结构

bool CudaImage::create2DHistoArray()
{
//preparing histograms
m_LastCudaError = cudaMalloc((void**)&m_dHistograms, (m_Height + 2 * m_Scale) * sizeof(unsigned int*));
if (m_LastCudaError != cudaSuccess)
return false;
//set all histograms to nullptr
m_LastCudaError = cudaMemset(m_dHistograms, 0, (m_Height + 2 * m_Scale) * sizeof(unsigned int*));
if (m_LastCudaError != cudaSuccess)
return false;
return true;
} 

那么在某个时刻,我会调用一个成员函数来分配一些m_dHistograms[I],如下所示:

bool CudaImage::initializeHistoRange(int start, int stop)
{ 
for (int i = start; i < stop; ++i) {
m_LastCudaError = cudaMalloc((void**)&m_dHistograms[i], 256 * 2 * m_ArcNo * (m_Width + 2 * m_Scale) * sizeof(unsigned int));
if (m_LastCudaError != cudaSuccess) {
return false;
}
//set all pixels in the gradient images to 0
m_LastCudaError = cudaMemset(m_dHistograms[i], 0, 256 * 2 * m_ArcNo * (m_Width + 2 * m_Scale) * sizeof(unsigned int));
if (m_LastCudaError != cudaSuccess)
return false;
}
return true;
}

最后一个函数中的第一个cudaMalloc在没有任何警告的情况下崩溃。当使用cuda memcheck运行时,我得到以下消息:

"从主机取消引用统一内存时,应用程序可能遇到错误。请在主机调试器下重新运行应用程序以捕获此类错误。">

有人能帮忙吗?另一个问题是数组分配是否得到了正确的实现。我不想从一开始就分配所有内存,因为内存太多了,所以我在构造函数(第一个函数(中只分配指向数组行的指针,然后在应用程序中,我在需要内存时分配内存,并释放不需要的内存。

您得到的是segfault,因为读取或修改主机代码中m_dHistograms[i]的值是非法的,因为它是在设备内存中分配的。你需要做的是这样的事情:

bool CudaImage::initializeHistoRange(int start, int stop)
{ 
for (int i = start; i < stop; ++i) {
// Allocated memory
unsigned int* p;
m_LastCudaError = cudaMalloc((void**)&p, 256 * 2 * m_ArcNo * (m_Width + 2 * m_Scale) * sizeof(unsigned int));
if (m_LastCudaError != cudaSuccess) {
return false;
}
//set all pixels in the gradient images to 0
m_LastCudaError = cudaMemset(p, 0, 256 * 2 * m_ArcNo * (m_Width + 2 * m_Scale) * sizeof(unsigned int));
if (m_LastCudaError != cudaSuccess)
return false;
}
// Transfer address of allocation to device    
m_LastCudaError = cudaMemcpy(m_dHistograms + i, &p, sizeof(unsigned int *), cudaMemcpyHostToDevice);
if (m_LastCudaError != cudaSuccess)
return false;
}
return true;
}

【免责声明:从未编译或运行,使用风险自负】

这里,分配地址存储在主机变量中,在完成分配和memset操作后,该主机变量最终被复制到设备阵列。这会导致每次分配额外的主机到设备内存传输。

我找到的解决方案是在这个stackoverflow答案的帮助下。代码如下:

bool CudaImage::initializeHistoRange(int start, int stop)
{
for (int i = start; i < stop; ++i) {
m_LastCudaError = cudaMalloc((void**)&m_hHistograms[i], 256 * 2 * m_ArcNo * (m_Width + 2 * m_Scale) * sizeof(unsigned int));
if (m_LastCudaError != cudaSuccess) {
return false;
}
cudaMemcpy(m_dHistograms, m_hHistograms, stop * sizeof(unsigned int*), cudaMemcpyHostToDevice);
if (m_LastCudaError != cudaSuccess)
return false;
}
return true;
}
bool CudaImage::create2DHistoArray()
{
m_LastCudaError = cudaMalloc((void**)&m_dHistograms, (m_Height + 2 * m_Scale) * sizeof(unsigned int*));
if (m_LastCudaError != cudaSuccess)
return false;
m_hHistograms = (unsigned int**)malloc((m_Height + 2 * m_Scale) * sizeof(unsigned int*));
return true;
}

也就是说,我在主机成员中使用了一个额外的成员,这有助于我在设备中创建内存。在算法操作期间释放内存的代码是:

void CudaImage::deleteFromHistoMaps(int index) {
//I need some more device memory
if (index + m_Scale + 1 < m_Height + 2 * m_Scale) {
initializeHistoRange(index + m_Scale + 1, index + m_Scale + 2);
}
//device memory is not needed anymore - free it
if (index >= m_Scale + 1) {
cudaFree(m_hHistograms[index - m_Scale - 1]);
m_hHistograms[index - m_Scale - 1] = nullptr;
}
}

最新更新