为什么CUDA会在访问课程成员时崩溃?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么CUDA会在访问课程成员时崩溃?相关的知识,希望对你有一定的参考价值。

对不起,如果这是一个新问题,但我找不到它。我一直在编写一个可以使用CDUA加速的程序。但是,我的方法很大程度上依赖于将类对象(完全,而不仅仅是它们的成员)传递给内核来运行。为了确定这是否可行,我写了一个小测试程序。

class bulkArray {
public:
    double* value;
    int xSize;

    bulkArray(int xSize) {
        value = new double[xSize];
        this->xSize = xSize;
    }
};

__global__ void addArrays(bulkArray *a, bulkArray *b, bulkArray *c, int N) {
    int id = blockIdx.x*blockDim.x + threadIdx.x;

    if (id < N)
        c->value[id] = a->value[id] + b->value[id];
}

int main() {
    int N = 50000000;

    bulkArray *a;
    bulkArray *b;
    bulkArray *c;

    a = new bulkArray(N);
    b = new bulkArray(N);
    c = new bulkArray(N);

    // allocate unified memory.
    cudaMallocManaged(&a, sizeof(a));
    cudaMallocManaged(&b, sizeof(b));
    cudaMallocManaged(&c, sizeof(c));

    // init vectors on host.
    for (int i = 0; i < N; i++) {
        // CRASHING HERE.
        a->value[i] = sin(i) * cos(i);
        b->value[i] = sin(i) * cos(i);
    }

    int blockSize = 1024;
    int gridSize = (int)ceil((float)N / blockSize);

    addArrays << <gridSize, blockSize >> > (a, b, c, N);

    // sum up vector c.
    double sum = 0;
    for (int i = 0; i < N; i++) {
        sum += c->value[i];
    }

    cout << "Final result: " << sum << endl;

    cudaFree(a);
    cudaFree(b);
    cudaFree(c);

    return 0;
}

不知何故,将3个对象加载到统一内存中会起作用,但是当我尝试访问它们进行修改时会失败。我已经查看了其他指南和示例,但无法确定出现了什么问题。我为发布的代码量道歉,但我不禁担心我正在尝试的是不可能的。

答案

您可能对托管内存或cudaMallocManaged的工作原理有一些误解。在某些方面,cudaMallocManaged在概念上类似于C库malloc,除了它分配管理内存。有关在简单的CUDA应用程序中使用托管内存的更详细介绍,您可能需要参考this blog

具体来说,以下是您的代码的一些问题:

  1. 对具有嵌入指针的对象数组使用托管分配时,如果要在设备上使用该分配,则需要使用托管分配替换所有分配级别。因此,如果要在设备代码中访问该成员/字段,则在构造函数中使用new将不起作用。我们可以在那里替换cudaMallocManaged
  2. 我们不使用new分配指针,然后使用cudaMallocManaged重新分配相同的指针。
  3. 当在指针上使用时,C(或C ++)中的sizeof函数将返回该指针的大小,而不是它指向的大小。因此,这不是分配对象数组的合理方法。
  4. CUDA内核启动是异步的,因此在内核启动后,如果要使用托管数据,则需要创建某种同步。

以下是解决上述问题的最小修改集。我省略了正确的CUDA错误检查,但我强烈建议在开发CUDA代码时。另外,如果您遇到困难,我建议您使用cuda-memcheck运行此代码:

$ cat t51.cu
#include <iostream>
using namespace std;
class bulkArray {
public:
    double* value;
    int xSize;

    void init(int xSize) {
        cudaMallocManaged(&value, xSize*sizeof(double));
        this->xSize = xSize;
    }
};

__global__ void addArrays(bulkArray *a, bulkArray *b, bulkArray *c, int N) {
    int id = blockIdx.x*blockDim.x + threadIdx.x;

    if (id < N)
        c->value[id] = a->value[id] + b->value[id];
}

int main() {
    int N = 50000;

    bulkArray *a;
    bulkArray *b;
    bulkArray *c;

    // allocate unified memory.
    cudaMallocManaged(&a, sizeof(bulkArray));
    cudaMallocManaged(&b, sizeof(bulkArray));
    cudaMallocManaged(&c, sizeof(bulkArray));
    a->init(N);
    b->init(N);
    c->init(N);
    // init vectors on host.
    for (int i = 0; i < N; i++) {
        a->value[i] = sin(i) * cos(i);
        b->value[i] = sin(i) * cos(i);
    }

    int blockSize = 1024;
    int gridSize = (int)ceil((float)N / blockSize);

    addArrays << <gridSize, blockSize >> > (a, b, c, N);
    cudaDeviceSynchronize();
    // sum up vector c.
    double sum = 0;
    double sum2 = 0;
    for (int i = 0; i < N; i++) {
        sum += c->value[i];
        sum2 += a->value[i] + b->value[i];
    }

    cout << "Final result: " << sum << " should be: " << sum2 <<  endl;

    cudaFree(a);
    cudaFree(b);
    cudaFree(c);

    return 0;
}
$ nvcc -arch=sm_35 -o t51 t51.cu
$ cuda-memcheck ./t51
========= CUDA-MEMCHECK
Final result: 0.624013 should be: 0.624013
========= ERROR SUMMARY: 0 errors
$

以上是关于为什么CUDA会在访问课程成员时崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

升级到 TensorRT 7 后加载或构建 cuda 引擎偶尔会崩溃

使用统一内存时 CUDA 中出现意外的读取访问冲突错误

DetachCurrentThread有时会在NDK中崩溃

在地图项目上单击两次时,片段中的地图会在滑动抽屉中崩溃

为啥这个简单的 NSWindow 创建代码会在 ARC 下关闭时触发自动释放池崩溃?

iPhone 应用程序在尝试访问 appDelegate 成员时崩溃