sexyrobto 发表于 2024-7-15 18:23

笔记-GPU硬件架构及运行机制

前言:见参考链接里的文章,本文只是个人整理笔记,只适合看过这篇文章的人抓重点内容。参考链接里的文章逻辑清晰,内容厚实,强烈保举大师去看一下。
参考链接:深入GPU硬件架构及运行机制
目录:
1.笔记
2.答题
1.笔记:

一、GPU物理架构
2010 - Fermi
(从Fermi开始GPU被划分成多个GPCs(Graphics Processing Cluster),每个GPC拥有多个SM(流多措置器)和一个光栅化引擎(Raster Engine))
拥有16个SM(法式员编写的shader是在SM上完成的)
{
每个SM:
2个Warp(线程束)
两组共32个Core单元(LD/ST)(load/store)模
16组加载存储块来加载和存储数据
4个特殊函数单元(SFU)(Special function units)执行特殊数学运算(sin、cos、log等)
每个Warp(线程束):
16个Core(运算核心,也叫流措置器Stream Processor)
Warp编排器(Warp Scheduler)一个由32个线程组成,通过Dispatch Units送到Core执行。
分发单元(Dispatch Unit)
每个Core:
1个FPU(浮点数单元)
1个ALU(逻辑运算单元)
}
64KB L1缓存
全局内存缓存(Uniform Cache)
纹理读取单元
纹理缓存(Texture Cache)
PolyMorph Engine:多边形引擎负责属性装配(attribute Setup)、顶点拉取(VertexFetch)、曲面细分、栅格化(这个模块可以理解专门措置顶点相关的东西)。
内部链接网络(Interconnect Network)
//SP(Streaming Processor,流措置器)
//GPC(图形措置簇)
// TPC(纹理措置簇)
//Memory内存
//Register File寄存器
//ROP(render output unit,衬着输入单元),措置深度测试,和framebuffer的混合
//SIMD(Single Instruction Multiple Data)是单指令大都据,
//co-issue可以通过合并1D与3D或2D与2D的指令解决着色器在低维向量操作率低的问题
二、GPU逻辑管线
法式通过图形API(DX)发出drawcall指令,指令被推送到驱动法式,驱动法式查抄指令合法性并放到GPU可以读取的Pushbuffer中。颠末一段时间或显式调用flush指令后,驱动法式把Pushbuffer的内容发送给GPU,GPU通过主机接口Host interface 接受这些命令并通过前端Front End措置这些命令。在图元装配器Primitive Distributor中开始工作分配,措置indexbuffer中顶点发生三角形形成批次batches,然后发送给多个GPCs,即提交上来n个三角形,分配给这几个GPC同时措置。在GPC中每个SM中的PolyMorph Engine负责通过三角形索引triangle indices取出三角形的数据,然后SM中以32个线程为一组的线程束Warp来调剂开始措置顶点数据,Wrap是典型的单指令多线程(SIMT)的实现,即32个线程同时执行不异的指令只是县城数据纷歧样,这样warp只需要一套逻辑对指令进行解码和执行就可以了。Sm的warp调剂器会按照挨次分发指令给整个warp,单个warp中的线程会锁步lock-step执行各自的指令,如果线程碰到不激活执行的情况也会被遮掩例如if true的分支。但当前线程数据的条件是false或循环次数纷歧样。因此shader中分支会显著增加时间消耗,在一个warp中的分支除非32个线程都走到if或else里面否则相当于所有的分支都走了一遍。线程不能独立执行指令而是以warp为单元,这些warp之间才是独立的。
由于warp中的指令完成时间纷歧,出格是内存加载,warp调剂器可能会简单的切换到另一个没有内存等待的warp,这是GPU客服内存读取延迟的关键,只是简单的切换活动线程组。为了使这种切换非常快,调剂器打点的所有warp在寄存器文件中都有本身的寄存器。这里就有个矛盾,shader需要越多的寄存器就会给warp留下越少的空间发生越少的warp,这时碰到内存延迟的时候就会只是等待而没有可以运行的warp可以切换。
一旦warp完成了vertexshader的所有指令,运算成果会被Viewport transform模块措置,三角形会被裁剪然后筹备栅格化,GPU会使用L1和L2缓存来进行vertex-shader和pixel-shader的数据通信。接下来这些三角形将被分割,再分配给多个GPC,三角形的范围决定着它将被分配到哪个光栅引擎(raster engines),每个raster engines覆盖了多个屏幕上的tile,这等于把三角形的衬着分配到多个tile上面。也就是像素阶段就把按三角形划分变成了按显示的像素划分了。
SM上的Attribute Setup保证了从vertex-shader来的数据颠末插值后是pixel-shade是可读的。
GPC上的光栅引擎(raster engines)在它接收到的三角形上工作,来负责这些这些三角形的像素信息的生成(同时会措置裁剪Clipping、背面剔除和Early-Z剔除)。32个像素线程将被分成一组,或者说8个2x2的像素块,这是在像素着色器上面的最小工作单元,在这个像素线程内,如果没有被三角形覆盖就会被遮掩,SM中的warp调剂器会打点像素着色器的任务。接下来的阶段就和vertex-shader中的逻辑法式完全一样,但是变成了在像素着色器线程中执行。 由于不耗费任何性能可以获取一个像素内的值,导致锁步执行非常便当,所有的线程可以保证所有的指令可以在同一点。
最后一步,此刻像素着色器已经完成了颜色的计算还有深度值的计算,在这个点上,我们必需考虑三角形的原始api挨次,然后才将数据移交给ROP(render output unit,衬着输入单元),一个ROP内部有很多ROP单元,在ROP单元中措置深度测试,和framebuffer的混合,深度和颜色的设置必需是原子操作,否则两个分歧的三角形在同一个像素点就会有冲突和错误。
//统一着色器架构:VS和PS用的都是不异的Core。同一个Core既可以是VS又可以是PS。
//像素块(Pixel Quad) 2x2的像素块是在像素着色器上面的最小工作单元
内存架构多级缓存布局:寄存器、L1缓存、L2缓存、GPU显存、系统显存。这种架构的特点是ALU多,GPU上下文(Context)多,吞吐量高,依赖高带宽与系统内存交换数据。

CPU-GPU数据流:将主存的措置数据复制到显存中。CPU指令驱动GPU。GPU中的每个运算单元并行措置。此步会从显存存取数据。GPU将显存成果传回主存。
显像机制:双缓冲GPU 会预先衬着一帧放入一个缓冲区中,用于视频控制器的读取。当下一帧衬着完毕后,GPU 会直接把视频控制器的指针指向第二个缓冲器。
垂直同步:V-Sync当开启垂直同步后,GPU 会等待显示器的 VSync 信号发出后,才进行新的一帧衬着和缓冲区更新。这样能解决画面扯破现象。
2.答题

1、GPU是如何与CPU协调工作的?
如分手式架构,CPU和GPU各自有独立的缓存和内存,数据流:1.将主存的措置数据复制到显存中。2、CPU指令驱动GPU。3、GPU中的每个运算单元并行措置。此步会从显存存取数据。4、GPU将显存成果传回主存。
2、GPU也有缓存机制吗?有几层?它们的速度差异多少?
①部门GPU有多级缓存布局:寄存器、L1缓存、L2缓存、GPU显存、系统显存。
②有两层



③shader直接访谒寄存器、L1、L2缓存还是斗劲快的,但访谒纹理、常量缓存和全局内存非常慢,会造成很高的延迟。
3、GPU的衬着流程有哪些阶段?它们的功能分袂是什么?



①法式通过图形API发出drawcall指令到驱动法式,驱动查抄指令合法性放到Pushbuffer。
②驱动法式把Pushbuffer的内容发送给GPU,GPU通过主机接口接受并通过前端措置。
③在图元分配器(Primitive Distributor)工作分配,三角形分成批次(batches)发送给多个GPCs。
④GPC中每个SM中的Poly Morph Engine负责通过三角形索引取出数据,即Vertex Fetch。



⑤获取数据之后,在SM中以线程束(Warp)来调剂措置顶点数据,Warp是典型的SIMT。
⑥warp调剂器分发指令,单个warp的线程锁步执行各自指令。指令可一次完成可多次调剂
⑦由于指令完成时间纷歧,出格是内存加载,warp调剂器可能会简单地切换,为了使这种切换非常快,调剂器打点的所有warp在寄存器文件中都有本身的寄存器。(这里就会有个矛盾发生,shader需要越多的寄存器,就会给warp留下越少的空间,就会发生越少的warp,这时候在碰到内存延迟的时候就会只是等待,而没有可以运行的warp可以切换。)
⑧warp完成vertex-shader的所有指令,运算成果会被Viewport Transform模块措置,三角形被裁剪筹备栅格化,GPU使用L1和L2缓存来进行vertex-shader和pixel-shader的数据通信。
⑨接下来这些三角形将被分割,再分配给多个GPC,三角形的范围决定着它将被分配到哪个光栅引擎(raster engines),每个raster engines覆盖了多个屏幕上的tile,这等于把三角形的衬着分配到多个tile上面。GPC上的光栅引擎(raster engines)在它接收到的三角形上工作,来负责这些这些三角形的像素信息的生成(同时会措置裁剪Clipping、背面剔除和Early-Z剔除)。32个像素线程将被分成一组,或者说8个2x2的像素块,这是在像素着色器上面的最小工作单元,在这个像素线程内,如果没有被三角形覆盖就会被遮掩,SM中的warp调剂器会打点像素着色器的任务。
⑩接下来的阶段就和vertex-shader中的逻辑法式完全一样,但是变成了在像素着色器线程中执行。 由于不耗费任何性能可以获取一个像素内的值,导致锁步执行非常便当,所有的线程可以保证所有的指令可以在同一点。最后一步,此刻像素着色器已经完成了颜色的计算还有深度值的计算,在这个点上,我们必需考虑三角形的原始api挨次,然后才将数据移交给ROP(render output unit,衬着输入单元),一个ROP内部有很多ROP单元,在ROP单元中措置深度测试,和framebuffer的混合,深度和颜色的设置必需是原子操作,否则两个分歧的三角形在同一个像素点就会有冲突和错误。



4、Early-Z技术是什么?发生在哪个阶段?这个阶段还会发生什么?会发生什么问题?如何解决?
①Early-Z技术可以将很多无效的像素提前剔除,避免它们进入耗时严重的像素着色器。Early-Z剔除的最小单元不是1像素,而是像素块
②为了减少像素着色器的额外消耗,将深度测试提至像素着色器之前,这就是Early-Z技术的由来。



③开启Alpha Test,Alpha Blend,Tex Kill,Multi-Sampling任一,封锁深度测试城市导致Early-Z掉效。此外,Early-Z技术会导致一个问题:深度数据冲突。
④例子要结合左下图,假设数值深度值5已经颠末Early-Z即将写入Frame Buffer,而深度值10刚好处于Early-Z阶段,读取并对比当前缓存的深度值15,成果就是10通过了Early-Z测试,会覆盖掉比本身小的深度值5,最终frame buffer的深度值是错误的成果。



避免深度数据冲突方式之一是在写入深度值前,再次与frame buffer的值进行对比:右上图
5、SIMD和SIMT是什么?它们的好处是什么?co-issue呢?
①SIMD是单指令大都据在GPU的ALU单元内,一条指令可以措置多维向量(一般是4D)的数据。好处是需要多条指令的有了SIMD技术后一条指令即可措置完。



②SIMT是SIMD的升级版,可对GPU中单个SM中的多个Core同时措置同一指令,而且每个Core存取的数据可以是分歧的即a、b 、c的值可以纷歧样。
③co-issue是为了解决SIMD运算单元无法充实操作的问题,但是,对于向量运算单元(Vector ALU),如果此中一个变量既是操作数又是存储数的情况,无法启用co-issue技术。于是标量指令着色器(Scalar Instruction Shader)应运而生,它可以有效地组合任何向量,开启co-issue技术,充实阐扬SIMD的优势。
6、GPU是并行措置的么?若是,硬件层是如何设计和实现的?
是。
7、GPC、TPC、SM是什么?Warp又是什么?它们和Core、Thread之间的关系如何?
①Turing架构GPU包含6个GPC,每个GPC有6个TPC,每个TPC有2个SM。
GPC(图形措置簇Graphics Processing Cluster) TPC(纹理措置簇Texture/Processor Cluster)SM(流多措置器Stream Multiprocessor)
②每个SM包含许多为线程执行数学运算的Core(核心,也叫流措置器Stream Processor),这些Core和其它单元由Warp Scheduler驱动,Warp Scheduler打点一组32个线程作为Warp(线程束)并将要执行的指令移交给Dispatch Units。
8、顶点着色器(VS)和像素着色器(PS)可以是同一措置单元吗?为什么?
可以,用了统一着色器架构(Unified shader Architecture)的GPU,VS和PS用的都是不异的Core。也就是,同一个Core既可以是VS又可以是PS。
这样就解决了分歧类型着色器之间的不服衡问题,还可以减少GPU的硬件单元,压缩物理尺寸和耗电量。此外,VS、PS可还可以和其它着色器(几何、曲面、计算)统一为一体。
9、像素着色器(PS)的最小措置单元是1像素吗?为什么?会带来什么影响?
①不是。像素着色器的最小工作单元是8个2x2的像素块,因为32个像素线程被分成一组。
②可简化和加速像素分拨。精简SM的架构。降低功耗。可辅助有效像素求导函数。
③会激化过绘制(Over Draw)的情况,损耗额外的性能。
10、Shader中的if、for等语句会降低衬着效率吗?为什么?
会。SM中有8个ALU(Core),由于SIMD的特性,每个ALU的数据纷歧样,导致if-else语句在某些ALU中执行的是true分支,有些ALU执行的是false分支,这样导致很多ALU的执行周期被浪费掉了(即masked out),拉长了整个执行周期。最坏的情况,同一个SM中只有1/8(8是同一个SM的线程数,分歧架构的GPU有所分歧)的操作率。
同样,for循环也会导致类似的情形,由于每个ALU的count纷歧样,加上有break分支,导致最快执行完shader的ALU可能是最慢的N分之一的时间,但由于SIMD的特性,最快的阿谁ALU依然要等待最慢的ALU执行完毕,才能接下一组指令的活!也就白白浪费了很多时间周期。
11、如下图,衬着不异面积的图形,三角形数量少(左)的还是数量多(右)的效率更快?为什么?



左边更快
因为不异面积的区域,如果所属的三角形越多,就会导致分配给SM的次数越多,消耗的衬着性能也越多。
12、GPU Context是什么?有什么感化?
①GPU Context代表了GPU计算的状态。在GPU中拥有本身的虚拟地址。GPU 中可以并存多个活跃态下的Context。
②由于SIMT技术的引入,导致很多同一个SM内的很多Core并不是独立的,当它们傍边有部门Core需要访谒到纹理、常量缓存和全局内存时,就会导致非常大的卡顿(Stall)
例如有4组上下文(Context),它们共用同一组运算单元ALU。越多Context可用就越可以提升运算单元的吞吐量。



13、造成衬着瓶颈的问题很可能有哪些?该如何避免或优化它们?
①减少CPU和GPU的数据交换:
合批(Batch)
减少顶点数、三角形数
视锥裁剪
BVH
Portal
BSP
OSP
避免每帧提交Buffer数据
CPU版的粒子、动画会每帧改削、提交数据,可移至GPU端。
减少衬着状态设置和查询
例如:glGetUniformLocation会从GPU内存查询状态,耗费很多时间周期。
避免每帧设置、查询衬着状态,可在初始化时缓存状态。
启用GPU Instance
开启LOD
避免从显存读数据
②减少过绘制:
避免Tex Kill操作
避免Alpha Test
避免Alpha Blend
开启深度测试
Early-Z
层次Z缓冲(Hierarchical Z-Buffering,HZB)
开启裁剪:
背面裁剪
遮挡裁剪
视口裁剪
剪切矩形(scissor rectangle)
控制物体数量
粒子数量多且面积小,由于像素块机制,会加剧过绘制情况
植物、沙石、毛发等也如此
③Shader优化:
避免if、switch分支语句
避免for循环语句,出格是循环次数可变的
减少纹理采样次数
禁用clip或discard操作
减少复杂数学函数调用
页: [1]
查看完整版本: 笔记-GPU硬件架构及运行机制