是否有必要使用推力::设备向量做 cudaMalloc 和 cudaMemcpy?

时间:2021-04-20 15:10:00

标签: c++ cuda thrust

我是 CUDA 的新手。我读到有必要使用 cudaMalloc 分配变量,然后使用 cudaMemcpy 将值复制到设备变量。像这样:

__global__ void suma(int *a, int *b, int *c)
{
    *c = *a + *b;
}

int suma_wrapper(int a, int b, int c,int* d_a, int* d_b, int* d_c)
{
    int size = sizeof(int);

    //Reservo espacio en la tarjeta gráfica para las variables de la GPU (DEVICE)
    cudaMalloc((void**) &d_a,size);
    cudaMalloc((void**) &d_b,size);
    cudaMalloc((void**) &d_c,size);

    //Asigno valores para las variables de la CPU (HOST)
    a = 10;
    b = 11;

    //(CPU->GPU)
    cudaMemcpy(d_a,&a, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_b,&b, size, cudaMemcpyHostToDevice);


    //1 block con 1 thread. Notar que se usan variables que ya están en la GPU
    suma<<<1,1>>>(d_a,d_b,d_c);


    cudaMemcpy(&c,d_c, size, cudaMemcpyDeviceToHost);



    cudaFree(d_a);
    cudaFree(d_b);
    cudaFree(d_c);

    return c;

}

该代码有效。

现在我想使用推力库,我不知道我是否必须做同样的事情。我有这个代码:

void boxcount2d_wrapper(std::vector<std::vector<short>> matriz_param, std::vector<int> &n_param, std::vector<int> &r_param)
{
    thrust::host_vector<int> n_host,r_host;
    thrust::device_vector<int> n_device,r_device;

    cudaMalloc((void**) &n_device,0); // They are empty at first
    cudaMalloc((void**) &r_device,0);

    thrust::host_vector<short> matriz_host(width*width);
    thrust::device_vector<short> matriz_device(width*width);
    cudaMemcpy(n_device,n_param, p*sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(r_device,r_param, p*sizeof(int), cudaMemcpyHostToDevice);

    for(auto i = 0; i < matriz_param.size(); i++)
    {
        for(auto j = 0; j < matriz_param.size(); j++)
        {
            matriz_host[i+j]  = matriz_param[i][j];
        }
    }

    cudaMalloc((void**) &matriz_device,matriz_device.size());
    cudaMemcpy(matriz_device,&matriz_host, width*width*sizeof(short), cudaMemcpyHostToDevice);

}


该代码无法编译。我在 cudaMemcpy 上收到此错误:

error: no suitable conversion function from "thrust::device_vector<short, thrust::device_allocator<short>>" to "void *" exists

是否在 GPU 上直接分配推力::device_vector?。我不知道我做错了什么。

我开始认为没有必要分配推力::device_vectors

1 个答案:

答案 0 :(得分:1)

Thrust 为您执行所有 CUDA API 调用。因此,虽然您可以在手动分配的内存上使用推力算法或将内存从 thrust::device_vector 传递到内核,但您不需要 cudaMalloccudaMemcpy,因为所有内容都已包含在标准 C++ 向量接口。

thrust::device_vector 分配的内存位于 GPU 上(如果您正在使用 GPU。您也可以使用 Thrust 在 CPU 上进行并行化)。因此构造函数会为您调用 cudaMalloc

对于数据传输,您可以像普通的 thrust::device_vector 一样使用不同的 thrust::host_vectorsstd::vector(例如,为不同的组合实现了构造函数和 operator=)。 Thrust 知道如何处理每种类型的向量,并会为您调用 cudaMemcpy。如果这对您来说不够明确,您也可以使用 thrust::copy

您的代码可能如下所示:

void boxcount2d_wrapper(std::vector<std::vector<short>> matriz_param, std::vector<int> &n_param, std::vector<int> &r_param)
{
    thrust::device_vector<int> n_device(n_param);
    thrust::device_vector<int> r_device(r_param);

    thrust::host_vector<short> matriz_host(width*width);

    for(auto i = 0; i < matriz_param.size(); i++)
    {
        for(auto j = 0; j < matriz_param.size(); j++)
        {
            matriz_host[i+j]  = matriz_param[i][j];
        }
    }

    thrust::device_vector<short> matriz_device(matriz_host);
    
    // ...do stuff...
}

thrust::device_vector 实际上甚至有一个带 std::vector 的构造函数,所以我们不必在这里浪费时间在不必要的 thrust::host_vector<int> 副本上。出于性能原因(与使用 Thrust 无关),我建议不要将 std::vector<std::vector<T>> 用于矩阵。相反,您应该使用线性内存并使用“词法索引”(lin_idx = y * width + x;),就像您在 Thrust 中所做的那样。然后你甚至可以摆脱这些循环。话虽如此,对于矩阵运算(其中的运算需要行和/或列索引),Thrust 不会是我的首选,因为在 CUDA 内核中编写它们通常更自然。

相关问题