CUDA 编程指南 —— 编程接口之使用NVCC编译


Programming Interface

在这里插入图片描述

CUDA C++ 为熟悉 C++ 编程语言的用户提供了一条简单的途径,可以轻松编写供设备执行的程序。
它由 C++ 语言的最小扩展集和运行时库组成。
核心语言扩展已在编程模型中引入。它们允许程序员将内核定义为 C++ 函数,并在每次调用该函数时使用一些新语法来指定网格和块维度。所有扩展的完整描述可以在 C++ 语言扩展中找到。包含其中一些扩展的任何源文件都必须使用 nvcc 进行编译,如使用 NVCC 编译中所述。
运行时是在 CUDA Runtime 中引入的。它提供在主机上执行的 C 和 C++ 函数,以分配和释放设备内存、在主机内存和设备内存之间传输数据、管理具有多个设备的系统等。运行时的完整描述可以在 CUDA 参考手册中找到。
运行时构建在较低级别的 C API(CUDA 驱动程序 API)之上,应用程序也可以访问该 API。驱动程序 API 通过公开较低级别的概念(例如 CUDA 上下文(设备的主机进程的模拟)和 CUDA 模块(设备的动态加载库的模拟))来提供额外的控制级别。大多数应用程序不使用驱动程序 API,因为它们不需要这种额外的控制级别,并且在使用运行时时,上下文和模块管理是隐式的,从而产生更简洁的代码。由于运行时可与驱动程序 API 互操作,因此大多数需要某些驱动程序 API 功能的应用程序可以默认使用运行时 API,并且仅在需要时使用驱动程序 API。驱动程序 API 在驱动程序 API 中进行了介绍,并在参考手册中进行了完整描述。

Compilation with NVCC

可以使用称为 PTXCUDA 指令集架构来编写内核,PTX 参考手册中对此进行了描述。然而,使用高级编程语言(例如 C++)通常更有效。在这两种情况下,内核都必须由 nvcc 编译为二进制代码才能在设备上执行。
nvcc 是一个编译器驱动程序,可简化编译 C++PTX 代码的过程:它提供简单且熟悉的命令行选项,并通过调用实现不同编译阶段的工具集合来执行它们。本节概述了 nvcc 工作流程和命令选项。完整的描述可以在 nvcc 用户手册中找到。

1. Compilation Workflow

1.1. Offline Compilation

使用 nvcc 编译的源文件可以包含主机代码(即在主机上执行的代码)和设备代码(即在设备上执行的代码)的混合。 nvcc 的基本工作流程包括将设备代码与主机代码分离,然后:

  • 将设备代码编译为汇编形式(PTX代码)和/或二进制形式(cubin对象),
  • 并通过必要的 CUDA 运行时函数调用替换内核中引入的 <<<…>>> 语法(并在执行配置中更详细地描述)来修改主机代码,以从 PTX 代码加载和启动每个已编译的内核,以及/或 cubin 对象。

修改后的主机代码可以作为 C++ 代码输出,留待使用其他工具进行编译,也可以通过让 nvcc 在最后一个编译阶段调用主机编译器来直接作为目标代码输出。修改后的主机代码可以作为 C++ 代码输出,留待使用其他工具进行编译,也可以通过让 nvcc 在最后一个编译阶段调用主机编译器来直接作为目标代码输出。

然后应用程序可以:

  • 链接到已编译的主机代码(这是最常见的情况),
  • 或者忽略修改后的主机代码(如果有)并使用 CUDA 驱动程序 API(请参阅驱动程序 API)加载并执行 PTX 代码或 cubin 对象。

1.2. Just-in-Time Compilation

应用程序在运行时加载的任何 PTX 代码都会由设备驱动程序进一步编译为二进制代码。这称为即时编译。即时编译增加了应用程序加载时间,但允许应用程序从每个新设备驱动程序附带的任何新编译器改进中受益。这也是应用程序在编译应用程序时不存在的设备上运行的唯一方法,如应用程序兼容性中详细介绍的。
当设备驱动程序即时编译某些应用程序的某些 PTX 代码时,它会自动缓存生成的二进制代码的副本,以避免在应用程序的后续调用中重复编译。当设备驱动程序升级时,缓存(称为计算缓存)会自动失效,因此应用程序可以从设备驱动程序中内置的新即时编译器的改进中受益。
环境变量可用于控制即时编译,如 CUDA 环境变量中所述
作为使用 nvcc 编译 CUDA C++ 设备代码的替代方案,NVRTC 可用于在运行时将 CUDA C++ 设备代码编译为 PTXNVRTCCUDA C++的运行时编译库;更多信息可在 NVRTC 用户指南中找到。

2. Binary Compatibility

二进制代码是特定于体系结构的。cubin 对象是使用指定目标架构的编译器选项 -code 生成的:例如,使用 -code=sm_80 进行编译会为计算能力 8.0 的设备生成二进制代码。从一个次要修订版到下一个修订版可以保证二进制兼容性,但不能从一个次要修订版到前一个修订版或跨主要修订版保证二进制兼容性。换句话说,为计算能力 X.y 生成的 cubin 对象将仅在计算能力 X.z 的设备上执行,其中 z≥y
Note

仅桌面支持二进制兼容性。 Tegra 不支持它。此外,不支持桌面和 Tegra 之间的二进制兼容性。

3. PTX Compatibility

某些 PTX 指令仅在具有较高计算能力的设备上受支持。例如,Warp Shuffle Functions 仅在计算能力 5.0 及以上的设备上支持。 -arch 编译器选项指定将 C++ 编译为 PTX代码时假定的计算能力。因此,例如,包含 warp shuffle 的代码必须使用 -arch=compute_50 (或更高版本)进行编译。
为某些特定计算能力生成的 PTX 代码始终可以编译为具有更大或相同计算能力的二进制代码。请注意,从早期 PTX 版本编译的二进制文件可能无法使用某些硬件功能。例如,从为计算能力 6.0 (Pascal) 生成的 PTX 编译的计算能力 7.0 (Volta) 的二进制目标设备将不会使用 Tensor Core 指令,因为这些指令在 Pascal 上不可用。因此,最终的二进制文件的性能可能比使用最新版本的 PTX 生成的二进制文件的性能更差。

4. Application Compatibility

要在具有特定计算功能的设备上执行代码,应用程序必须加载与此计算功能兼容的二进制或 PTX 代码,如二进制兼容性PTX 兼容性中所述。特别是,为了能够在具有更高计算能力的未来架构上执行代码(尚无法生成二进制代码),应用程序必须加载将为这些设备即时编译的 PTX 代码(请参阅 Just-及时编译(Just-in-Time Compilation))。
将哪些 PTX 和二进制代码嵌入到 CUDA C++ 应用程序中由 -arch-code 编译器选项或 -gencode 编译器选项控制,如 nvcc 用户手册中详细说明。例如,

nvcc x.cu
        -gencode arch=compute_50,code=sm_50
        -gencode arch=compute_60,code=sm_60
        -gencode arch=compute_70,code=\"compute_70,sm_70\"

嵌入与计算能力 5.0 和 6.0(第一个和第二个 -gencode 选项)兼容的二进制代码以及与计算能力 7.0(第三个 -gencode 选项)兼容的 PTX 和二进制代码。

生成主机代码以在运行时自动选择要加载和执行的最合适的代码,在上面的示例中,该代码将是:

  • 5.0 二进制代码,适用于计算能力 5.0 和 5.2 的设备,
  • 6.0 二进制代码,适用于计算能力 6.0 和 6.1 的设备,
  • 7.0 二进制代码,适用于计算能力 7.0 和 7.5 的设备,
  • PTX 代码在运行时编译为二进制代码,适用于计算能力 8.0 和 8.6 的设备。

x.cu 可以具有使用扭曲减少操作的优化代码路径,例如,仅在计算能力 8.0 及更高版本的设备中支持这些操作。 __CUDA_ARCH__ 宏可用于根据计算能力区分各种代码路径。它仅为设备代码定义。例如,当使用 -arch=compute_80 进行编译时,__CUDA_ARCH__ 等于 800。

使用驱动程序 API 的应用程序必须编译代码以分隔文件,并在运行时显式加载和执行最合适的文件。
Volta 架构引入了独立线程调度,它改变了 GPU 上线程的调度方式。对于依赖于以前架构中 SIMT 调度的特定行为的代码,独立线程调度可能会改变参与线程的集合,从而导致不正确的结果。为了帮助迁移,同时实施独立线程调度中详细介绍的纠正措施,Volta 开发人员可以使用编译器选项组合 -arch=compute_60 -code=sm_70 选择加入 Pascal 的线程调度。
nvcc 用户手册列出了 -arch、-code-gencode 编译器选项的各种简写。例如,-arch=sm_70-arch=compute_70 -code=compute_70,sm_70 的简写(与 -gencode arch=compute_70,code=\"compute_70,sm_70\" 相同)。

5. C++ Compatibility

编译器前端根据C++语法规则处理CUDA源文件。主机代码支持完整的 C++。但是,设备代码仅完全支持 C++ 的一个子集,如 C++ 语言支持中所述。

6. 64-Bit Compatibility

64 位版本的 nvcc 以 64 位模式编译设备代码(即指针是 64 位)。仅以 64 位模式编译的主机代码支持以 64 位模式编译的设备代码。

  • 27
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的码泰君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值