CUDA C编程手册: 编程接口(一)
阅读原文时间:2021年04月22日阅读:1

CUDA C编程手册: 编程接口(一)

引言

CUDA C 简单的编程方法,它与C语言编程非常相似,可以很快地写出在设备上运行的程序。它由一些小的C语言扩展和一个运行时库组成。

核心的编程扩展已经在编程模型中有了介绍。这些扩展可以使得程序员定义C形式的核函数,且利用一些新的语法来指明网格和块的维度。任何使用了这些扩展的源文件必须使用NVCC编译器来编译。

运行时库提供的C函数可以在主机端执行,包括内存的分配和释放、数据传输和管理系统上的多个设备等。运行时库的完整的描述可以在CUDA参考手册(CUDA reference manual)中找到。运行时库是基于底层的CUDA 驱动API。驱动API 通过暴露一些底层的概念(如CUDA contexts、CUDA module) 来提供了额外的控制层。大多数应用并不需要这些由驱动提供的额外控制。当使用运行时的时候, context 和 module都是暗含的,这会使得代码更加简洁。驱动API 同样可以在参考手册中找到。

NVCC编译

核函数可以使用CUDA指令集架构PTX来进行编写,在参考手册中可以查看PTX的具体内容。但是使用更加高级的编程语言, 如C语言,会更加有效率。不管怎么样,核函数最终都会被nvcc编译成可以在设备上运行的二进制代码。

nvcc 是一个编译驱动,它简化了编译C或者PTX代码的过程:它提供了简单且类似的命令行选项, 这些命令行选项可以在不同的编译阶段被调用的工具所执行使用。这一部分给出了nvcc工作流的概览和编译选项。更详细的内容可以查看nvcc用户手册。

编译工作流

离线编译

使用NVCC编译的源文件,可以混合主机端代码和设备端代码。nvcc 的基本工作流:

  1. 分离设备端代码和主机端代码。
  2. 编译设备端代码为汇编形式(PTX) 且/或.二进制形式(cubin)
  3. 修改主机端代码,利用CUDA C 运行时函数替换<<<…>>>, 来加载和发射每个编译好的核函数。被修改的主机端代码可以输出为C代码或者object代码。
  4. 链接编译好的主机代码或者忽略修改的主机端代码且利用CUDA 驱动API 来加载和执行PTX代码或者cubin object。

即时编译

应用程序在运行时加载的任何PTX代码都会被设备驱动程序编译成而二进制代码。这称作即时编译。 这种编译方式增加了应用的加载时间,但却允许应用从新驱动中获益。这也是唯一的方法, 使得运行在设备上的应用可以不经过编译。

当驱动即时编译应用程序的一些PTX代码时, 它会缓存编译好的二进制代码,放置接下来的程序调用时重复编译。这些计算缓存compute cache在驱动升级的时候会自动失效,以便这些应用可以从新的驱动中获益。

二进制兼容性

二进制代码是架构敏感的。一个 cubin对象在生成时通过使用选项-code来指明目标架构。比如, 编译选项 -code=sm_35 会生成计算力3.5的设备的二进制代码。 二进制兼容是保证小修改之间的向后兼容性, 而不是向前兼容, 更不能跨大版本兼容。比如, 一个为计算力为X.y架构生成的二进制文件, 它只能在计算力为X.z的架构上运行,其中z>=y。

PTX兼容性

一些PTX指令只能在相应的设备架构上运行。 在编译C为PTX代码时, 编译选项-arch给出了所设定的计算力。例如,对于使用了warp shuffle功能的代码, 需要在编译时添加选项-arch=compute_30。 当然,设定更高的计算力也是可行的。

PTX代码为了某些指定计算力的设备,通常会被编译成更高或者相等的计算力。值得注意的是,一些早期的PTX代码编译成的二进制文件并不会使用新的硬件特性。例如用计算力为6的PTX代码生成指定计算力为7的二进制代码并不会使用Tensor Core 指令。因此,用最新的PTX生成的最终二进制代码可能性能不是最好的。

应用兼容性

为了在指定计算力的设备上运行代码,一个应用程序必须加载可兼容的二进制文件或者PTX代码。特别是为了做到可以兼容将来更高计算力的架构,一个应用必须加载PTX代码。

哪种PTX代码或者二进制代码嵌入到CUDA C 应用中,是通过编译选项-arch和-code或者-gencode编译选项来控制的。

-gencode arch=compute_35,code=sm_35
-gencode arch=compute_50,code=sm_50
-gencode arch=compute_60,code=\'compute_60,sm_60\'

主机端代码会生成在运行时自动选择最合适代码来加载和执行,对于上面的例子,结果如下:
1、对于计算力为3.5和3.7的设备是3.5的二进制代码;
2、对于计算力为5.0和5.2的设备是5.0的二进制代码;
3、对于计算力为6.0和6.1的设备是6.0的二进制代码;
4、对于计算力高于7.0的设备,PTX代码在运行时编译成二进制代码。

CUDA__ARCH可以用来执行基于不同计算力而编译不同的代码。这个宏仅仅是为了设备代码而定义的。当编译选项arch=compute_35时,CUDA_ARCH=350。

C/C++兼容性

编译器的前端处理CUDA源文件的时候是根据C++ 语法规则而来的。完整的C++在设备端代码是支持的。 但只有它的一个子集被设备端代码支持。

64位兼容性

64-bit版本的nvcc 以64-bit模式编译设备端代码。 只有当主机端代码使用64-bit编译时,设备端代码才会支持64-bit编译。对于32-bit是同样的道理。但是可以通过设置编译选项-m64, -m32来设置不同的编译模式。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章