【问题标题】:passing intrinsic function as template parameter将内在函数作为模板参数传递
【发布时间】:2018-07-30 02:01:46
【问题描述】:

我正在尝试将 atomicAdd 函数作为模板参数传递给另一个函数。

这是我的 Kernel1:

template<typename T, typename TAtomic>
__global__ void myfunc1(T *address, TAtomic atomicFunc) {
    atomicFunc(address, 1);
}

尝试 1:

myfunc1<<<1,1>>>(val.dev_ptr, atomicAdd);

由于编译器无法匹配预期的函数签名,它不起作用。

尝试 2: 首先,我将 atomicAdd 包装到一个名为 MyAtomicAdd 的自定义函数中。

template<typename T>
__device__ void MyAtomicAdd(T *address, T val) {
    atomicAdd(address, val);
}

然后,我定义了一个名为“TAtomic”的函数指针,并将TAtomic声明为模板参数。

typedef void (*TAtomic)(float *,float);

template<typename T, TAtomic atomicFunc>
__global__ void myfunc2(T *address) {
    atomicFunc(address, 1);
}

myfunc2<float, MyAtomicAdd><<<1,1>>>(dev_ptr);
CUDA_CHECK(cudaDeviceSynchronize());

实际上,尝试 2 个作品。但是,我不想使用 typedef。我需要更通用的东西。

尝试 3: 只需将 MyAtomicAdd 传递给 myfunc1。

myfunc1<<<1,1>>>(dev_ptr, MyAtomicAdd<float>);
CUDA_CHECK(cudaDeviceSynchronize());

编译器可以编译代码。但是我运行程序的时候,报错:

"ERROR in /home/liang/groute-dev/samples/framework/pagerank.cu:70: invalid program counter (76)"

我只是想知道,为什么尝试 3 不起作用?是否存在任何简单或温和的方法来实现此要求?谢谢。

【问题讨论】:

    标签: c++ templates cuda


    【解决方案1】:

    尝试 3 不起作用,因为您试图在主机代码中获取 __device__ 函数的地址,这在 CUDA 中是非法的:

    myfunc1<<<1,1>>>(dev_ptr, MyAtomicAdd<float>);
                              ^
                              effectively a function pointer - address of a __device__ function
    

    在 CUDA 中的这种使用尝试将解析为某种“地址” - 但它是垃圾,因此当您尝试将其用作设备代码中的实际函数入口点时,您会遇到遇到的错误:@987654324 @(或者在某些情况下,只是illegal address)。

    您可以通过将内在函数包装在函子而不是裸 __device__ 函数中来使您的 Try 3 方法工作(没有 typedef):

    $ cat t48.cu
    #include <stdio.h>
    
    template<typename T>
    __device__ void MyAtomicAdd(T *address, T val) {
        atomicAdd(address, val);
    }
    
    
    template <typename T>
    struct myatomicadd
    {
      __device__ T operator()(T *addr, T val){
        return atomicAdd(addr, val);
      }
    };
    
    template<typename T, typename TAtomic>
    __global__ void myfunc1(T *address, TAtomic atomicFunc) {
        atomicFunc(address, (T)1);
    }
    
    
    int main(){
    
      int *dev_ptr;
      cudaMalloc(&dev_ptr, sizeof(int));
      cudaMemset(dev_ptr, 0, sizeof(int));
    //  myfunc1<<<1,1>>>(dev_ptr, MyAtomicAdd<int>);
      myfunc1<<<1,1>>>(dev_ptr, myatomicadd<int>());
      int h = 0;
      cudaMemcpy(&h, dev_ptr, sizeof(int), cudaMemcpyDeviceToHost);
      printf("h = %d\n", h);
      return 0;
    }
    $ nvcc -arch=sm_35 -o t48 t48.cu
    $ cuda-memcheck ./t48
    ========= CUDA-MEMCHECK
    h = 1
    ========= ERROR SUMMARY: 0 errors
    $
    

    我们也可以实现一个稍微简单的版本,让仿函数模板类型从内核模板类型中推断出来:

    $ cat t48.cu
    #include <stdio.h>
    
    struct myatomicadd
    {
    template <typename T>
      __device__ T operator()(T *addr, T val){
        return atomicAdd(addr, val);
      }
    };
    
    template<typename T, typename TAtomic>
    __global__ void myfunc1(T *address, TAtomic atomicFunc) {
        atomicFunc(address, (T)1);
    }
    
    
    int main(){
    
      int *dev_ptr;
      cudaMalloc(&dev_ptr, sizeof(int));
      cudaMemset(dev_ptr, 0, sizeof(int));
      myfunc1<<<1,1>>>(dev_ptr, myatomicadd());
      int h = 0;
      cudaMemcpy(&h, dev_ptr, sizeof(int), cudaMemcpyDeviceToHost);
      printf("h = %d\n", h);
      float *dev_ptrf;
      cudaMalloc(&dev_ptrf, sizeof(float));
      cudaMemset(dev_ptrf, 0, sizeof(float));
      myfunc1<<<1,1>>>(dev_ptrf, myatomicadd());
      float hf = 0;
      cudaMemcpy(&hf, dev_ptrf, sizeof(float), cudaMemcpyDeviceToHost);
      printf("hf = %f\n", hf);
      return 0;
    }
    $ nvcc -arch=sm_35 -o t48 t48.cu
    $ cuda-memcheck ./t48
    ========= CUDA-MEMCHECK
    h = 1
    hf = 1.000000
    ========= ERROR SUMMARY: 0 errors
    $
    

    更多关于CUDA中设备函数指针使用的处理链接this answer

    【讨论】:

    • 我想知道......这个包装器能否通过模板进行概括,以便将单个包装器用于所有设备端功能?即template &lt;typename F, typename... Ts&gt; ?
    猜你喜欢
    • 2017-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-28
    • 2012-06-07
    • 2014-08-02
    • 2012-12-27
    相关资源
    最近更新 更多