It consists of a minimal set of extensions to the C++ language and a runtime library.
使用PTX
CUDA指令集来编写kernel,kernel通过 nvcc
编译成二进制代码在设备上执行。
nvcc
是一个编译器驱动程序,可简化 C ++ 或 PTX 代码的编译过程:它提供简单且熟悉的命令行选项,并通过调用实现不同编译阶段的工具集合来执行它们。本节概述了 nvcc 工作流和命令选项。
Offline Compilation(离线编译)
nvcc编译的源文件包括:主机代码host code(主机上执行)和设备代码device code(设备上执行),nvcc的基本流程是将设备代码和主机代码分开;
<<<...>>>
修改主机代码,从 PTX代码 或者 cubin对象 加载和启动每个编译的kernel修改后的主机代码可以以C ++代码输出,以便使用其他工具进行编译,也可以通过在最后一个编译阶段让nvcc
调用主机编译器直接作为目标代码输出。
应用程序可以:
Just-in-Time Compilation(即时编译)
应用程序在 runtime 时加载的任何 PTX代码,都会由设备驱动程序进一步编译为二进制代码binary code(存入缓存中,避免重复编译),但会消耗一定的加载时间。
CUDA 环境变量可用于即时编译。
NVRTC 可以作为使用nvcc编译 CUDA C ++ 设备代码的替代方法,NVRTC可用于在 runtime 时将 CUDA C ++ 设备代码编译为 PTX。
次要版本具有向后兼容性,计算能力X.y生成的 cubin 对象将仅在计算能力X.z的设备上执行,其中z≥y。
某些PTX指令仅在具有更高计算能力的设备上受支持。
-arch
编译器选项指定将C++编译为PTX代码时假定的计算能力。 因此,例如,包含warp shuffle的代码必须使用-arch = compute_30
(或更高版本)进行编译。
为某些特定的计算能力生成的 PTX代码 始终可以编译为具有更大或相等计算能力的二进制代码。但由于较早的 PTX版本 编译的二进制文件可能未使用某些硬件功能,最终二进制文件的性能可能比使用最新版本的 PTX 生成二进制文件时的性能差。
要在具有特定计算功能的设备上执行代码,应用程序必须加载与二进制计算和PTX兼容性中所述的,与此计算功能兼容的及时编译的二进制或PTX代码。
-arch
和 -code
编译器选项或 -gencode
编译器选项,控制哪个PTX 和二进制代码嵌入 CUDA C ++应用程序中。
nvcc x.cu
// 嵌入与计算能力3.5和5.0兼容的二进制代码
-gencode arch=compute_35,code=sm_35
-gencode arch=compute_50,code=sm_50
// 嵌入与计算能力6.0兼容的PTX和二进制代码
-gencode arch=compute_60,code=\'compute_60,sm_60\'
生成主机代码,以在运行时自动选择最合适的代码来加载和执行,在上面的示例中,该代码将是:
x.cu
可以具有一个优化的代码路径,例如,它使用warp shuffle操作,只有计算能力为3.0或更高的设备才支持。
__CUDA_ARCH__
宏可用于根据计算能力来区分各种设备代码路径。例如,当使用-arch = compute_35
进行编译时,__ CUDA_ARCH__ = 350
。
使用驱动程序API的应用程序编译代码,必须分离文件,并在运行时显式加载和执行最合适的文件。
nvcc
用户手册列出了-arch
,-code
和-gencode
编译器选项的各种简写形式。例如,-arch = sm_35
是-arch = compute_35-code = compute_35,sm_35
的简写,与-gencodearch = compute_35,code = \'compute_35,sm_35 \'
相同。
编译器的前端根据 C++语法规则 处理 CUDA源文件。
主机代码支持完全C++,设备代码仅完全支持 C++的子集。
-m64
编译器选项以64位模式编译设备代码。m32
编译器选项以32位模式编译设备代码。在与应用程序链接的 cudart库 中实现了 runtime,可以通过 cudart.lib
或 libcudart.a
静态实现,也可以通过 cudart.dll
或 libcudart.so
动态实现。
需要 cudart.dll
和/或 cudart.so
进行动态链接的应用程序,通常会将它们作为应用程序安装包的一部分包含在内。只有在链接到 CUDA runtime 的同一实例的组件之间传递 CUDA runtime symbols 的地址才是安全的。
如异构编程中提到的那样,CUDA 编程模型假定一个由主机host 和设备device 组成的系统,每个主机和设备都有各自独立的内存。设备内存Device Memory 概述了用于管理设备内存的runtime 函数。