假设我有一个包含所有不同数字A[4000]
[45,21,764,234,7,0,12,55,...]
然后我有另一个数组B[4000]
,表示数组A
中区域的位置,如果它是区域的一部分,则为1
,如果0
,则为1's
它不是。如果0
彼此相邻,这意味着它们属于同一地区,如果它们不是彼此相邻(1's
之间有B = [1,1,1,0,1,1,0,0...]
),那么是不同地区的一部分。
离。 first three numbers in array A
表示我想要找到5th and 6th numbers in array A, etc.
区域中的最大值,以及C[4000]
中的最大值
这样我就可以生成一个数组A
,在B
表示的每个区域中保存0
的最大值,而在不属于的区域中保存C = [764,764,764,0,7,7,0,0...]
区域。
所以在这种情况下0 to 2,000 regions
2 to 4,000 numbers long
可以有任何地方,区域的长度可以从4000
开始。我事先不知道有多少地区或地区的大小不同。
我一直试图在CUDA中提出一个可以实现这个结果的内核。它需要尽可能快地完成,因为它实际上它将用于图像,这只是一个简化的例子。我的所有想法,例如使用缩减,只有在只有一个区域跨越所有A
个数组1
的情况下才有效。但是,我不认为我可以在这里使用缩减,因为阵列中可能有多个区域被3996
分隔为0's
个空格(int intR = 0;
while(B[blockIdx.x * blockDim.x + threadIdx.x + intR] > 0){
intMaxR = intMaxR < A[blockIdx.x * blockDim.x + threadIdx.x + intR] ? A[blockIdx.x * blockDim.x + threadIdx.x + intR] : intMaxR;
intR++;
}
int intL = 0;
while(B[blockIdx.x * blockDim.x + threadIdx.x - intL] > 0){
intMaxL = intMaxL < A[blockIdx.x * blockDim.x + threadIdx.x - intL] ? A[blockIdx.x * blockDim.x + threadIdx.x + intL] : intMaxL;
intL++;
}
intMax = intMaxR > intMaxL ? intMaxR : intMaxL;
for(int i = 0; i < intR; i++){
C[blockIdx.x * blockDim.x + threadIdx.x + i] = intMax;
}
for(int i = 0; i < intL; i++){
C[blockIdx.x * blockDim.x + threadIdx.x - i] = intMax;
}
),并且缩减将导致我松散轨道分开的地区。或者,内核中有太多的循环,而if中的语句要快,例如
{{1}}
显然,即使使用共享内存,代码也很慢,并且并没有真正利用CUDA的并行特性。有没有人知道如何在CUDA中有效地完成这项工作?
提前致谢。
答案 0 :(得分:2)
一种可能的方法是使用thrust。
可能的顺序是这样的:
这是一个完整工作的代码,使用A和B向量来证明这一点:
#include <iostream>
#include <thrust/device_vector.h>
#include <thrust/adjacent_difference.h>
#include <thrust/reduce.h>
#include <thrust/copy.h>
#include <thrust/transform_scan.h>
#include <thrust/iterator/discard_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/functional.h>
#define DSIZE 8
template <typename T>
struct abs_val : public thrust::unary_function<T, T>
{
__host__ __device__
T operator()(const T& x) const
{
if (x<0) return -x;
else return x;
}
};
template <typename T>
struct subtr : public thrust::unary_function<T, T>
{
const T val;
subtr(T _val): val(_val) {}
__host__ __device__
T operator()(const T& x) const
{
return x-val;
}
};
int main(){
int A[DSIZE] = {45,21,764,234,7,0,12,55};
int B[DSIZE] = {1,1,1,0,1,1,0,0};
thrust::device_vector<int> dA(A, A+DSIZE);
thrust::device_vector<int> dB(B, B+DSIZE);
thrust::device_vector<int> dRed(DSIZE);
thrust::device_vector<int> diffB(DSIZE);
thrust::device_vector<int> dRes(DSIZE);
thrust::reduce_by_key(dB.begin(), dB.end(), dA.begin(), thrust::make_discard_iterator(), dRed.begin(), thrust::equal_to<int>(), thrust::maximum<int>());
thrust::adjacent_difference(dB.begin(), dB.end(), diffB.begin());
thrust::transform_inclusive_scan(diffB.begin(), diffB.end(), diffB.begin(), abs_val<int>(), thrust::plus<int>());
thrust::gather_if(thrust::make_transform_iterator(diffB.begin(), subtr<int>(B[0])), thrust::make_transform_iterator(diffB.end(), subtr<int>(B[0])), dB.begin(), dRed.begin(), dRes.begin());
thrust::copy(dRes.begin(), dRes.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}
关于示例的说明:
以上代码应生成与您所需的C
输出向量匹配的结果,如下所示:
$ nvcc -arch=sm_20 -o t53 t53.cu
$ ./t53
764 764 764 0 7 7 0 0
$
我们可以使用thrust::placeholders进一步简化上述代码,无需额外的仿函数定义:
#include <iostream>
#include <thrust/device_vector.h>
#include <thrust/adjacent_difference.h>
#include <thrust/reduce.h>
#include <thrust/copy.h>
#include <thrust/transform_scan.h>
#include <thrust/iterator/discard_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/functional.h>
#define DSIZE 2000000
using namespace thrust::placeholders;
typedef int mytype;
int main(){
mytype *A = (mytype *)malloc(DSIZE*sizeof(mytype));
int *B = (int *)malloc(DSIZE*sizeof(int));
for (int i = 0; i < DSIZE; i++){
A[i] = (rand()/(float)RAND_MAX)*10.0f;
B[i] = rand()%2;}
thrust::device_vector<mytype> dA(A, A+DSIZE);
thrust::device_vector<int> dB(B, B+DSIZE);
thrust::device_vector<mytype> dRed(DSIZE);
thrust::device_vector<int> diffB(DSIZE);
thrust::device_vector<mytype> dRes(DSIZE);
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start);
thrust::reduce_by_key(dB.begin(), dB.end(), dA.begin(), thrust::make_discard_iterator(), dRed.begin(), thrust::equal_to<mytype>(), thrust::maximum<mytype>());
thrust::adjacent_difference(dB.begin(), dB.end(), diffB.begin());
thrust::transform_inclusive_scan(diffB.begin(), diffB.end(), diffB.begin(), _1*_1, thrust::plus<int>());
thrust::gather_if(thrust::make_transform_iterator(diffB.begin(), _1 - B[0]), thrust::make_transform_iterator(diffB.end(), _1 - B[0]), dB.begin(), dRed.begin(), dRes.begin());
cudaEventRecord(stop);
cudaEventSynchronize(stop);
float et;
cudaEventElapsedTime(&et, start, stop);
std::cout<< "elapsed time: " << et << "ms " << std::endl;
thrust::copy(dRes.begin(), dRes.begin()+10, std::ostream_iterator<mytype>(std::cout, " "));
std::cout << std::endl;
return 0;
}
(我已修改上述占位符代码,还包括生成更大尺寸的数据集,以及一些基本的计时设备。)