【发布时间】:2017-05-13 20:53:23
【问题描述】:
我在尝试让 CUDA 程序按索引管理 lambda 数组时遇到了麻烦。重现问题的示例代码
#include <cuda.h>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <cassert>
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true){
if (code != cudaSuccess) {
fprintf(stderr,"GPUassert: %s %s %d\n",
cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
template<typename Lambda>
__global__ void kernel(Lambda f){
int t = blockIdx.x * blockDim.x + threadIdx.x;
printf("device: thread %i: ", t);
printf("f() = %i\n", f() );
}
int main(int argc, char **argv){
// arguments
if(argc != 2){
fprintf(stderr, "run as ./prog i\nwhere 'i' is function index");
exit(EXIT_FAILURE);
}
int i = atoi(argv[1]);
// lambdas
auto lam0 = [] __host__ __device__ (){ return 333; };
auto lam1 = [] __host__ __device__ (){ return 777; };
// make vector of functions
std::vector<int(*)()> v;
v.push_back(lam0);
v.push_back(lam1);
// host: calling a function by index
printf("host: f() = %i\n", (*v[i])() );
// device: calling a function by index
kernel<<< 1, 1 >>>( v[i] ); // does not work
//kernel<<< 1, 1 >>>( lam0 ); // does work
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaDeviceSynchronize() );
return EXIT_SUCCESS;
}
编译
nvcc -arch sm_60 -std=c++11 --expt-extended-lambda main.cu -o prog
我在运行时遇到的错误是
➜ cuda-lambda ./prog 0
host: f() = 333
device: GPUassert: invalid program counter main.cu 53
CUDA 似乎无法管理 int(*)() 函数指针形式(而主机 c++ 确实可以正常工作)。另一方面,每个 lambda 都作为不同的数据类型进行管理,无论它们在代码中是否相同并且具有相同的协定。那么,在CUDA中如何通过索引来实现功能呢?
【问题讨论】:
-
您的代码,如果工作,将导致替代路径(无法内联),这是处理 GPU 时不希望出现的行为。也许您可以创建一个内核/内核调用数组,并在编译时设置 lambda 值?
-
会看一下,假设可以创建一个 __ global __ lambdas 数组。
-
我很确定你依赖于 CUDA 解析器中的一些静态编译器分析魔法,当 lambda 放入容器时会中断。
-
M. Harris 在 Nvidia 博客中写了一些答案,表明 CUDA 不具备主机 c++ 程序在 lambda 方面的所有功能。在那种情况下,这个问题可能是目前不适合 GPU 计算的设计之一?
-
您可以在 CUDA 内核中使用函数指针,但不能以您在此处尝试的方式使用。关键是您不能直接从主机代码中获取指向设备函数的指针,这是使您的方案正常工作所必需的。您需要跳过一些障碍才能使其工作,即detailed in the answer to this question。请注意,此处的示例未使用 lambda,但适用相同的原则。