在下面的代码中,cudaMemcpy无法正常工作,它返回错误,程序退出。可能是什么问题?在我看来,我似乎没有做违法的事情, vector 的大小对我来说似乎还不错。

该算法可能在某些时候做错了什么,但我想这个想法是正确的。代码是通过并行执行一些部分和来对n个数字求和,然后重新进行迭代。

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>
#include <iostream>

__device__ int aug_vec(int *vec, const int& i, const int& size) {
    return (i >= size) ? 0 : vec[i];
}

__global__ void sumVectorElements(int *vec,const int& size) {
    const int i = (blockDim.x*blockIdx.x + threadIdx.x);
    vec[i] = aug_vec(vec, 2*i, size) + aug_vec(vec, 2 * i + 1, size);
}

__host__ int parallel_sum(int *vec,const int& size) {

    cudaError_t err;
    int *d_vec, *cp_vec;
    int n_threads = (size >> 1) + (size & 1);

    cp_vec = new int[size];
    err = cudaMalloc((void**)&d_vec, size * sizeof(int));

    if (err != cudaSuccess) {
        std::cout << "error in cudaMalloc!" << std::endl;
        exit(1);
    }

    err = cudaMemcpy(d_vec, vec, size*sizeof(int), cudaMemcpyHostToDevice);

    if (err != cudaSuccess) {
        std::cout << "error in cudaMemcpy!" << std::endl;
        exit(1);
    }

    int curr_size = size;
    while (curr_size > 1) {
        std::cout << "size = " << curr_size << std::endl;
        sumVectorElements<<<1,n_threads>>>(d_vec, curr_size);
        curr_size = (curr_size >> 1) + (curr_size & 1);
    }

    err = cudaMemcpy(cp_vec, d_vec, size*sizeof(int), cudaMemcpyDeviceToHost); //THIS LINE IS THE PROBLEM!

    if (err != cudaSuccess) {
        std::cout << "error in cudaMemcpy" << std::endl;
        exit(1);
    }

    err = cudaFree(d_vec);

    if (err != cudaSuccess) {
        std::cout << "error in cudaFree" << std::endl;
        exit(1);
    }

    int rval = cp_vec[0];

    delete[] cp_vec;

    return rval;
}

int main(int argc, char **argv) {
    const int n_blocks = 1;
    const int n_threads_per_block = 12;

    int vec[12] = { 0 };
    for (auto i = 0; i < n_threads_per_block; ++i) vec[i] = i + 1;
    int sum = parallel_sum(vec, n_threads_per_block);
    std::cout << "Sum = " << sum << std::endl;

    system("pause");

    return 0;
}

最佳答案

内核之后的cudaMemcpy操作实际上异步报告由于内核执行而导致的错误。您的错误报告是原始的。如果您有错误代码,则可以通过打印出将该错误代码传递给cudaGetErrorString()的结果来获得更多有用的信息。

由于使用了引用参数,内核中发生了错误:

__global__ void sumVectorElements(int *vec,const int& size) {
                                           ^^^^^^^^^^^^^^^

您传递给内核并希望在内核代码中使用的任何参数都必须引用按值传递的数据,或者是可从设备代码访问/引用的数据。例如,在CUDA中将主机指针传递给设备代码通常是不合法的,因为尝试取消引用设备代码中的主机指针将失败。

上面的异常(exception)是设备代码中可访问的数据/指针/引用。 Unified memorypinned/mapped data是两个示例,此处均未使用。

结果,引用参数涉及主机存储器中某项(size)的引用(基本上是地址)。当内核代码尝试使用该项目时,必须首先取消引用它。在CUDA中,在设备代码中取消引用宿主项是非法的(除非使用UM或固定内存)。

在这种情况下,解决方案很简单:转换为普通的按值传递情况:
__global__ void sumVectorElements(int *vec,const int size) ...
                                                    ^
                                                 remove ampersand

关于c++ - cudaMemcpy不起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49353187/

10-12 06:07