Hi!请登陆

NVIDIAGPU的一些解析(一)

2022-6-17 141 6/17

之前我写了关于Intel GPU的一些介绍,这次就写一下nVIDIA GPU。

前排预警,全文很长……

因为不是写什么论文,我也没实际写代码去做测量,一些理解也来自猜测,出错是难免的,欢迎讨论纠错。大部分信息都来自于官方白皮书,以及很容易搜到的论文。


流处理器 (Stream Processor)

首先要提到一个流处理器的概念。

从DX9时代过来的人应该都知道那场大变革,顶点渲染和像素渲染在DX10被合并成统一渲染。虽然对于开发者来说,vertex shader和fragment(pixel) shader的概念依旧存在,但底下执行的单元却被统一了,即由流处理器来进行处理。

这么做是有原因的,当时的游戏有些注重顶点运算,有些注重像素运算;而GPU里也存在着顶点管线和像素管线的说法,两者的比例并不是固定值。显然,不同的游戏有不同的最佳比例,由此也引申出了A黑游戏、N黑游戏的说法[1]

DX10统一两条管线,相当于把两种单元从静态分配改为动态分配,能提高资源的利用率。

AN两家也跟着DX10推出了各自的新一代显卡,而其中N家的G80架构有着巨大革新,奠定了未来的N卡架构。

对于现在的N卡架构来说,流处理器数量即CUDA Core数量。

Scalar

Scalar也就是标量,这算是G80引入的一大革新之一。

通常来说,GPU是给渲染设计的,运算的对象要么是颜色RGBA,要么是坐标XYZW,都是向量。于是早期的GPU都是对一个4单位的向量进行操作。

而G80提出了通用计算的概念,这意味着运算的对象可能是其他东西,不一定能凑成4单位的向量了。为了提高通用性,G80就引入了标量计算的概念,运算粒度变小了,而同期的AMD只是在旧架构上做修改,依旧是4D向量。

在这之后,所有的N家架构图中都有密密麻麻的SP格子,但硬件上是不是真的如图上一样做成一个个Scalar ALU,那就不得而知了。以我的经验与看法,我更倾向于把这看作是宣传物料,硬件上还是SIMD ALU。至于说真正实现Scalar的,很可能只是ISA。

AoS与SoA,SIMD与SIMT

这里得插一段来介绍一下SIMD。有些人可能觉得奇怪,N家的架构不是一直标榜SIMT吗,怎么又扯到SIMD了。但我认为SIMD和SIMT并不矛盾。

SIMD是单指令,多数据。但具体到程序设计里,这SIMD又有两种用法。这里[2]介绍了两种数据组织方式,一种是Structure of Array(SoA),另一种是Array of Structure(AoS)。

structSOAPoint{floatx[N];floaty[N];floatz[N];floatw[N];};structAOSPoint{floatx;floaty;floatz;floatw;};AOSPointpoints[N];

如上所示,SoA是把一堆标量聚集在一起,然后按照所需的数据结构去排布。而AoS是先按照所需的数据结构去排布,然后再组成数组。

通常来说AoS的做法不太适合SIMD。因为数据结构里可能不止是xyzw的坐标,还可能有rgba的颜色,甚至一堆不相干、非向量的数据,这意味着你常要对不同的数据做不同的处理,而冗余数据还会影响内存局部性。如果是128bit的SSE,可以一条指令计算坐标一条指令计算颜色。但万一是256bit的AVX呢?坐标和颜色就很难用同一条指令去做相同的计算了。

而SoA就不一样了,一堆x坐标放在一起,做的是同样的运算。SSE和AVX的区别只是循环的步长不一样而已。(当然要是涉及到xyzw间互相运算就麻烦了)

那这有什么意义呢?联想一下SIMT,单指令,多线程,做同样的操作,一共N个线程……这不就是SoA嘛?!

换句话说,以前的GPU是AoS,每次操作坐标或者颜色的4个分量。现在的GPU是SoA,每次操作x个线程去运算同一个分量。这么做的好处就是不用局限于SIMD4,而与之相对的,对于单个线程来说,每次运算的也就变成了标量。

正如AoS和SoA只是SIMD的两种用法一样,新旧GPU也只是对SIMD单元的用法做了改变。你可以想象一个MxN的网格,以前按行处理,现在按列处理而已。

(当然更复杂的还有AoSoA等,就不细说了)

CUDA (Compute Unified Device Architecture)

CUDA是NVIDIA伴随着G80推出的。虽然名字以architecture结尾,但CUDA这个词却有很多不同的用法。

CUDA可以是和OpenCL、OpenGL类似的一种API,也可以算作装有N卡的平台。后来GPU里的向量单元被称作CUDA Core。

而CUDA的本质,是在GPU上跑通用计算。

CUDA使用PTX(Parallel Thread eXecution)来作为ISA。注意这并不是底层硬件用的ISA,而是一种Virutal ISA,Intel也有类似的东西叫VISA。PTX的作用是在源码和硬件指令集间建立一个通用、兼容的中间格式,你可以把它理解为C 到ASM之间的LLVM IR,或者是SPIR-V、DXIL,只不过并不是SSA形式的[3]

GPU的架构变化频繁,没有很固定的ISA,每代之间通常都有改变,所以分发机器码很容易出现不兼容或者不优化的情况。分发源码的话一来容易被破解,二来会浪费时间在一些重复的parsing、通用优化上。所以大家通常会建立一种比较兼容的中间格式。

Warp

随着CUDA引入的,还有个Warp的概念。

CUDA编程时,你只需要写单个线程要做的事情,然后指定多少个线程去跑就行了(它们可以被组织成1D、2D、3D的形式)。

但Warp的存在,意味着线程和线程之间并不是完全独立的,X个线程会被困成一束,一起执行。和SIMD一样,SIMT也有局限性。而对于N家卡,目前所有架构的X都是32。

SM (Steaming Multiprocessor)

SM单元的概念正是随着G80架构出现的。Streaming MultiprocessorStream Processor很相似,但看得出前者范围比后者大。

不过SM单元也随着时代变迁发生了许多巨大的变化。这篇文章就主要谈一谈SM的发展。


G80

相关推荐