0%

CPU微架构里的Flush概念

现代CPU为了高性能会进行各种投机的指令执行,反正目前CPU里有空余的硬件资源,放着
也是放着,CPU就提前执行一些指令,如果这些指令就是后续应该指令的指令,那么到时候
这些指令就可以直接完成,如果这些指令不是后面要执行的指令,CPU就把它们抛弃,也就是
常说的把它们刷掉(flush)。

一条指令在CPU的各个部件里可能占据资源,所以flush一条指令,指的是清理掉这条指令在
CPU占据的所有资源。如下是一个CPU的内部示意图,flush掉一条就要flush掉一条指令在各
个部件里占据的资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
                            +-------+   +----+
+-----+-->|issue q|-->| EX |\
|issue| +-------+ +----+ \
|logic| \
+----+ +----+ | | +-------+ +----+ \+-----+ +----+
| IF |-->| ID |-->| |-->|issue q|-->| EX |--->| MEM |--->| WB |
+----+ +----+ | | +-------+ +----+ /+-----+ +----+
| | /
| | +-------+ +----+ /
+-----+-->|issue q|-->| EX |/
+-------+ +----+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ old
ROB | | | | | | | | | | | | | | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^ ^ ^ \-------------/
allocate flush commit retired

flush一般要刷掉一堆指令,我们从ROB的角度去看,如上图所示,在某个时刻,发现要从
flush位置开始flush,那么flush到allocate位置上的所有指令都要刷掉。这里allocate是
最新进入流水线的指令的位置。

CPU里触发指令flush的原因有很多,总结起来大概可以有:1. 分支预测错了,要刷掉错误
执行的指令;2. load/store冲突,提前指令的load已经load的后续指令要刷掉;3. 异常或
中断后要跳到异常处理程序,所以异常或者中断后之前取入流水线的指令也要都刷掉。

和软件不一样,CPU硬件各个部件是在时钟信号的触发下同步执行的,也就是说一拍中可能
会产生多个flush请求,那么硬件就要综合计算下要怎么flush,直观上看,应该是从最老的
flush点开始做flush,就是从下图最靠右的flush点开始做flush,而且这个flush已经包含
了左边的各个flush。

1
2
3
4
5
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  old
ROB | | | | | | | | | | | | | | | | | | | | | | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^ ^ ^ ^ ^ \-------------/
allocate flush flush flush commit retired

当有flush请求时,说明检测到了硬件里错误投机的指令,flush这个动作应该马上进行,这
样被错误占据的硬件资源就可以被释放出来。但是,有时考虑到硬件实现的问题,也有先打
一个flush的标记,在后续合适的时间点再做具体的flush动作。