Article
CUDA笔记-平台与编译
CUDA平台与编译.cu文件相关的知识内容
为了支持在多种异构的系统上进行计算,CUDA平台实际上是由多种软件、硬件以及其他技术组成,以下是CUDA平台中基础的概念或是基本的组件。

CC & SM Versions
每款NVIDIA GPU都有一个特定的计算能力(Compute Capability, CC)版本号。版本号由主版本号X和次版本号Y组成,用X.Y表示,如12.0,用于标识对应GPU架构所支持的硬件特性以及一些硬件参数。查询GPU的计算能力可以通过以下两种方法:
- 通过NVIDIA驱动提供的nvidia-smi工具进行查询
nvidia-smi --query-gpu=name,compute_cap
# NVIDIA GeForce RTX 5080, 12.0
- 运行时通过API获取,可以通过以下三种API获取:
- 由CUDA Runtime API提供的
cudaDeviceGetAttribute(), 包含在`<cuda_runtime_api.h>中 - 由CUDA Driver API提供的
cuDeviceGetAttribute(), 包含在<cuda.h>中 - 由NVML API提供的
nvmlDeviceGetCudaComputeCapability(),包含在<nvml.h>中,注意这个需要带上-lnvidia-ml链接参数
如果想看某个CC号对应的GPU具体支持什么硬件特性,如Tensor Core, Thread Block Cluster等,可以在CUDA Programming Guide, Feature Availability一节找到。
GPU中执行计算的硬件单元被称为流式多处理器(Streaming Multiprocessor, SM)。每一种GPU架构都有其对应的CC Number, 每一种GPU架构的SM版本也与其CC Number存在对应关系,主版本号为X,次版本号为Y的情况下,SM版本为sm_XY,例如CC Number为12.0的情况下,SM版本为sm_120,在将.cu文件编译为机器码(cubin/二进制)时,会用SM版本号作为标识,从而编译器能够为特定的硬件生成其能够识别的指令,在程序运行时,驱动也能够加载匹配的版本运行。
CUDA Toolkit & NVIDIA Driver
NVIDIA Driver
NVIDIA驱动可以视为是GPU的操作系统,当我们需要使用NVIDIA GPU时,首先需要在对应的操作系统上安装NVIDIA驱动软件。NVIDIA驱动是CUDA的基础,在CUDA之外,还提供了其他方式来操控GPU,如Vulkan/Direct3D。 NVIDIA驱动也有其对应的版本号,如r595等。
CUDA Toolkit
CUDA Toolkit是一系列库文件、头文件以及工具所构成的集合,用来开发在GPU上跑的软件。
CUDA Toolkit和NVIDIA Driver的关系有点类似于gcc, 各种header, gdb等调试工具和操作系统之间的关系。
CUDA Runtime
CUDA Runtime是CUDA Toolkit提供的一部分库文件所构成的集合。CUDA Runtime对外提供API以及部分语言扩展(如<<<grid, block>>>)用于处理在GPU上申请内存、在GPU和GPU和CPU之间传输数据、跑Kernel等常见任务。CUDA Runtime对外提供的API部分则被称为是CUDA Runtime API。
CUDA Compatibility document说明了对应的GPU、驱动以及CUDA Toolkit应该怎么兼容。
CUDA Runtime API & CUDA Driver API
CUDA Runtime API的底层是CUDA Driver API, 部分特性只有通过CUDA Driver API才能够实现。
CUDA Driver API章节中能够查询到更多CUDA Driver API的使用细节。
CUDA Runtime API 文档中包含了所有可用的CUDA Runtime API,同理CUDA Driver API文档。
Parallel Thread Execution (PTX)
Parallel Thread Execution (PTX) virtual instruction set architecture (ISA),即并行线程执行虚拟指令集架构是CUDA平台中的重要组成部分,PTX是一种专门为NVIDIA GPU所设计的高级汇编语言,对GPU硬件实际执行的ISA做了一层抽象,应用程序可以直接写PTX。
对于一些DSL以及高级语言的编译器,可以先将对应的语言转换为PTX作为中间表示,再通过NVIDIA的Offline或者just-in-time编译工具得到可执行GPU二进制代码。
由于GPU架构的迭代,性能的不断提升,PTX virtual ISA的标准也被划分为多个版本,用于支持不同计算能力的GPU。能够支持CC X.Y的PTX版本被称为是compute_80。
Cubins and Fatbins
.cu文件通过nvcc首先得到PTX代码,再被编译为CUDA二进制,即cubin。每个cubin有其对应的SM version,如sm_120等。
对于使用GPU进行计算的程序,通常包含在CPU上执行的代码和在GPU上执行的代码。GPU代码部分被包含在一个名为fatbin的容器中,里面可以包含多个不同SM版本的cubin以及不同计算能力的PTX代码(便于在未来平台上通过JIT编译使用)。
Binary Compatibility
某些情况下,NVIDIA GPU能够保证二进制文件的兼容性,具体来说是显卡的CC主版本号与cubin文件要求的一致,次版本号等于或高于cubin文件所要求的。
PTX Compatibility
当应用程序在fatbin中存储了GPU代码的PTX版本后,在应用程序运行时可以通过JIT编译成不低于PTX计算版本号的SM版本号的二进制,例如compute_80的PTX代码,可以编译成sm_120版本的cubin文件。
Just-in-Time Compilation
程序运行时加载PTX代码,并通过设备驱动程序将其编译为二进制文件,这一过程被称为是即时编译(Just-in-Time, JIT Compilation)。JIT会增加应用程序的加载时间,但该机制能够让应用程序编译时还不存在的程序被动态进行加载。同时,他能够让对应PTX代码获得最新的即时编译器的优化。
具体来说,当driver中内置的编译器编译PTX代码时,会将得到的二进制文件进行缓存,这一过程被称为compute cache, 从而避免编译过程被重复触发。当driver更新时,内置二进制缓存会被删除,此时PTX代码通过最新一代的driver中内置的编译器编译所得到的产物将受益于编译器各项改进所带来的好处。
关于PTX在运行时如何以及何时进行JIT Compilation可以查阅Lazy Loading部分, 通过也有一些环境变量能够影响JIT Compilation的行为,见CUDA Environment Variables。
NVRTC, 一种用于CUDA C++的运行时编译库,能够在运行时将CUDA C++ device code编译为PTX。