在gpu上的数组上做push :: min_element

时间:2015-10-21 14:41:57

标签: cuda gpu thrust

我试图找到gpu上最小的数组。我可以在cpu上的东西上使用min_element,但不知道如何在gpu上的东西上做。另外我很困惑为什么min_element的返回必须是一个数组,因为只有一个最小值?这是我认为最接近的,但我得到: '错误:没有合适的转换函数来自" thrust :: device_ptr" to" double *"存在'对于min_element行。

代码:

#include <stdio.h>
#include <stdlib.h> /* for rand() */
#include <unistd.h> /* for getpid() */
#include <time.h> /* for time() */
#include <math.h>
#include <assert.h>
#include <iostream>
#include <ctime>
#include <thrust/scan.h>
#include <thrust/device_ptr.h>
#include <thrust/reduce.h>
#include <thrust/extrema.h>
#include <cuda.h>

using namespace std;

bool errorAsk(const char *s="n/a")
{
cudaError_t err=cudaGetLastError();
if(err==cudaSuccess)
    return false;
printf("CUDA error [%s]: %s\n",s,cudaGetErrorString(err));
return true;
};

double *fillArray(double *c_idata,int N,double constant) {
    int n;
    for (n = 0; n < N; n++) {
            c_idata[n] = constant*floor(drand48()*10);

    }
return c_idata;
}

int main(int argc,char *argv[])
{
    int N;
    N = 100;

    double *c_data,*g_data,*result;
    result = new double[N];

    c_data = new double[N];
    c_data = fillArray(c_data,N,1);

    cudaMalloc(&g_data,N*sizeof(double));
    cudaMemcpy(g_data,c_data,N*sizeof(double),cudaMemcpyHostToDevice);
    thrust::device_ptr<double> g_ptr =  thrust::device_pointer_cast(g_data);

    result = thrust::min_element(g_ptr, g_ptr + N); // not sure how to get this to work
//        result = thrust::max_element(c_data, c_data + N); //works but I need to do this on the gpu

    cudaMemcpy(c_data,g_data,N*sizeof(double),cudaMemcpyDeviceToHost);

    cout<<result[0]<<endl;
}

1 个答案:

答案 0 :(得分:4)

thrust::min_element返回迭代器

来自documentation

  

min_element找到范围[first,last]中的最小元素。它返回[first,last]中的第一个迭代器 i,这样[first,last]中的其他迭代器都没有指向小于* i的值。

迭代器就像一个指针。它表示元素在容器中的位置。像指针一样,迭代器可以添加到,减去等等。

所以我们可以直接提取这个迭代器:

thrust::device_ptr<double> result_position = thrust::min_element(...

或另一种方法是从容器的起点获得该位置的相对偏移量:

int result_offset = thrust::min_element(g_ptr, ...) - g_ptr;

这是有效的,因为可以减去迭代器(或thrust::device_ptr)。从min_element返回的迭代器减去容器的开头将给出最小元素位置的偏移量。

以下是基于您的代码的实用示例:

$ cat t957.cu
#include <stdio.h>
#include <stdlib.h> /* for rand() */
#include <iostream>
#include <thrust/device_ptr.h>
#include <thrust/extrema.h>

using namespace std;

bool errorAsk(const char *s="n/a")
{
cudaError_t err=cudaGetLastError();
if(err==cudaSuccess)
    return false;
printf("CUDA error [%s]: %s\n",s,cudaGetErrorString(err));
return true;
};

double *fillArray(double *c_idata,int N,double constant) {
    int n;
    for (n = 0; n < N; n++) {
            c_idata[n] = constant*floor(drand48()*10.0);

    }
return c_idata;
}

int main(int argc,char *argv[])
{
    int N;
    N = 100;

    double *c_data,*g_data;
//    result = new double[N];

    c_data = new double[N];
    c_data = fillArray(c_data,N,1.0);
    c_data[32] = -1.0;
    cudaMalloc(&g_data,N*sizeof(double));
    cudaMemcpy(g_data,c_data,N*sizeof(double),cudaMemcpyHostToDevice);
    thrust::device_ptr<double> g_ptr =  thrust::device_pointer_cast(g_data);

    int result_offset = thrust::min_element(g_ptr, g_ptr + N) - g_ptr;

    double min_value = *(g_ptr + result_offset);
    // we could also do this:
    // double min_value = c_data[result_offset];
    std::cout<< "min value found at position: " << result_offset << " value: " << min_value << std::endl;
}
$ nvcc -o t957 t957.cu
$ ./t957
min value found at position: 32 value: -1
$

thrust quick start guide简要介绍了迭代器及其在推力中的用法。