使用OpenCL合并两个已排序的数组

时间:2013-05-13 21:49:17

标签: c opencl

我有一些用于合并两个排序数组的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合并的最佳方法是什么?

2 个答案:

答案 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];
    }
}

这个内核没有优化。根据设备的不同,有许多方法可以优化。