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指定一个真实架构的计算能力,用以确定可执行文件能否使用的CPU
具体可参看官方文档:
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文件并执行。
1 PTX是CUDA平台为基于CPU通用计算而定义的虚拟机和指令集
2 nvcc编译命令总是使用两个体系结构,一个是虚拟的中间体系结构,另一个是实际的GPU体系结构
3 虚拟架构更像是对应所需的GPU的功能声明
4 虚拟架构尽可能选择低 --- 适配更多实际GPU真实架构尽可能选择高 --- 充分发挥GPU性能
2 GPU架构与计算能力
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