问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

CUDA编程:nvcc编译过程和GPU计算能力详解

创作时间:
作者:
@小白创作中心

CUDA编程:nvcc编译过程和GPU计算能力详解

引用
CSDN
1.
https://m.blog.csdn.net/weixin_42445727/article/details/140893132

CUDA(Compute Unified Device Architecture)是NVIDIA推出的通用并行计算架构,该架构使GPU能够解决复杂的计算问题。nvcc(NVIDIA CUDA Compiler)是CUDA的编译器,用于将CUDA代码编译为GPU可执行的二进制代码。本文将详细介绍nvcc的编译过程和GPU计算能力的相关知识。

1 nvcc编译流程

nvcc编译流程主要包括以下几个步骤:

  1. nvcc将全部源代码分离为主机代码和设备代码
  2. 主机(host)代码是标准的C/C++代码,设备(device)代码是C/C++的扩展语言
  3. nvcc先将设备代码编译为PTX(Parallel Thread Execution)伪汇编代码,再将PTX代码编译为二进制的cubin目标代码
  4. 在将源代码编译为PTX代码时,需要使用选项-arch=compute_XY指定一个虚拟架构的计算能力,用以确定代码中能够使用的CUDA功能
  5. 在将PTX代码编译为cubin代码时,需要使用选项-code-sm ZW指定一个真实架构的计算能力,用以确定可执行文件能否使用的GPU

具体可参看官方文档:
nvcc编译过程:https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html

下面结合这张图进行具体讲解:

NVCC的编译过程分为离线编译和即时编译两部分组成:

离线编译(绿色虚线框内):
CUDA源程序(即xxx.cu文件)在编译前的预处理会被分为主机端代码和设备段代码(即图中的左右分支):

  1. 如图右分支:在设备端代码会被编译成ptx文件(可以看作是用于设备端的汇编文件)或是直接可运行的二进制文件xxx.cubin,然后将起.ptx/.cubin文件放在fatbinary文件中。
  2. 如图左分支:在主机端代码进行预处理,并将其嵌入到fatbinary文件中,并将CUDA特定的C++扩展转换成标准C++结构(通过cudafe++和cudafe1.stub.c合成为。cudafe1.cpp),然后C++主机编译器将所合成的主机代码与嵌入的fatbinary编译成主机.o/.obj文件。

即时编译(图片绿色虚线框下方):
在主机设备启动代码时,CUDA run-time系统会对fatbinary文件进行检测,以获得一个对于GPU设备合适的映像(之后还会提及):

  1. 如果之前的cubin文件与当前GPU相匹配,run-time系统通过nvlink对多个设备端文件进行链接,最后通过host linker链接主机端文件成可执行文件。
  2. 如果cubin文件所表示的虚拟设备与当前GPU不符或者fatbinary文件中只包含ptx文件,将会对fatbinary文件中的ptx文件进行即时编译,并对其进行链接(nvlink)最后通过host linker链接主机端文件成可执行文件。

补充说明:
NVCC极大的考虑到了应用的向后兼容性,(如最上面图的绿色实线宽内)将输入设备端代码根据虚拟gpu结构(virtual architecture)编译成ptx,以及通过当前的真实gpu结构将其编译成cubin文件,到时进行直接执行即可。

由于ptx的存在,可以提高其兼容性,通过在运行时对ptx进行即时编译成cubin文件并执行。

PTX是CUDA平台为基于CPU通用计算而定义的虚拟机和指令集。nvcc编译命令总是使用两个体系结构,一个是虚拟的中间体系结构,另一个是实际的GPU体系结构。虚拟架构更像是对应所需的GPU的功能声明。虚拟架构尽可能选择低以适配更多实际GPU,真实架构尽可能选择高以充分发挥GPU性能。

2 GPU架构与计算能力

GPU架构与计算能力是CUDA编程中非常重要的概念。计算能力通常由两个数字组成,例如"6.1",其中第一个数字表示主版本号,第二个数字表示次版本号。不同的GPU架构具有不同的计算能力,这决定了它们能够支持的CUDA功能和性能水平。

3 CUDA程序兼容性问题

3.1 指定虚拟架构计算能力

  • C/C++源码编译为PTX时,可以指定虚拟架构的计算能力,用来确定代码中能够使用的CUDA功能
  • C/C+=源码转化为PTX这一步与GPU硬件无关
  • 编译指令(指定虚拟架构计算能力)
// XY: 第一个数组X代表计算能力的主版本号,第二个数字Y代表计算能力的次版本号
-arch=compute_XY
  • PTX的指令在能在更高的计算能力的GPU使用
nvcc helloworld -o hello -arch=compute_61
编译出来的可执行文件hello可以在计算能力>=6.1的GPU上面运行,在计算能力小于6.1的GPU无法运行

3.2 指定真实架构计算能力

  • PTX指令转化为二进制cubin代码与具体的GPU有关
  • 编译指令(指定真实架构的计算能力)
// XY:第一个数字X代表能力的主版本号,第二个数字Y代表计算能力的次版本号
-code=sm_XY
  • 注意
1 二进制cubin代码,大版本之前不兼容
2 指定真实架构计算能力的时候必须指定虚拟架构计算能力
3 指定真实架能力必须大于等于虚拟架构计算能力
  • 真实架构可以实现低小版本到高小版本的兼容

3.3 指定多个GPU版本编译

  • 使得编译出来的二进制文件可以在多个GPU中运行
  • 同时指定多组计算能力
编译选项: -gencode arch=compute_XY -code=sm_XY
如:
-gencode arch=compute_35 -code=sm_35 //开普勒架构
-gencode arch=compute_50 -code=sm_50 // 麦克斯韦架构
-gencode arch=compute_60 -code=sm_60 // 帕斯卡架构
-gencode arch=compute_70 -code=sm_70 // 福特架构
  • 编译出的可执行文件包含四个二进制版本,生成的可执行文件称为胖二进制文件(fatbinary)

3.4 nvcc即时编译

  • 在运行可执行文件时,从保留的PTX代码临时编译出cubin文件
  • 在可执行文件中保留PTX代码,nvcc编译指令指定所保留的PTX代码虚拟架构
指令 -gencode arch=compute_Xy, code=sm_XY
两个计算能力都是虚拟架构计算能力
两个虚拟架构计算能力必须一致
如:
-gencode arch=compute_35, code=sm_35
-gencode arch=compute_60, code=sm_60
-gencode arch=compute_61, code=sm_61

3.5 nvcc编译默认计算能力

不同版本CUDA 编译器在编译CUDA代码时,都有一个默认计算能力,

CUDA6.0及更改版本, 默认计算能力1.0
CUDA6.5-CUDA8.0,默认计算能力2.0
CUDA9.0-CUDA10.2,默认计算能力3.0
CUDA11.6,默认计算能力5.2

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号