GPU CUDA推力

我有一个Cuda C ++代码,它使用目前在单个GPU上正常工作的Thrust。 我现在想修改它为多GPU。 我有一个主机功能,其中包括一些Thrust调用,用于对设备阵列进行排序,复制和计算差异等。 我想要使​​用每个GPU同时在自己的(独立)阵列集上运行这个Thrust调用序列。 我读过Thrust函数的返回值是同步的,但我可以使用OpenMP让每个主机线程调用一个在独立GPU上运行的函数(使用Thrust调用)?

例如(用浏览器编码):

#pragma omp parallel for 
for (int dev=0; dev<Ndev; dev++){
   cudaSetDevice(dev);
   runthrustfunctions(dev);
}

void runthrustfunctions(int dev){
  /*lots of Thrust functions running on device arrays stored on corresponding GPU*/
 //for example this is just a few of the lines"

 thrust::device_ptr<double> pos_ptr = thrust::device_pointer_cast(particle[dev].pos);
 thrust::device_ptr<int> list_ptr = thrust::device_pointer_cast(particle[dev].list);
 thrust::sequence(list_ptr,list_ptr+length);
 thrust::sort_by_key(pos_ptr, pos_ptr+length,list_ptr);
 thrust::device_vector<double> temp(length);
 thrust::gather(list_ptr,list_ptr+length,pos_ptr,temp.begin());   
 thrust::copy(temp.begin(), temp.end(), pos_ptr);

}`

我认为我还需要在GPU 0上存储结构“particle [0]”,在GPU 1上存储particle [1]等等,我猜测这是不可能的。 一个选项可能是针对每个GPU情况使用“开关”和单独的代码。

我想知道这是一种正确的方法,还是有更好的方法? 谢谢


是的,你可以结合推力和OpenMP。

以下是一个完整的结果示例:

$ cat t340.cu
#include <omp.h>
#include <stdio.h> 
#include <stdlib.h>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/copy.h>
#include <time.h>
#include <sys/time.h>

#define DSIZE 200000000

using namespace std;

int main(int argc, char *argv[])
{
    timeval t1, t2;
    int num_gpus = 0;   // number of CUDA GPUs

    printf("%s Starting...nn", argv[0]);

    // determine the number of CUDA capable GPUs
    cudaGetDeviceCount(&num_gpus);

    if (num_gpus < 1)
    {
        printf("no CUDA capable devices were detectedn");
        return 1;
    }

    // display CPU and GPU configuration
    printf("number of host CPUs:t%dn", omp_get_num_procs());
    printf("number of CUDA devices:t%dn", num_gpus);

    for (int i = 0; i < num_gpus; i++)
    {
        cudaDeviceProp dprop;
        cudaGetDeviceProperties(&dprop, i);
        printf("   %d: %sn", i, dprop.name);
    }

    printf("initialize datan");


    // initialize data
    typedef thrust::device_vector<int> dvec;
    typedef dvec *p_dvec;
    std::vector<p_dvec> dvecs;

    for(unsigned int i = 0; i < num_gpus; i++) {
      cudaSetDevice(i);
      p_dvec temp = new dvec(DSIZE);
      dvecs.push_back(temp);
      }

    thrust::host_vector<int> data(DSIZE);
    thrust::generate(data.begin(), data.end(), rand);

    // copy data
    for (unsigned int i = 0; i < num_gpus; i++) {
      cudaSetDevice(i);
      thrust::copy(data.begin(), data.end(), (*(dvecs[i])).begin());
      }

    printf("start sortn");
    gettimeofday(&t1,NULL);

    // run as many CPU threads as there are CUDA devices
    omp_set_num_threads(num_gpus);  // create as many CPU threads as there are CUDA devices
    #pragma omp parallel
    {
        unsigned int cpu_thread_id = omp_get_thread_num();
        cudaSetDevice(cpu_thread_id);
        thrust::sort((*(dvecs[cpu_thread_id])).begin(), (*(dvecs[cpu_thread_id])).end());
        cudaDeviceSynchronize();
    }
    gettimeofday(&t2,NULL);
    printf("finishedn");
    unsigned long et = ((t2.tv_sec * 1000000)+t2.tv_usec) - ((t1.tv_sec * 1000000) + t1.tv_usec);
    if (cudaSuccess != cudaGetLastError())
        printf("%sn", cudaGetErrorString(cudaGetLastError()));
    printf("sort time = %fsn", (float)et/(float)(1000000));
    // check results
    thrust::host_vector<int> result(DSIZE);
    thrust::sort(data.begin(), data.end());
    for (int i = 0; i < num_gpus; i++)
    {
        cudaSetDevice(i);
        thrust::copy((*(dvecs[i])).begin(), (*(dvecs[i])).end(), result.begin());
        for (int j = 0; j < DSIZE; j++)
          if (data[j] != result[j]) { printf("mismatch on device %d at index %d, host: %d, device: %dn", i, j, data[j], result[j]); return 1;}
    }
    printf("Successn");
    return 0;

}
$ nvcc -Xcompiler -fopenmp -O3 -arch=sm_20 -o t340 t340.cu -lgomp
$ CUDA_VISIBLE_DEVICES="0" ./t340
./t340 Starting...

number of host CPUs:    12
number of CUDA devices: 1
   0: Tesla M2050
initialize data
start sort
finished
sort time = 0.398922s
Success
$ ./t340
./t340 Starting...

number of host CPUs:    12
number of CUDA devices: 4
   0: Tesla M2050
   1: Tesla M2070
   2: Tesla M2050
   3: Tesla M2070
initialize data
start sort
finished
sort time = 0.460058s
Success
$

我们可以看到,当我将程序限制为使用单个设备时,排序操作大约需要0.4秒。 然后,当我允许它使用全部4个设备(在所有4个设备上重复相同的排序)时,整个操作只需要0.46秒,即使我们做了4倍的工作。

对于这种特殊情况,我碰巧使用CUDA 5.0,推力v1.7和gcc 4.4.6(RHEL 6.2)

链接地址: http://www.djcxy.com/p/47421.html

上一篇: gpu CUDA Thrust

下一篇: Multiple processes launching CUDA kernels in parallel