0%

CUDA 函数前缀

CUDA 函数前缀作为 CUDA 编程中一种特殊的使用技巧,其具有一定的限制意义。

CUDA 使用 cu 作为文件类型后缀,而在文件中又存在几种前缀,如果在修改编写 .cu 文件时不注意,会出现问题,比如:

1
error : calling a __host__ function from a __global__ function is not allowed.

在 CUDA 中有三种常见的前缀:__device____global____host__,其分别代表不同的意思,而这三个单词其实也是 CUDA 中常见的三种运行场景:

限定符 执行 调用 备注
__global__ 设备端执行 可以从主机调用也可以从计算能力3以上的设备调用 必须有一个void的返回类型
__device__ 设备端执行 设备端调用
__host__ 主机端执行 主机调用 可以省略

因为函数前缀设定了函数的运行环境,因此对函数内部实现也做出了一定的限制,具体来说就是,device 函数因为只能在 GPU 上执行,因此不能调用常见的一些 C/C++ 函数(没有 GPU 实现),global 函数虽然能在 CPU 上运行,但是也能在 GPU 上面运行,因此同理。host 函数则没有这个限制,可以调用普通函数实现。

因此,在出现报错如:error : calling a __host__ function from a __global__ function is not allowed. 时候,即为将一个普通的函数错误地添加进入了 global 前缀定义函数,在 .cu 文件中是不允许的。

注意,有时候一个函数可以同时被多个前缀修饰的,比如 CUDA 10 浮点数的转换:

1
__host__ ​ __device__ ​ __half 	__float2half ( const float  a ) throw ( )

以上修饰这个函数可以在 host 端被调用,也可以在 device 端被调用。实际上这个函数在 CUDA 9.2 以后才允许在 host 端调用,其 CUDA 8.0 的版本:

1
__device__ ​ __half __float2half ( const float  a )

因此,我们通过一个函数的前缀就可以判断这个函数的运行环境。