如何使用宏或C ++模板在主机和设备代码中都允许可重复使用的代码?

时间:2019-01-09 17:16:50

标签: c++ cuda

我正在用CUDA和C ++编写一个业余raytracer,但遇到了一个我无法得到答案的问题。我已经编写了CPU和GPU代码,以便可以在具有或不具有CUDA功能的设备的机器上执行。但是,这在以下意义上导致了一些代码重复: 一小部分功能需要随机数生成,这可以通过主机上的stdlib和设备上的curand来实现。我很想拥有__host__ __device__函数,该函数采用Sampler结构,可以在主机上调用rand()或在设备上调用curand_uniform()。我已经尝试了一些方法,但是无法使程序进行编译-编译器抱怨无法从__device__代码中调用__host__函数,反之亦然。

理想情况下,我希望渲染函数采用Sampler *,看起来像下面的代码。

谢谢!

struct Sampler {
    __host__ virtual float getNextFloat() { return rand() / (RAND_MAX + 1.f); }
};

struct CudaSampler : Sampler { 
    curandState* p_curandState;
    __device__ float getNextFloat() { return curand_uniform(p_curandState); }
};

1 个答案:

答案 0 :(得分:1)

您所要求的应该是可能的。我们不想尝试通过__host____device__分别重载一个函数(不允许),并且我们不想尝试使用继承和虚函数(虚拟函数表将不能在从主机传递到设备的对象中使用。

但是,如果我们避免这些问题,基本思想是使用__CUDA_ARCH__ nvcc macro来区分编译器的主机路径和设备路径,通常遵循建议的here。 / p>

这是一种可能的方法,大致遵循您的概述:

$ cat t34.cu
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <curand_kernel.h>


struct Sampler {
  __host__ __device__ float operator()(curandState *s){
#ifdef __CUDA_ARCH__
    return curand_uniform(s);
#else
    return rand()/(float)RAND_MAX;
#endif
  }
};

__global__ void init_rng(curandState *state, size_t n){
        size_t idx = threadIdx.x+blockDim.x*blockIdx.x;
        if (idx < n)
          curand_init(1234, idx, 0, state+idx);
}

__global__ void gpu_sample(Sampler s, curandState *state, size_t n){
        size_t idx = threadIdx.x+blockDim.x*blockIdx.x;
        if (idx < n)
                printf("gpu id: %lu, val: %f\n", idx, s(state+idx));
}

__host__  void cpu_sample(Sampler s){
        curandState dummy;
    std::cout << "cpu: " << s(&dummy) << std::endl;
}

int main(){
        int n = 1;
        int nTPB = 256;
        curandState *s;
        Sampler my_op;
        cudaMalloc(&s, n*sizeof(curandState));
        init_rng<<<(n+nTPB-1)/nTPB, nTPB>>>(s,n);
        gpu_sample<<<(n+nTPB-1)/nTPB, nTPB>>>(my_op, s, n);
        cudaDeviceSynchronize();
        cpu_sample(my_op);
}



$ nvcc -o t34 t34.cu
$ cuda-memcheck ./t34
========= CUDA-MEMCHECK
gpu id: 0, val: 0.145468
cpu: 0.840188
========= ERROR SUMMARY: 0 errors
$