线程束是为了提高效率打包的线程集合(NVIDIA称之为Warps,AMD称为Wavefronts) 。在每一个循环中的调度单位是Warp,同一个Warp内每个线程在同一时刻执行相同命令 。
取指与译码操作过程如下:
取指模块(I-Fetch)根据PC指向的指令,从内存中获取到相应的指令块 。需要注意的是,在GPGPU中,一般没有CPU中常见的乱序执行 。
文章插图
图 3-5 取指模块
- 指令缓存(I-Cache)读取固定数量的字节(对齐),并将指令位存储到寄存器中 。
- 对I-Cache的请求会导致命中、未命中或保留失败(Reservation fail) 。保留失败发生于未命中保持寄存器 (MSHR) 已满或指令缓存中没有可替换的区块 。不管命中或者未命中,循环取指都会移向下一Warp 。
在命中的情况下,获取的指令被发送到译码阶段 。在未命中的情况下,指令缓存将生成请求 。当接收到未命中响应时,新的指令块被加载到指令缓存中,然后Warp再次访问指令缓存 。 - 指令缓冲(I-Buffer)用于从I-Cache中获取指令后对译码后的指令进行缓冲 。最近获取的指令被译码器译码并存储在 I-Buffer 中的相应条目中,等待发射 。
- 每个 Warp 都至少对应两个 I-Buffer 。每个 I-Buffer 条目都有一个有效位(Valid)、就绪位(Ready)和一个存于此 Warp 的已解码的指令 。有效位表示在 I-Buffer 中的该已解码的指令还未发射,而就绪位则表示该Warp的已解码的指令已准备好发射到执行流水线 。
文章插图
图 3-4 指令缓冲
当Warp内的I-Buffer 为空时,Warp以循环顺序访问指令缓存 。(默认情况下,会获取两条连续的指令)这时对应指令在I-Buffer中的有效位被激活,直到该Warp的所有提取的指令都被发送到执行流水线 。
当所有线程都已执行,且没有任何未完成的存储或对本地寄存器的挂起写入,则 Warp 完成执行且不再取指 。当线程块中的所有Warp都执行完成且没有挂起的操作,标记线程块完成 。所有线程块完成标记为内核已完成 。
相对于CPU,GPU的前端一般没有乱序发射,每个核心的尺寸就可以更小,算力更密集 。
3.3 发射发射是指令就绪后,从指令缓冲进入到执行单元的过程 。
在(译码后的)指令发射阶段,指令循环仲裁选择一个Warp,将I-Buffer中的发射到流水线的后级,且每个周期可从同一Warp发射多条指令 。
所发射的有效指令应符合以下条件:
- 在Warp里未被设置为屏障等待状态;
- 在I-Buffer中已被设置为有效指令(有效位被置为1);
- 已通过计分板(Scoreboard)检查;
- 指令流水线的操作数访问阶段处于有效状态 。
在发射阶段,存储相关指令(Load、Store等)被发送至存储流水线进行相关存储操作 。其他指令被发送至后级SP(流处理器)进行相关计算 。
3.3.1 SIMT堆栈SIMT堆栈用于在Warp前处理SIMT架构的分支分化的执行 。一般采用后支配堆栈重收敛机制来减少分支分化对计算效率的负面影响 。
SIMT 堆栈的条目代表不同的分化级别,每个条目存储新分支的目标 PC、后继的直接主要再收敛 PC 和分布到该分支的线程的活动掩码 。在每个新的分化分支,一个新条目被推到栈顶;而当 Warp 到达其再收敛点时,栈顶条目则被弹出 。每个 Warp 的 SIMT 堆栈在该 Warp 的每个指令发出后更新 。
线程束分化
从功能角度来看,虽然SIMT架构下每个线程独立执行,但在实际的计算过程中会遇到一些分支的处理,即有些线程执行一个分支,而另外的线程则执行其他分支 。如果在同一个Warp内不同的线程执行不同的分支,就会造成线程束分化,导致后继SIMD计算的效率降低 。因此应尽量避免线程束的分化 。
文章插图
图 3-6 线程束分化与重聚合
SIMT堆栈功能
SIMT堆栈模块可有效改善线程束分化引起的GPGPU执行单元利用率下降的问题 。
SIMT堆栈重点解决:
控制流嵌套问题(Nested Control Flow)
推荐阅读
- 新车买完就降价,很多用户很害怕,买个二手车划算么?
- 史上最严标准国六B将至,多家车企建议给予6到12个月销售过渡期
- 为何酒店的房间内都要放4个枕头?女服务员:很多人都不懂怎么用
- 汽车的电瓶还有保质期?多久换一次,平时又要怎么保养?
- 口粮酒大盘点,众多品牌 ,众多香型,众多档次,你更喜欢哪一款呢
- 姜涛|网红姜涛模仿高启盛,半个月内发布三十多个作品,内容同质化严重
- 普吉岛|痞幼泰国被偶遇,脸上浮肿头发凌乱,从精致变邋遢,更多细节曝光
- 鞠婧祎|狗仔爆料助理摸鞠婧祎臀部!商场里多次伸手,两人关系引热议
- 碘吃多了有什么危害
- 香蕉泡白醋真的可以减肥吗