Shader在GPU中是如何执行的?
首先,我想说明一下,虽然文章的标题是 How GPU Works,但是我无意再去重复GPU工作的各个stage,流水线这些概念。本文会深入到更底层一点:GPU是如何执行shader的。在本文中,我除了GPU执行shader的方式之外,还有稍微涉及一些多核心,SIMD,超线程这些过去大家看上去貌似非常高大上的概念。
一个简单shader
这就是一个非常简单的diffuse shader(HLSL),是fragment(pixel) shader,每个片元着色器是独立执行的,并不需要特地的去执行并行编程(像CPU多线程那样),但是每个片元着色器确实有自己单独的逻辑控制流。
代码运行的方式
GPU和CPU运行shader的方式差不多,都是先编译成汇编,然后单步执行。
然后逐步执行
CPU和GPU架构对比
两者对比可以发现,GPU core相比CPU core,去掉了乱序执行,分支预测和内存预取的功能,并去掉了大块的缓存,使相同面积可以容纳更多的核心。而且去除了分支预测,乱序等功能之后也能使程序顺序执行时更高效(代价是分支效率下降,后文会提)。
指令流共享
到此我们可以发现一个现象,就是每个片元执行的代码都是相同的,GPU cores完全可以复用一套指令。为此,GPU工程师们发明了一个极具想象力的设计。
将ALU和Context增加,使用一个指令来控制多个ALU进行计算。这种技术在CPU那边有个学名,叫 SIMD ,也就是通过一条汇编指令控制多个计算。
这样,就实现了译码器和ALU一对多的映射。
各种GPU运算都是这样的
在现代GPU中,一般16到64个ALU共享一个指令流
分支运算
上文提到过GPU core相比CPU core,是简化过的,简化掉了分支分支预测的功能,那GPU是如何执行分支语句的呢。了解shader的同学可能也了解,分支语句会让shader的性能极剧下降,在此我也会一起解释。
分支语句的位置
GPU在编译时会找到分支语句的位置,然后在执行时,对于分支语句,会将各分支分配给不同的ALU来执行。
并不是每个ALU的计算结果都有效,而无效的结果Context会负责舍弃。也就是说在最坏情况下,分支语句相比无分支语句仅有1/8的的性能(取决于ALU数)。期望值是1/2,也就是平常大家常说的分支语句会令shader性能折半。
Stalls
Stalls是一个硬件术语,指芯片因为上一条指令执行过慢,而无事可做的情况。回到之前的diffuseshader上。
采样是GPU从显存中读取贴图信息的过程,有大量延迟,一般在100到1000个时钟周期。为了防止这个问题,CPU通常采用超大的缓存+超大带宽的方式来减小io时的stalls。
这里又是CPU和GPU硬件设计上截然不同的地方,因为Cache不命中会使 Stall 发生(必须从主存储器取值),所以GPU设计时索性去掉了big data cache和Memory pre-fetcher,取而代之的是一种非常巧妙的方法。
对于一个GPU core,所需拥有的Context数是ALU数目的数倍。这样,当其中一组Context遭遇采样io时,迅速切换到下一组Context。等到IO结束之后,前一组Context余下的指令才继续执行。大家一般谈论的CPU超线程其实也是这个原理,两个Context共享一个physics core。
发生中断时切换Context
中断结束后继续执行 图像采样需要数百时钟周期,是通常指令执行的数十到数百倍,因此一个GPU core上拥有的Context数也是ALU的数十倍。刚好符合了实际情况:屏幕像素数远远多于GPU流处理器个数。
Multi Contexts
实例:GTX480
NVIDIA管一个GPU core叫一组SM,一个ALU叫一个CUDA core,CUDA core可以在一个时钟周期内执行一个乘法和一个加法(即一个MAD,Multiply & Add指令)。一组SM有两个Fetch/Decode单元,个人猜测这样就可以在执行分支语句时一人一半。一组SM有48组Context,也就是说,一组SM,可以同时执行 32 * 48 = 1536 个 CUDA 线程。
GTX480一共有15组SM,也就是说GTX480同时可以执行多达 1536 * 15 = 23,040 个 CUDA 线程。可以说非常惊人了。
结语
本文介绍了一下DX10/openGL 3.x时代的显卡,也就是SM4.0统一着色架构下的显卡设计。在tensorFlow和RTX相继问世后,NVIDIA也发布了拥有tensor core的titan V和拥有RTX core的RTX2080/2080Ti,面对机器学习和光线追踪这两个if else遍地的情况,GPU的设计也作出了很大的变化,最直接的感受就是分支语句没有性能损失了。相信GPU的设计也更接近CPU了。从当年的Silicon Graphics RealityEngine的众CPU开始,到RTX/tensor core,图形硬件的发展,不也是一种循环吗。
https://www.cs.cmu.edu/afs/cs/academic/class/15462-f11/www/lec_slides/lec19.pdf
http://www.cs.cmu.edu/afs/cs/academic/class/15462-f12/www/lec_slides/462_gpus.pdf
- 原文作者:Binean
- 原文链接:https://bzhou830.github.io/post/20210215GPUShader/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。