广义来说并行分为俩种,提高单元效率是时域并行,一般是通过提高 utilization,而增加单元数量则是空域并行。现代处理器中往往各种并行机制混合存在,本文旨对不同的并行机制分析归类。大部分并行机制都是针对俩个问题:1)解耦单元之间的依赖关系提高并行度 [1],以及2)访存问题,后续并行机制大都可以围绕这俩点分析,后文以问题一问题二概括之。
ILP:Core 内并行
Pipeline
流水线属于时域并行的一种。相比非流水化架构,不考虑额外引入的寄存器,硬件实际执行单元没有变化,抛开时钟在时间层面提高了硬件的 utilization。划分流水线的依据在于问题一:减少流水线上不同 stage 之间依赖关系,否则就要插入气泡或者停住流水线降低 utilization,比如 CISC 指令集复杂指令带来复杂的依赖关系,进而导致难以划分 stage,即使 RISC 中需要处理冒险问题[2]。
Superscalar Pipeline
超标量属于空域并行,直接添加流水线的数量。个人理解超标量的名称来自寻址特点,即寻址到多个 scalar 粒度,这与向量处理器 SIMD 寻址到单个 vector 粒度相对应。
TLP:Core 外并行
Multi-Core
因为线程和硬件之间隔了一个操作系统,一般来说线程没有直接对应的硬件单元概念,下文为理解清晰,假设没有操作系统,线程直接对应 core。多核并行也同于空域并行,但和超标量的区别是什么?
ILP 虽然做到同时跑多条指令,但指令之间的距离是相邻或相近的,就像有一个指令窗口在慢慢滑动。这是因为每个 core 用一个缓存,所有 ILP 都基于时间局部性共用同一个缓存的数据。而 TLP 不同的 core 之间有各自不同的缓存,就像好几个窗口(上下文)在程序中同时前进一样。TLP 和 ILP 的区别在于缓存。[3]
Hyper Thread
超线程一个物理核掰俩个逻辑用属于从另一个角度挖掘局部性。相邻指令对应的数据可能复用,但某个数据不一定对应相邻指令。当某个上下文窗口的数据用完,但这个数据还有其他上下文需要复用,便切换到另一个上下文状态复用缓存数据,同时 prefetch 内存。与真正的 multi-core 在于不同的线程共享了一个缓存,时间上分别复用执行和控制单元,同时附之额外存储单元恢复和还原现场完成上下文切换。
空域 | 时域 | |
---|---|---|
ILP | Superscalar | Pipeline |
TLP | Multi-Core | Hyper Thread |
单元互作用的讨论可见 https://www.cnblogs.com/devil-sx/p/18351623 ↩︎
缓存也并非完全独立,L1、L2、L3层层缓存,这几个窗口仍分布在某一个大窗口内。 ↩︎