推力:访问使用 cudaMallocPitch 创建的设备变量
Thrust: Accessing a device variable created with cudaMallocPitch
我有一个数据矩阵,我应该使用 GPU(以及可能的推力库)对其进行一些详细说明。到目前为止,我已经能够将数据复制到 GPU 并编写自己的内核函数。现在,根据我的内核函数的输出,我将利用 thrust 库对同一数据矩阵进行其他阐述,尽可能避免从 GPU<->CPU.[= 下载和重新上传数据14=]
因此,我使用 cudaMallocPitch 函数在 GPU 中创建了一个设备变量:
float *d_M;
size_t pitch;
cudaStatus = cudaMallocPitch(&d_M, &pitch, sizeof(float)*(N), M+1);
if (cudaStatus != cudaSuccess)
{
fprintf(stderr, "cudaMalloc Failed!");
INFO;
return CUDA_MALLOC_ERROR;
}
这个变量表示一个维度为 NxM+1 的矩阵。在使用 ad-hoc cuda 函数对 GPU 进行了一些详细说明之后,我将使用 thrust 库对每一行的元素求和,并将结果放在每一行的 M+1 列上。
对于这样的操作,我会使用 thrust 库。
我的意图应该是检索使用 cudaMallocPitch 创建的 raw pointer,将其转换为 thrust::device_ptr 然后操作它使用推力功能。所以,在代码中:
thrust::device_ptr<float> dd_M = thrust::device_pointer_cast(d_M);
但是,当我尝试打印两个变量的地址以确保指针具有相同的地址时:
printf("Address d_M: %p\n", &d_M);
printf("Address dd_M: %p\n", &dd_M);
我得到了不同的地址值。我不知道我做错了什么。对于这样的操作,我只是按照 link Thrust - Memory Management Functions.
的推力手册进行操作
cudaMallocPitch
基本上无法使用推力。这是因为它创建了这样的分配:
D D D D D D D D D D D D D D X X
D D D D D D D D D D D D D D X X
D D D D D D D D D D D D D D X X
D D D D D D D D D D D D D D X X
D D D D D D D D D D D D D D X X
...
其中 D
项代表您的实际数据,X
项代表附加到每行的额外 space 以使您的数据宽度与所需的机器间距相匹配。
问题是thrust对X
代表的这个"unused"区域没有概念。当数据中有 "unused" 间隙时,没有 方便的 方法告诉推力函数分配线程(并生成适当的连续索引)。所以如果我们将上面的转换为推力矢量:
D D D D D D D D D D D D D D X X D D D D D D D D D D D D D D X X D D ...
分散在向量中的 X
区域不能方便地 "skipped" 在推力算法和索引中。如果你真的想这样做,可能会想出一个 thrust::permutation_iterator
来解决上述映射,但这将有其自身的低效率,这将超过在 pitched 上运行的任何性能优势数据。
如果您改用 cudaMalloc
,那么您的数据将是连续的,就像 thrust 期望的那样。
我有一个数据矩阵,我应该使用 GPU(以及可能的推力库)对其进行一些详细说明。到目前为止,我已经能够将数据复制到 GPU 并编写自己的内核函数。现在,根据我的内核函数的输出,我将利用 thrust 库对同一数据矩阵进行其他阐述,尽可能避免从 GPU<->CPU.[= 下载和重新上传数据14=]
因此,我使用 cudaMallocPitch 函数在 GPU 中创建了一个设备变量:
float *d_M;
size_t pitch;
cudaStatus = cudaMallocPitch(&d_M, &pitch, sizeof(float)*(N), M+1);
if (cudaStatus != cudaSuccess)
{
fprintf(stderr, "cudaMalloc Failed!");
INFO;
return CUDA_MALLOC_ERROR;
}
这个变量表示一个维度为 NxM+1 的矩阵。在使用 ad-hoc cuda 函数对 GPU 进行了一些详细说明之后,我将使用 thrust 库对每一行的元素求和,并将结果放在每一行的 M+1 列上。
对于这样的操作,我会使用 thrust 库。 我的意图应该是检索使用 cudaMallocPitch 创建的 raw pointer,将其转换为 thrust::device_ptr 然后操作它使用推力功能。所以,在代码中:
thrust::device_ptr<float> dd_M = thrust::device_pointer_cast(d_M);
但是,当我尝试打印两个变量的地址以确保指针具有相同的地址时:
printf("Address d_M: %p\n", &d_M);
printf("Address dd_M: %p\n", &dd_M);
我得到了不同的地址值。我不知道我做错了什么。对于这样的操作,我只是按照 link Thrust - Memory Management Functions.
的推力手册进行操作cudaMallocPitch
基本上无法使用推力。这是因为它创建了这样的分配:
D D D D D D D D D D D D D D X X
D D D D D D D D D D D D D D X X
D D D D D D D D D D D D D D X X
D D D D D D D D D D D D D D X X
D D D D D D D D D D D D D D X X
...
其中 D
项代表您的实际数据,X
项代表附加到每行的额外 space 以使您的数据宽度与所需的机器间距相匹配。
问题是thrust对X
代表的这个"unused"区域没有概念。当数据中有 "unused" 间隙时,没有 方便的 方法告诉推力函数分配线程(并生成适当的连续索引)。所以如果我们将上面的转换为推力矢量:
D D D D D D D D D D D D D D X X D D D D D D D D D D D D D D X X D D ...
分散在向量中的 X
区域不能方便地 "skipped" 在推力算法和索引中。如果你真的想这样做,可能会想出一个 thrust::permutation_iterator
来解决上述映射,但这将有其自身的低效率,这将超过在 pitched 上运行的任何性能优势数据。
如果您改用 cudaMalloc
,那么您的数据将是连续的,就像 thrust 期望的那样。