假设我们有这个排序数组
0 1 1 1 1 2 2 2 2 2 3 10 10 10
我想有效地找到元素变化的位置。例如,在我们的数组中,位置如下:
0 1 5 10 11
我知道有一些库(推力)可以实现这一点,但是我想为教育目的创建自己的有效实现。
你可以在这里找到整个代码:http: //pastebin.com/Wu34F4M2
它也包括验证。
内核是以下函数:
__global__ void findPositions(int *device_data,
int totalAmountOfValuesPerThread, int* pos_ptr, int N){
int res1 = 9999999;
int res2 = 9999999;
int index = totalAmountOfValuesPerThread*(threadIdx.x +
blockIdx.x*blockDim.x);
int start = index; //from this index each thread will begin searching
if(start < N){ //if the index is out of bounds do nothing
if(start!=0){ //if start is not in the beginning, check the previous value
if(device_data[start-1] != device_data[start]){
res1 = start;
}
}
else res1 = start; //since it's the
//beginning we update the first output buffer for the thread
pos_ptr[index] = res1;
start++; //move to the next place and see if the
//second output buffer needs updating or not
if(start < N && device_data[start] != device_data[start-1]){
res2 = start;
}
if((index+1) < N)
pos_ptr[index+ 1] = res2;
}
}
我创建了这么多线程,因此每个线程都必须处理数组的两个值。
device_data
将所有数字存储在数组中totalAmountOfValuesPerThread
在这种情况下,是每个线程必须使用的值的总量pos_ptr
具有相同的长度device_data
,每个线程将缓冲区的结果写入此device_vector
N
device_data
是数组中数字的总数
在调用的输出缓冲区中res1
,res2
每个线程要么保存以前未找到的位置,要么保持原样。
例子:
0 <---- thread 1
1
1 <---- thread 2
1
2 <---- thread 3
2
3 <---- thread 4
每个线程的输出缓冲区,假设大数 9999999 是inf
:
thread1 => {res1=0, res2=1}
thread2 => {res1=inf, res2=inf}
thread3 => {res1=4, res2=inf}
thread4 => {res1=6, res2=inf}
每个线程都会更新 ,pos_ptr
device_vector
因此该向量将具有以下结果:
pos_ptr =>{0, 1, inf, inf, 4, inf, 6, inf}
完成内核后,我使用库对向量进行排序,Thrust
并将结果保存在名为host_pos
. 所以host_pos
向量将具有以下内容:
host_pos => {0, 1, 4, 6, inf, inf, inf, inf}
这个实现很糟糕,因为
- 内核内部创建了很多分支,因此会出现低效的换行处理
- 我假设每个线程仅使用 2 个值,这是非常低效的,因为创建了太多线程
- 我创建并传输一个
device_vector
与输入一样大并且驻留在全局内存中的 a。每个线程访问这个向量以便写入结果,这是非常低效的。
1 000 000
这是每个块中有512
线程时输入大小的测试用例。
CPU time: 0.000875688 seconds
GPU time: 1.35816 seconds
另一个输入大小的测试用例10 000 000
CPU time: 0.0979209
GPU time: 1.41298 seconds
请注意,CPU 版本几乎慢了 100 倍,而 GPU 几乎相同。
不幸的是我的GPU没有足够的内存,所以让我们尝试一下50 000 000
CPU time: 0.459832 seconds
GPU time: 1.59248 seconds
据我了解,对于大量输入,我的 GPU 实现可能会变得更快,但是我相信更有效的方法可能会使实现更快,即使对于较小的输入也是如此。
为了让我的算法运行得更快,你会建议什么设计?不幸的是,我想不出更好的办法。
先感谢您