使用CUDA中的减少来查找数组中的最小值(但跳过一些元素)

时间:2014-03-31 12:11:39

标签: c++ c cuda reduce minimum

我有一大堆浮点数,我希望使用CUDA中的减少来找出数组的最小值(忽略存在的-1)及其索引。我已经编写了以下代码来执行此操作,在我看来应该可以工作:

 __global__ void get_min_cost(float *d_Cost,int n,int *last_block_number,int *number_in_last_block,int *d_index){
     int tid = threadIdx.x;
     int myid = blockDim.x * blockIdx.x + threadIdx.x;
     int s;

     if(result == (*last_block_number)-1){
         s = (*number_in_last_block)/2;
     }else{
         s = 1024/2;
     }

     for(;s>0;s/=2){
         if(myid+s>=n)
             continue;
         if(tid<s){
             if(d_Cost[myid+s] == -1){
                 continue;
             }else if(d_Cost[myid] == -1 && d_Cost[myid+s] != -1){
                 d_Cost[myid] = d_Cost[myid+s];
                 d_index[myid] = d_index[myid+s];
             }else{
                 // both not -1
                 if(d_Cost[myid]<=d_Cost[myid+s])
                     continue;
                 else{
                     d_Cost[myid] = d_Cost[myid+s];
                     d_index[myid] = d_index[myid+s];
                 }
             }
         }
         else
             continue;
         __syncthreads();
     }
     if(tid==0){
         d_Cost[blockIdx.x] = d_Cost[myid];
         d_index[blockIdx.x] = d_index[myid];
     }
     return;
 }

last_block_number参数是最后一个块的id,number_in_last_block是最后一个块中的元素数(2的幂)。因此,所有块每次都会启动1024个线程,最后一个块只使用number_in_last_block个线程,而其他块将使用1024个线程。

此函数运行后,我希望每个块的最小值都在d_Cost[blockIdx.x],其索引在d_index[blockIdx.x]

我多次调用此函数,每次更新线程和块的数量。第二次调用此函数时,线程数现在等于剩余的块数等。

但是,上述功能并没有给我所需的输出。实际上,每次运行程序时它都会给出不同的输出,即在一些中间迭代期间它返回一个不正确的值作为最小值(尽管每次不正确的值非常接近最小值)。

我在这里做错了什么?

1 个答案:

答案 0 :(得分:2)

正如我在上面的评论中所提到的,我建议尽可能避免编写自己的缩减并使用CUDA Thrust。即使在您需要自定义这些操作的情况下也是如此,通过适当的重载可以实现自定义,例如关系操作。

下面我提供一个简单的代码来评估数组中的最小值及其索引。它基于An Introduction to Thrust演示文稿中包含的经典示例。唯一的补充是按照您的要求跳过计数中的-1。这可以通过用-1替换数组中的所有INT_MAX来合理地完成,即根据IEEE浮点标准的最大可表示整数。

#include <thrust\device_vector.h>
#include <thrust\replace.h>
#include <thrust\sequence.h>
#include <thrust\reduce.h>
#include <thrust\iterator\zip_iterator.h>
#include <thrust\tuple.h>

// --- Struct returning the smallest of two tuples
struct smaller_tuple
{
    __host__ __device__ thrust::tuple<int,int> operator()(thrust::tuple<int,int> a, thrust::tuple<int,int> b)
    {
        if (a < b)
            return a;
        else
            return b;
    }
};


void main() {

    const int N = 20;
    const int large_value = INT_MAX;

    // --- Setting the data vector
    thrust::device_vector<int> d_vec(N,10);
    d_vec[3] = -1; d_vec[5] = -2;

    // --- Copying the data vector to a new vector where the -1's are changed to FLT_MAX
    thrust::device_vector<int> d_vec_temp(d_vec);
    thrust::replace(d_vec_temp.begin(), d_vec_temp.end(), -1, large_value);

    // --- Creating the index sequence [0, 1, 2, ... )
    thrust::device_vector<int> indices(d_vec_temp.size());
    thrust::sequence(indices.begin(), indices.end());

    // --- Setting the initial value of the search
    thrust::tuple<int,int> init(d_vec_temp[0],0);

    thrust::tuple<int,int> smallest;
    smallest = thrust::reduce(thrust::make_zip_iterator(thrust::make_tuple(d_vec_temp.begin(), indices.begin())),
                          thrust::make_zip_iterator(thrust::make_tuple(d_vec_temp.end(), indices.end())),
                          init, smaller_tuple());

    printf("Smallest %i %i\n",thrust::get<0>(smallest),thrust::get<1>(smallest));
    getchar();
}