分配2D数组时cudaMalloc崩溃

时间:2018-11-13 12:36:43

标签: c++ cuda histogram

我正在尝试为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运行时,出现以下消息:

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

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

2 个答案:

答案 0 :(得分:1)

您将遇到段错误,因为在主机代码中读取或修改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操作后最终复制到设备阵列。这会导致每分配一个额外的主机到设备内存传输的代价。

答案 1 :(得分:0)

我找到的解决方案是借助this stackoverflow answer。代码如下:

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;
    }
}