【问题标题】:CUDA copying an array of arrays filled with data, from host to deviceCUDA 将一组充满数据的数组从主机复制到设备
【发布时间】:2018-03-15 06:44:45
【问题描述】:

我一直在寻找一种将填充数组主机传输到CUDA中的设备的方法。

我有什么:

  • 填充了数据的全局数组数组,我需要将其复制到设备以供内核执行。
  • 数组中的数组长度不同。

我有一个函数来初始化数组和它的值:

double** weights; // globally defined in host
int init_weigths(){
    weights = (double**) malloc(sizeof(double*) * SIZE);

    for (int i = 0; i < SIZE; i++) {
        weights[i] = (double*) malloc(sizeof(double) * getSize(i));

        for (int j = 0; j < getSize(i); j++){
            weights[i][j] = get_value(i,j);
        }
    }
}

我的(不工作的)解决方案

我设计了一个解决方案,收集互联网上其他答案的信息,但没有人奏效。我认为这是因为我的数组数组已经填满了信息,并且包含的​​数组的长度可变。

我的解决方案是在所有cudaMemcpy 调用以及第二次和更多cudaMalloc 调用中抛出“无效参数”错误;由cudaGetLastError() 检查。 解决方案是这样的:

double** d_weights;
int init_cuda_weight(){
    cudaMalloc((void **) &d_weights, sizeof(double*) * SIZE);

    double** temp_d_ptrs = (double**) malloc(sizeof(double*) * SIZE);
    // temp array of device pointers
    for (int i = 0; i < SIZE; i++){
        cudaMalloc((void**) &temp_d_ptrs[getSize(i)],
                sizeof(double) * getSize(i));
        // ERROR CHECK WITH cudaGetLastError(); doesn't throw any errors ar first.
        cudaMemcpy(temp_d_ptrs[getSize(i)], weights[getSize(i)], sizeof(double) * getSize(i), cudaMemcpyHostToDevice);
        // ERROR CHECK WITH cudaGetLastError(); throw "invalid argument" error for now and beyond.
    }

   cudaMemcpy(d_weights, temp_d_ptrs, sizeof(double*) * SIZE,
        cudaMemcpyHostToDevice);
}

作为附加信息,我稍微简化了代码。数组数组中包含的数组具有不同的长度(即 SIZE2 不是恒定的),这就是我不展平为一维数组的原因。

这个实现有什么问题?实现副本的任何想法?

编辑2: 我写的原始代码没问题。我编辑了代码以包含我遇到的错误并在下面包含正确的答案(代码)。

【问题讨论】:

  • 您显示的代码没有问题。对于此类问题,您需要提供minimal reproducible example,即expectedHere 是一个完整工作的示例,逐字使用您的代码,并且它运行时不会引发任何运行时错误。根据您所展示的内容,我唯一可以推测的是,您用于分配 temp_d_ptrs[i]SIZE2 与您在有问题的 cudaMemcpy 操作中使用的 SIZE2 之间可能存在不匹配。但根据你所展示的,不可能说出来。
  • 感谢您提供的信息!我非常感谢为此类问题提供更好的示例;感谢您也没有直接投反对票。我复制了没有“for”循环的示例,并且内存分配和复制工作正常,如我所愿。我现在正试图找出问题所在。我不确定我应该如何处理这个问题,现在我发现我提供的示例没问题。
  • 将来,如果您想避免投反对票,我的建议是认识到这个问题(或类似问题)需要每个 SO 帮助页面的 MCVE,因此您甚至不应该发布这样的问题在这里没有一个。那么至少没有人可以因为明显违反该规则而投反对票。您显然(在我看来)违反了该规则。而且我认为将其称为规则并不过分,因为它在 SO 帮助页面上进行了详细说明,并且使用了 must 这个词。
  • @RobertCrovella 谢谢你的澄清,我是新来的。现在我没有足够的时间来制作 MCVE(而且因为我的真实代码非常复杂)。您建议我删除问题以避免投票吗?由于我在最后一个问题中的声誉下降,并且系统警告我,他们可能会阻止我提出进一步的问题。但我认为代码可能对其他人有所帮助。
  • 我编辑了示例以包含真正的问题。并用我们所说的正确代码回答了解决方案。感谢您的帮助。

标签: c arrays cuda


【解决方案1】:

错误是我使用数组总大小getSize(i) 作为分配和副本的索引。这是一个被真实代码的复杂性和冗长隐藏的天真的错误。

正确的解决方法是:

double** d_weights;
int init_cuda_weight(){
    cudaMalloc((void **) &d_weights, sizeof(double*) * SIZE);

    double** temp_d_ptrs = (double**) malloc(sizeof(double*) * SIZE);
    // temp array of device pointers
    for (int i = 0; i < SIZE; i++){
        cudaMalloc((void**) &temp_d_ptrs[i],
                sizeof(double) * getSize(i));
        // ERROR CHECK WITH cudaGetLastError()
        cudaMemcpy(temp_d_ptrs[i], weights[i], sizeof(double) * getSize(i), cudaMemcpyHostToDevice);
        // ERROR CHECK WITH cudaGetLastError()
    }

   cudaMemcpy(d_weights, temp_d_ptrs, sizeof(double*) * SIZE,
        cudaMemcpyHostToDevice);
}

【讨论】:

    猜你喜欢
    • 2017-08-27
    • 1970-01-01
    • 1970-01-01
    • 2013-08-30
    • 2018-03-13
    • 1970-01-01
    • 2011-08-24
    • 1970-01-01
    • 2023-03-14
    相关资源
    最近更新 更多