C++ 如何有效地将数据从2D主机阵列(带填充)复制到1D设备阵列,并删除CUDA中的原始填充?
主机上有一个带填充的2D列主数组,例如:C++ 如何有效地将数据从2D主机阵列(带填充)复制到1D设备阵列,并删除CUDA中的原始填充?,c++,cuda,C++,Cuda,主机上有一个带填充的2D列主数组,例如: |1 4 7| |2 5 8| A_h = |3 6 9| |x x x| |x x x| 我想将数据作为1D阵列复制到设备内存: {1, 2, 3, 4, 5, 6, 7, 8, 9} //preferred 或 使用CUDA和/或推力实现这一目标的最快有效方法是什么 编辑:我跟随Robert的评论删除了使用推力时的循环,但代码只能复制第一列
|1 4 7|
|2 5 8|
A_h = |3 6 9|
|x x x|
|x x x|
我想将数据作为1D阵列复制到设备内存:
{1, 2, 3, 4, 5, 6, 7, 8, 9} //preferred
或
使用CUDA和/或推力实现这一目标的最快有效方法是什么
编辑:我跟随Robert的评论删除了使用推力时的循环,但代码只能复制第一列。如何在不使用循环的情况下使其适用于整个阵列
thrust::counting_iterator<int> first(0);
thrust::counting_iterator<int> last = first + rows;
thrust::device_vector<real_type> A_d(rows * cols);
thrust::copy(thrust::make_permutation_iterator(A_h, first),
thrust::make_permutation_iterator(A_h, last), A_d.begin());
推力::首先计算迭代器(0);
推力::计数迭代器最后一次=第一次+行;
推力:设备矢量A\u d(行*cols);
推力::复制(推力::生成置换迭代器(A_h,第一),
推力::生成置换迭代器(A_h,last),A_d.begin();
如果用例只是将一个较大源的子集复制到一个较小的目的地,而这个目的地没有跨步(如此连续),那么一个带有谓词的条件复制可能是最简单的方法(我猜gather也会起作用)。大概是这样的:
#include <vector>
#include <iostream>
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <thrust/iterator/counting_iterator.h>
struct indexer
{
int lda0;
int lda1;
indexer() = default;
__device__ __host__
indexer(int l0, int l1) : lda0(l0), lda1(l1) {};
__device__ __host__
bool operator()(int x) {
int r = x % lda0;
return (r < lda1);
};
};
int main()
{
const int M0 = 5, N=3;
const int M1 = 3;
const int len1 = M1*N;
{
std::vector<int> data{ 1, 2, 3, -1, -1, 4, 5, 6, -1, -1, 7, 8, 9, -1, -1 };
thrust::device_vector<int> ddata = data;
thrust::device_vector<int> doutput(len1);
indexer pred(M0, M1);
thrust::counting_iterator<int> idx(0);
thrust::copy_if(ddata.begin(), ddata.end(), idx, doutput.begin(), pred);
for(int i=0; i<len1; i++) {
int val = doutput[i];
std::cout << i << " " << val << std::endl;
}
}
return 0;
}
如果您想要更一般的东西(如此快速的输入和输出),那么您可能会使用与
scatter\u If
相同的想法。正如注释中所指出的,这可以通过cudaMemcpy2D
或一个拷贝内核来完成。没有办法直接完成。最简单的方法是使用cudaMemcpy2D
,其中cuda
标签上有许多问题。最快的方法可能是在主机上重新格式化阵列,然后执行“普通”cudaMemcpy(或推力复制)。如果不知道数组和填充的确切大小,就不可能确定什么是最快的方法。另一个常见的建议是使用cudaMemcpy
按原样发送数组,然后在设备代码中重新格式化(使用内核,或者按原样使用)。嗨,罗伯特,谢谢你的回复。假设矩阵A的大小为N×M,主机填充为64字节。你能详细说明一下“然后用设备代码重新格式化”吗?我已经知道你的矩阵的大小是N×M。如果你写的是纯主机代码,你想把这个矩阵从填充的重新格式化为未添加的,你知道怎么做吗?如果是这样的话,那么编写一个CUDA内核来做同样的事情。这将是一个非常简单的CUDA内核。您正在将数据从填充的输入数组复制到未添加的输出数组。您可以在主机端或设备端执行此操作。根据N和M的实际值,一种方法可能优于另一种方法。如果没有基准测试,可能无法确定。是的,我已经编写了一个代码,使用推力删除填充,但它与宿主代码非常相似:循环每列并将数据复制到行。我以为你在回复中提出了一个新的算法来“在设备代码中重新格式化”,这样我就可以学习了。谢谢。理想情况下,您永远不会在推力代码中编写循环。通过置换迭代器
和对推力::复制
的单个调用,可以完成从填充到未添加的推力复制操作。不需要循环。在您的回答中,如果有5个参数(并且没有策略),请复制。这是个错误吗?不,不是。向下滚动…明白了吗
#include <vector>
#include <iostream>
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <thrust/iterator/counting_iterator.h>
struct indexer
{
int lda0;
int lda1;
indexer() = default;
__device__ __host__
indexer(int l0, int l1) : lda0(l0), lda1(l1) {};
__device__ __host__
bool operator()(int x) {
int r = x % lda0;
return (r < lda1);
};
};
int main()
{
const int M0 = 5, N=3;
const int M1 = 3;
const int len1 = M1*N;
{
std::vector<int> data{ 1, 2, 3, -1, -1, 4, 5, 6, -1, -1, 7, 8, 9, -1, -1 };
thrust::device_vector<int> ddata = data;
thrust::device_vector<int> doutput(len1);
indexer pred(M0, M1);
thrust::counting_iterator<int> idx(0);
thrust::copy_if(ddata.begin(), ddata.end(), idx, doutput.begin(), pred);
for(int i=0; i<len1; i++) {
int val = doutput[i];
std::cout << i << " " << val << std::endl;
}
}
return 0;
}
$ nvcc -arch=sm_52 -std=c++11 -o subset subset.cu
$ ./subset
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9