如果你想了解
Nvcc
到底搞了什么鬼,究竟
compute_xy sm_xy
区别在哪里,
ptx,cudabin
又是怎么嵌套到
exe
里面最终被驱动执行的,这一节正是你想要的知识。他将讲解每一个编译的具体步骤,而且不光是知识,读者可以自己动手操作来体验这一个过程。他的用处不仅在能够对
CUDA
的编译以及工作机制有更深的认识,而且可以进行高级
debug
,比如可以自己手动进行
ptx->cudabin
的步骤等等。
参考:
nvcc2.1.pdf
由于水平有限,错误部分欢迎大家留言指出
作者:
insky(wenyao2009(at)gmail.com)
主页:
www.gamecoding.cn
1.
一个编译例子
随意找一个包含
kernel
以及
kernel
调用的
.cu
文件,如
x.cu
。进入命令行
:
敲打
nvcc –cuda x.cu –keep
将得到如下结果,
-cuda
是将
.cu
编译成
.cu.cpp
,
-keep
保留中间结果。(如果提示找不到
nvcc
请在
path
中添加
%cuda_bin_path%
)
打开
.cu
文件所在目录(此处是
ptx
)
,
你会惊讶的发现多出了一大堆文件,是的,很烦,不过很快你将会喜欢上他们,因为他们把
nvcc
的工作流程完美的记录下来了。好吧,那我们开始吧。
2. Virtual architecture vs GPUfeature
首先定位到文件
x.cu, x.ptx, x.sm_10.cubin
这三个文件上来,他们按照下图流程依次生成,
x.cubin,x.ptx
最终会被嵌套到
x.cu.cpp
中。
Virtual compute architecture
对应
nvcc
的
-arch
编译选项,他的值如下表所示。他的意思
是
nvcc
将针对哪个类型的
virtual compute architecture
生成
ptx
汇编代码。如果是
compute_10
则
x.cu
中无法使用
atomic
等不支持的操作,否则会出现编译错误。
Real sm architecture
指的是真实
GPU
的架构,这个选项对应于
nvcc
的
-code
编译选项,
他可以选的值如下表所示。他的意思是根据此目标
GPU
架构将
x.ptx
编译成
x.cubin
,一般
来说,
Real sm architecture
必须等于或者高于对应的
Virtual compute architecture
。比如:
Nvcc –cuda x.cu –arch compute_13 –code sm_10
是行不通的。
到这里,你或许会说
“
你讲错了吧
”
,
nvcc
的
-arch
选项可以取
sm_13
呢,
cudarule
都这么取的,没错,是可以怎么做,因为有些特殊机制的支持:
_ -code
可以有多个值,将生成多个版本的
cubin
,最终全部嵌套在
exe
中,见下节
_ -code
里面可以包含
compute_xy,
对应的
ptx
会被嵌套在
exe
中,见下节
_
省略
-arch,
则自动选择最接近的
nvcc x.cu –code=sm_13 _ nvcc x.cu –arch=compute_13 –code=sm_13
_
省略
-code
nvcc x.cu –arch=sm_13 _ nvcc x.cu –arch=compute_13 –code=compute_13 sm_13
nvcc x.cu –arch=compute_10 _ nvcc x.cu –arch=compute_10 –code=compute_10
_
省略
-arch –code
nvcc x.cu _ nvcc x.cu –arch=compute_10 –code=sm_10
3. cubin
,
ptx
是如何组织到
exe
中,又是如何被加载到驱动中去的
好的,现在我们已经能够用
-code –arch
去控制
nvcc
生成对应
virtual or gpu architecture
的
ptx
及
cubin
文件了。接下来我们讲更彻底去了解,这些
ptx, cubin
是怎么集中到
exe
中,又是如何被执行的。打开
x.cu.cpp
,搜索
“
__deviceText_$compute_10$
”
,
找到了吗?没错,这就是
compute_10
下的
PTX
代码的二进制形式,接着往下看,你可以找到
“
__deviceText_$sm_10$
”
,这是
sm_10
下的
cubin
代码。好吧,再接着看吧:
static __cudaFatPtxEntry __ptxEntries []
static __cudaFatCubinEntry __cubinEntries[]
static __cudaFatDebugEntry __debugEntries[]
他们分别是
ptx
数组,
cubin
数组以及
debug
数组,
{0
,
0}
结尾的原因不用多说了吧,再找找
__cudaFatPtxEntry
在哪定
义
的吧
cuda2.1include__cudaFatFormat.h
,好好的读一下这个文件的说
明
,你会
长叹
一
声
“
你
丫
原来
藏
在这里
”
。
OK
,全文
引
用如下:
4.
回头来解决剩下的中间文件
其
实
nvcc
只
是个编译
器
驱动,他会调用很多
cuda tools
去完成
各
个编译步骤,最
后
调用
系统
的
c/cpp
编译
器
(cl,gcc)
以及
链
接
器
。他的流程如下图所示:
1
,
cudafe.exe
去分
离
host code, device code
,生成
.gpu
等
2
,
nvopencc(
我想应
该
就是
nvcc.exe
完成的
)
编译
.gpu
到
.ptx
3
,
ptxas.exe
编译
.ptx
到
.cubin
4
,
fatbin.exe
编译
.cubin
到
.fatbin.c
,最终集
合
到
.cu.cpp
或者
.cu.c
中。