是否有必要使用 thrust::device_vector 执行 cudaMalloc 和 cudaMemcpy?
Is it necessary do a cudaMalloc and cudaMemcpy with a thrust::device_vector?
我是 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;
}
该代码有效。
现在我想使用 thrust 库,我不知道我是否必须做同样的事情。我有这个代码:
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
是否thrust::device_vector 直接在 GPU 分配?。我不知道我做错了什么。
我开始认为没有必要分配 thrust::device_vectors
Thrust 为您完成所有 CUDA API 调用。因此,虽然您可以在手动分配的内存上使用 Thrust 算法或将内存从 thrust::device_vector
传递给内核,但您不需要 cudaMalloc
和 cudaMemcpy
,因为所有内容都已包含在标准 C++ 矢量接口。
thrust::device_vector
分配的内存位于 GPU 上(如果您使用的是 GPU。也可以使用 Thrust 在 CPU 上进行并行化)。所以构造函数为你调用cudaMalloc
。
对于数据传输,您可以像正常的 std::vector
一样使用不同的 thrust::device_vector
和 thrust::host_vectors
(例如,针对不同的组合实现构造函数和 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 不会是我的矩阵运算的首选(运算需要行- and/or 列索引),因为它们通常更自然地写在 CUDA 内核中。
我是 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;
}
该代码有效。
现在我想使用 thrust 库,我不知道我是否必须做同样的事情。我有这个代码:
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
是否thrust::device_vector 直接在 GPU 分配?。我不知道我做错了什么。
我开始认为没有必要分配 thrust::device_vectors
Thrust 为您完成所有 CUDA API 调用。因此,虽然您可以在手动分配的内存上使用 Thrust 算法或将内存从 thrust::device_vector
传递给内核,但您不需要 cudaMalloc
和 cudaMemcpy
,因为所有内容都已包含在标准 C++ 矢量接口。
thrust::device_vector
分配的内存位于 GPU 上(如果您使用的是 GPU。也可以使用 Thrust 在 CPU 上进行并行化)。所以构造函数为你调用cudaMalloc
。
对于数据传输,您可以像正常的 std::vector
一样使用不同的 thrust::device_vector
和 thrust::host_vectors
(例如,针对不同的组合实现构造函数和 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 不会是我的矩阵运算的首选(运算需要行- and/or 列索引),因为它们通常更自然地写在 CUDA 内核中。