我有一些用于合并两个排序数组的C代码:
void merge(int m, int n, int A[], int B[], int C[]) {
int i, j, k;
i = 0;
j = 0;
k = 0;
while (i < m && j < n) {
if (A[i] <= B[j]) {
C[k] = A[i];
i++;
} else {
C[k] = B[j];
j++;
}
k++;
}
if (i < m) {
for (int p = i; p < m; p++) {
C[k] = A[p];
k++;
}
} else {
for (int p = j; p < n; p++) {
C[k] = B[p];
k++;
}
}
}
我想将合并部分放到OpenCL内核中,最好的方法是什么?或者将两个排序数组与OpenCL合并的最佳方法是什么?
答案 0 :(得分:3)
如果你的阵列的长度是2的相同,你可以我们进行bitonic排序。从最后的蝴蝶步骤(wiki链接中蓝色/棕色图的最后一个块)开始,你将使gpu饱和,同时充分利用设备的内存速度。如果阵列接近2的幂,您也可以填充阵列。我用这种方法成功地对数百万(例如2 ^ 20 .. 2 ^ 24)条目的列表进行了排序。 请参阅:'Bitonic Sorter' Wiki
如果每个数组中有任意数量的元素,则在处理已排序的两个列表时,可能不值得传输时间。这是因为您一次只比较两个值,并将其中一个值移动到结果列表中。这是对gpu的一种可怕的使用,因为你基本上是单线程的。优化可能是将每个源阵列的前4-8kb加载到本地内存中,然后将已排序的块写入本地内存。您仍然只使用整个gpu的一个计算单元,但内存速度会很快。再说一次,可能不值得麻烦。当合并任意长度的排序数组时,你的cpu L1和L2数据缓存以及出色的时钟速度应该优于gpu。
答案 1 :(得分:0)
最简单的方法是创建三个缓冲区A,B和C,然后调用两个clEnqueueCopyBuffer(),如下所示:
clEnqueueCopyBuffer( cmdQueue, A, C, 0, 0, m, 0, NULL, NULL );
clEnqueueCopyBuffer( cmdQueue, B, C, 0, m, n, 0, NULL, NULL );
如果你想要一个天真的内核来做,它将起作用:
__kernel void merge(int m, __global const int* A, __global const int* B, _global int* C )
{
int id= (int)get_global_id(0);
if( id<m )
{
C[id]=A[id];
}
else
{
C[id]=B[id-m];
}
}
这个内核没有优化。根据设备的不同,有许多方法可以优化。