使用库传递CUDA函数指针

时间:2014-03-05 15:57:38

标签: cuda linker nvcc

我正在使用CUDA并尝试使用函数指针将CUDA函数传递给稍后在其设备内核中使用此函数的库,类似于CUDA函数指针示例。

代码的重要部分是:

/** Type definition for the execution function in #qsched_run. */
typedef void (*qsched_funtype)( int , void * );

__device__ void gpuTest(int type , void *data)
{
  ....
}
__device__ qsched_funtype function = gpuTest;

void main(...)
{
//Various initialization setup.

if( cudaMemcpyFromSymbol( &func , function , sizeof(qsched_funtype) ) != cudaSuccess)
    error("Failed to copy function pointer from device");

qsched_run_CUDA( &s , func );
}

qsched_run_CUDA函数是一个库函数,它执行一些初始化,将函数指针复制到设备(它可以看到的变量),然后运行一个内核,在某些点使用该函数指针调用gpuTest函数。

代码编译正确,前提是我使用-G和以下nvcc调用:

nvcc -g -G -m64 -I../src ../src/.libs/libquicksched_cuda.a -L/home/aidan/cuda_6.0/lib -L/home/aidan/cuda_6.0/lib64 -lcudart -lcuda -DWITH_CUDA -gencode arch=compute_30,code=sm_30 -lgomp test_gpu_simple.cu -o out.out

,其中

../src/.libs/libquicksched_cuda.a

是包含qsched_run_CUDA函数的库。

当我从我的nvcc调用中删除-G标志然后突然全部中断,并且qsched_run_CUDA中运行的内核因 无效程序计数器 错误而崩溃,并且函数指针(包括在我自己的.cu文件中)设置为0x4。

据推测,我需要在http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#using-separate-compilation-in-cuda中隐约解释使用CUDA中的单独编译(Cuda function pointer consistency) - 但是我不确定如何在使用库函数时这样做,既不是nvcc的指南也不是stackoverflow链接明确了如何做到这一点。

有没有人有这方面的经验?我试图简单地尝试使用nvlink来做到这一点,但是我没有做得很远(我把它传给了一个库似乎并不高兴。)

1 个答案:

答案 0 :(得分:3)

是的,您需要使用单独的编译。我根据您到目前为止所展示的内容整理了一个简单的测试用例,并使用文档中的nvcc separate compilation library example。这是代码:

kernel_lib.cu:

#include <stdio.h>

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)

/** Type definition for the execution function in #qsched_run. */
typedef void (*qsched_funtype)( int , void * );

__global__ void mykernel(int type, void *data, void *func){
  ((qsched_funtype)func)(type, data);
}

int qsched_run_CUDA(int val, void *d_data, void *func)
{
  mykernel<<<1,1>>>(val, d_data, func);
  cudaDeviceSynchronize();
  cudaCheckErrors("kernel fail");
  return 0;
}

main.cu:

#include <stdio.h>
#define DATA_VAL 5

int qsched_run_CUDA(int, void*, void*);

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)

/** Type definition for the execution function in #qsched_run. */
typedef void (*qsched_funtype)( int , void * );

__device__ void gpuTest(int type , void *data)
{
  ((int *)data)[0] = type;
}
__device__ qsched_funtype function = gpuTest;


int main()
{
  void *func;
  cudaMemcpyFromSymbol( &func , function , sizeof(qsched_funtype));
  cudaCheckErrors("Failed to copy function pointer from device");
  int h_data = 0;
  int *d_data;
  cudaMalloc((void **)&d_data, sizeof(int));
  cudaCheckErrors("cudaMalloc fail");
  cudaMemset(d_data, 0, sizeof(int));
  cudaCheckErrors("cudaMemset fail");
  int return_val = qsched_run_CUDA(DATA_VAL, (void *)d_data, func);
  if (return_val != 0) printf("return code error\n");
  cudaMemcpy(&h_data, d_data, sizeof(int), cudaMemcpyDeviceToHost);
  cudaCheckErrors("cudaMemcpy fail");
  if (h_data != DATA_VAL) {printf("Fail! %d\n", h_data); return 1;}
  printf("Success!\n");
  return 0;
}

编译命令和结果:

$ nvcc -arch=sm_20 -dc kernel_lib.cu
$ nvcc -lib kernel_lib.o -o test.a
$ nvcc -arch=sm_20 -dc main.cu
$ nvcc -arch=sm_20 main.o test.a -o test
$ ./test
Success!
$

我使用CUDA 5.0进行此测试。