Mar 31, 2022 ✧ 字数统计:3.3k(字) ♨︎ 阅读时长:11(分钟)
本文介绍计算机系统中采用的流水线技术,包括流水线相关的基础知识、工作原理、流水线技术对性能的改进、吞吐率、加速比和效率等相关的计算以及存在的问题等内容。
流水线技术简单介绍流水线技术通过并行硬件(利用时间并行性,区别于空间并行性)来提高计算机系统的性能。
流水线技术把一项任务分解成若干项顺序执行的子任务,不同的子任务由不同的操作部件来负责执行,而这些部件可以同时并行工作,这项技术的关键在于重叠执行
,通过这种方式可以在不增加硬件或者只增加少量硬件的前提下数倍的提升处理机运算速度。
根据使用情况的不同,流水线可以分成三个级别:
(1)操作部件级流水线(运算符操作流水线) 将复杂的算术运算和逻辑运算组成流水线的工作方式。
(2)指令级流水线 把一条指令的执行过程分解成多个阶段,比如可以把某个指令分解为:取指令、分析指令、执行指令三个阶段。
(3)处理机间级流水线(宏流水线) 由 N(N>=2)个处理机通过存储器串行连接,每个处理机完成某项专门的任务,各个处理机所得到的结果需要存放到跟下一个处理机所共享的存储器里面。
根据流水线的实际应用,可以从不同角度进行分类。
静态流水线:在同一时间内只能按照一种运算的连接方式进行工作(一定是单功能)。
动态流水线:在同一时间内允许按照多种不同运算的连接方式工作(一定是多功能)。
线性流水线:从输入到输出,每个功能段只允许经过一次,不存在反馈回路。
非线性流水线:从输入到输出,某些功能段将数次通过流水线,存在反馈回路,常用于递归调用。
单功能流水线:只能实现某种固定的功能,比如加法运算。
多功能流水线:各段可以进行不同的连接,通过不同的连接方式来实现不同的功能(资源利用率较高也更灵活,但控制更复杂)。
-
流水线中处理的必须是连续的任务。
-
在流水线每个操作部件的后面,都要有一个缓冲寄存器(锁存器),称为流水寄存器,这个缓冲寄存器用于保存本阶段的执行结果,以保证各个部件之间的速度是匹配的,以及各个部件独立、并行运行。换句话说,流水寄存器用于在相邻的两段“操作”之间传送数据,以保证提供后面要用到的数据的供应,并把各段的处理工作相互隔离。
-
因为流水线的主要工作方式是把大的操作任务分解为多个独立的、小的操作部件,依靠多个操作部件并行工作来缩短程序执行时间的。因为流水线中各段的执行时间应该尽量相等,执行时间最长的一段将成为整个流水线的瓶颈。
-
流水技术适合于大量重复的时序过程,只有在输入端连续不断提供任务的情况下,才能充分发挥流水线的效率。
-
流水线中存在排入时间和排空时间。
上面这张图是我画的抽象之后的典型 5 级 CPU 执行流水线,但这张图其实没有办法表述清楚“多道工序同时执行”这个流水线技术最重要的特征,所以下面我通过时空图
来描述流水线的工作。流水线的处理方向与之相对应的是多个任务按照顺序挨个执行。
我们假设某个处理机的执行指令分成三个阶段,分别是取指、分析和执行,假设每个阶段执行需要时间都是 t,那么上面左侧的图片描述的指令顺序执行的时空图,上面右侧的图片描述的是指令流水线执行的时空图。
我们可以通过上面的图示看出,顺序执行 3 条指令,需要的时间是 9t,流水线方式执行需要的时间是 5t,流水线采用的执行方式其实就是取指、分析和执行三个阶段部件在同时并发的工作,在第 1 条指令的执行阶段,同时分析第 2 条指令,取第 3 条指令。
如果不好理解的话,可以把这个场景类比为一个三个人 A\B\C 在对苹果进行操作的过程,其中 A 负责把苹果放入到水槽中,B 负责清洗水槽中的苹果,C 负责把水槽中的苹果捞起来装到袋子中,每次只能操作一个苹果。严格的顺序执行,类似于 A 在做“把第一个苹果放入到水槽中”这个动作的时候,B 和 C 处于等待的状态,当这个动作完成后,B 执行“清洗水槽中的这个苹果”这个操作,此时 A 处于无事可做的状态,C 处于等待的状态,当清洗完成后,C 开始执行“把水槽中的苹果捞起来装到袋子中”这个动作,此时 A 和 B 处于空闲的状态。
假设有 n 个苹果需要处理,每个苹果处理的三个阶段的单位时间都是 t,那么:
顺序执行的工作方式需要的时间为:n x 3 x t
流水线执行工作方式需要的时间可以这样计算:3 x t + (n-1) x t
这里在进行计算的时候,其实我们涉及到了多个参与量,它们包括指令的数量
、指令的执行阶段
、每个指令执行阶段需要的单位时间
,在上面的案例中,指令的数量为 3 条,指令的执行阶段为 3 个,每个指令执行阶段需要的单位时间我们假设都是相等的。接下来,我们来看一个稍微复杂点的情况。
假设:
指令的数量(n):4条
指令的执行阶段(k):4个
每个指令执行阶段需要的单位时间:为t
我们来看个更复杂的情况
假设:
指令的数量(n):3条
指令的执行阶段(k):4个
每个指令执行阶段需要的单位时间:A(1t) B(3t) C(2t) D(1t)
由此,我们可以总结出一个指令流水线完成 n 个任务所需要总时间的计算公式:
\[T_k = \sum_{i=1}^kt_i + (n -1 ) max(t_1,t_2,···,t_k) \]另外,从上图我们也能看出,流水线的性能瓶颈取决于多个操作中每个执行阶段所需要的最长单位时间(取 t1,t2,t3,t4,···tk 的最大值
),在设计流水线的时候应该尽可能的让每个操作的执行单位时间都相等。
我们可以通过吞吐率、加速比和流水线的效率等指标衡量某段流水线性能的优劣。
吞吐率( Though Put rate, TP )
吞吐率指的是在单位时间内流水线所完成的任务数量或输出的结果数量。
吞吐率的计算公式为:
其中,n 表示任务(指令)的数量。
假设,现在有一条线性流水线共分成 k 段,各段的执行时间分别是 t1,t2,···tk,那么该流水线完成 n 个连续任务需要的总时间为:
\[T_k = \sum_{i=1}^kt_i + (n -1 ) max(t_1,t_2,···,t_k) \]通过推断,我们可以得出该流水线的实际吞吐率为:
\[TP = \frac n{ \sum_{i=1}^kt_i + (n -1 )max(t_1,t_2,···,t_k)} \]此时,该流水线的最大吞吐率为:
\[TP_{max} = \frac 1{ max(t_1,t_2,···,t_k)} \]从上面的公式可以看出,当流水线中各段执行时间不完全相等的时候,吞吐率主要由流水线中执行最长的那个功能段来决定,这个功能段也就成了整个流水线的瓶颈,它的执行时间被称为瓶颈时间。解决可以问题,可以考虑把瓶颈段再进行细分,让瓶颈的时间变小。
说明 流水线的实际吞吐率要小于最大吞吐率。只有当 n >= k 的时候,它们才约等。
假设现在有一条6段线性流水线,它们的单位执行时间分别是1ns,2ns,3ns,4ns,3ns,2ns,那么:
该流水线完成10个连续任务需要的总时间 = (1 + 2 + 3 + 4 + 3 + 2) + (10 -1)4 = 15 + 36 = 51ns
该流水线的实际吞吐率 = 10 / 51 = 0.196
该流水线的最大吞吐率 = 1 / 4 = 0.25
比较理想的情况是,一条 k 段连续流水线中的每段执行时间均相等(设为 t),那么:
该流水线完成 n 个连续任务需要的总时间可以表示为:
因此,实际的吞吐率为:
\[TP = \frac n{T_k} = \frac {n}{ kt + (n - 1)t} = \frac {n}{ (k + n - 1)t} \]此时,最大的吞吐率为:
\[TP_{max} = \lim_{n \to \infty} \frac {n}{ (k + n - 1)t} = \frac {1}{t} \]假设上面这段流水线中每一段执行时间都是等量的,比如2ns,那么我们再计算一遍:
该流水线完成10个连续任务需要的总时间 = (2 + 2 + 2 + 2 + 2 + 2) + (10 -1)2 = 12 + 18 = 30ns
该流水线的实际吞吐率 = 10 / 30 = 0.333
该流水线的最大吞吐率 = 1 / 2 = 0.5
加速比( Speedup Ratio, S )
加速比是衡量流水线性能的另一个关键指标,它其实指的是不使用流水线(顺序)执行和使用流水线来执行同一段任务所用总时间的比。
计算流水线加速比的基本公式为:
\[S = \frac {T_o}{ T_k } \]当流水线的各个流水段的执行时间不相等的时候,一条 k 段线性流水线完成 n 个连续任务的实际加速比可以表示为:
\[S = \frac {n\sum_{i=1}^kt_i}{ \sum_{i=1}^kt_i + (n -1 )max(t_1,t_2,···,t_k)} \]假设,某流水线分为 5 段,若每一段所需要的时间分别为 1ns、2ns、3ns、4ns、2ns,那么该流水线的加速比为:
\[S = \frac {(1 + 2 + 3 + 4 + 2)n}{ (1 + 2 + 3 + 4 + 2)+4(n-1)} = \frac {12n}{12 + 4(n-1)} = \frac {3n}{ 3 + n -1} \]假设现在有一条4段线性流水线,它们的单位执行时间分别是1ns,2ns,3ns,1ns那么:
顺序执行完成10个连续任务需要的总时间 = (1 + 2 + 3 + 1) * 10 = 70
该流水线完成10个连续任务需要的总时间 = (1 + 2 + 3 + 1) + 3 * (10 -1) = 34
该流水线的实际加速比 = 70 / 34
备注:3的值来自于取(1ns,2ns,3ns,1ns)中的最大值
同理,理想的情况是,一条 k 段连续流水线中的每段执行时间均相等(设为 t),那么:
该流水线完成 n 个连续任务的实际加速比为:
\[S = \frac {nkt}{ (K+n-1)t } = \frac {nk}{k+n-1} \]这种情况下的最大的加速比为:
\[S_{max} = \lim_{n \to \infty} \frac {nk}{k+n-1} = k \]假设现在有一条4段线性流水线,它们的单位执行时间都是1ns那么:\
顺序执行完成10个连续任务需要的总时间 = (1 + 1 + 1 + 1) * 10 = 40\
该流水线完成10个连续任务需要的总时间 = (1 + 1 + 1 + 1) + 1 * (10 -1) = 13\
该流水线的实际加速比 = 40 / 13
效率(E)
流水线的效率指的是流水线的设备利用率,流水线的效率包含时间和空间两部分的因素。
流水线的效率被定义为 n 项任务所占用的时空区与 k 个流水段总的时空区之比。
实际上,n 项任务所占用的时空区其实就是顺序执行 n 项任务所使用的总时间。
计算流水线效率的一般公式为
如果流水线各段的执行时间不相等,那么连续执行 n 项任务时的流水线效率为:
\[E = \frac {n\sum_{i=1}^kt_i}{ k(\sum_{i=1}^kt_i + (n -1 )max(t_1,t_2,···,t_k))} \]如果流水线中的每段执行时间均相等(设为 t),而且输入的 n 项任务是连续的,那么一条 k 段流水线的效率为:
\[E = \frac {nkt}{k(k + n -1)t} = \frac {n}{k + n -1} \]此时,流水线的最高效率为:
\[E_{max} = \lim_{n \to \infty} \frac {n}{k + n -1} = 1 \]由上面的数学公式可以看出,当流水线的效率达到最大值 1 的时候,这时流水线的各段均处于忙碌的状态。
结合计算流水线加速比的公式,流水线的效率可以表示为:
\[E = \frac Sk \]公式转换一下,则流水线的吞吐率可以理解为流水线的效率和单位时间的比值。
\[TP = \frac Et \]从上面的公式,我们可以看出当时钟周期t不变的时候,流水线的效率与吞吐率成正比
。
吞吐率、加速比和效率这些指标都可以用来衡量一条流水线的性能,为了得到比较高的性能,流水线应该尽可能满负荷工作。
综合来看,增加流水线的段数(k的值),流水线的吞吐率和加速比都能提高,但因为每个操作段的输出端都必须要设置一个锁存器(缓冲寄存器),因此当段数增多的时候,锁存器(缓冲寄存器)的总延迟时间也会随之增加,且增加锁存器(缓冲寄存器)的数量,不可避免的要增加流水线的价格成本。因此,在设计流水线的时候需要综合考虑各方便的因素,以选择流水线的最佳段数。
系统中也可能存在多条流水线,假如采用度量为i的超标量流水线处理机来连续处理n条指令,那么因为同时运行了i条流水线,因此平均每条流水线只需要执行n/i条指令。
此外,在实际的情况中,还需要注意流水线中的各段可能会相互影响,阻塞流水线以影响性能。