H19

CPU 流水线

点击正文段落选定收藏或划线位置;未选定时使用屏幕内第一段。

课内目录

一块主板上,CPU 插座、内存插槽、存储接口和网卡接口各有分工。即使 CPU 的时钟频率不变,程序处理数据的速度也可能相差很大。本课从 CPU 内部的流水线出发,解释指令为什么能重叠推进、为什么又会互相等待。我们使用便于画图的 5 级、顺序、单发射教学模型;真实芯片的级数、执行资源和恢复机制需要查阅对应资料,不能从这张模型图反推。

1 流水线要解决的吞吐问题

设想 CPU 要连续处理 1000 条指令,每条指令都要经过取指、译码、执行、访存和写回。如果等当前指令走完全部步骤,才允许后续指令开始,那么某个步骤工作时,其余步骤的大部分资源就会闲着。流水线的思路是把这些步骤分给不同阶段,让不同指令在同一时刻占用不同阶段。它主要改善连续完成任务的速度,也就是吞吐率。

吞吐率与延迟要分开。延迟关注某条指令从进入到完成用了多久;吞吐率关注持续运行时,每段时间完成多少条指令。在理想的 5 级模型中,某条指令仍要穿过 5 个阶段,但填满流水线后,每个周期都可能完成 1 条指令。看见连续几个周期都有结果出现,并不意味着每条指令都只经历了 1 个周期。

先采用很强的假设:每级都恰好需要 1 个周期,阶段间没有额外开销,也没有任何冲突。连续完成 N 条指令需要 N+4 个周期。最前面的 4 个周期用于让首条指令接近出口,后面的指令依次到达。若 N=20,共需 24 个周期,平均每周期完成约 0.83 条;若 N=1000,则需要 1004 个周期,平均值才接近 1。

指令重叠推进以及 CPU 与主板部件的边界
指令重叠推进以及 CPU 与主板部件的边界

这里的时钟周期不能随意当成真实时间。未流水化的设计可能用较长周期完成全部工作,流水化后则可以缩短周期。为了直观比较,若每步工作都需要 1 ns,串行完成 20 条指令的理想时间为 100 ns,而上述流水线需要 24 ns。这只是忽略阶段开销的算例,不是任何实物 CPU 的速度承诺。

实际阶段很难完全均衡,阶段之间还要用寄存器保存中间状态。这些寄存器的建立时间、时钟分配和控制逻辑都占预算。把流水线切得更细,可能提高频率,却也可能增加等待和恢复成本。因此“阶段越多,吞吐越高”不是普遍成立的规则;频率变化与每条指令花费的周期必须一起看。

把场景放回机箱:一台服务器配有 8 核 CPU、32 GiB 内存、PCIe 4.0 x4 NVMe 固态盘和 10 GbE 网卡。网卡把数据送入内存后,CPU 执行解析与校验指令,流水线才直接参与这些指令的推进。如果网口已经接近线速,CPU 再快也未必增加网络吞吐;如果 CPU 在等待内存,单看主频同样解释不了等待。

学习流水线时要先确定观察单位。这里研究 1 个核心内的指令重叠,不把 8 核并行、程序线程数和网卡吞吐混在一起。后文的“每周期 1 条”指教学模型稳定运行时的理想上限。真实芯片可能具有多个发射通道,也可能因为依赖而长期达不到其上限,这些现象需要分别说明。

2 取指-译码-执行-访存-写回

我们用 F、D、E、M、W 表示 5 个阶段。F 是取指,根据程序计数器给出的地址取得指令;D 是译码,识别操作并读取需要的寄存器;E 是执行,完成算术、逻辑运算或地址计算;M 是访存,对加载和存储访问数据通路;W 是写回,把需要保存的结果写入寄存器。阶段名称描述主要职责,不表示所有指令都做完全相同的事。

例如加载指令 LD R1, 0(R2) 表示从 R2 指向的地址读取数据并放入 R1。D 读取 R2,E 计算有效地址,M 发出或完成模型规定的数据访问,W 更新 R1。加法指令 ADD R3, R1, R4 则在 E 计算结果,经过 M 时不需要读取内存,最后在 W 更新 R3。在固定 5 级图中,这条加法仍保留 M 所在的时间格。

存储指令把寄存器中的数据写向内存体系,通常没有通用寄存器结果可供 W 写回。分支指令则要决定接下来从哪个地址取指。为了让图可以逐周期推演,本课统一让分支在 E 结束时得到方向和目标;真实处理器可能在别处完成判断。只要改动这些时点,冲突分析就必须跟着改,不能直接套用结论。

5 个阶段的职责与阶段寄存器
5 个阶段的职责与阶段寄存器

每个阶段之间都有保存中间状态的位置。需要传递的不只是算术数值,还包括目标寄存器编号、是否需要写回、访存类型以及这条指令是否有效。否则,当某条指令到达 W 时,控制逻辑就可能把属于其他指令的结果写到错误位置。教学图中的每个格子因此代表指令及其随行状态,而不只是数据经过某根导线。

动画先放入 4 条互不依赖的寄存器运算。第 1 个周期只有 F 有工作,第 3 个周期 F、D、E 同时工作,但它们分别属于不同指令。第 5 个周期首条指令写回,第 8 个周期最后 1 条写回。可以用这个过程检查“同时”这个词的含义:不同硬件阶段在同一周期工作,并不是某条指令在同一周期完成全部阶段。

本课暂定取指与数据访问拥有足够独立的资源,并且命中时 M 用 1 个周期完成。这只是为了隔离流水线机制。真实 CPU 通常先访问缓存,缓存未命中后才可能继续访问其他层次乃至主内存。不能把图里的 M=1 理解为 DDR 内存只需 1 个核心周期,也不能把固态盘读请求直接放进这个时间格。

CPU 加载指令访问的是地址空间中的数据;读取存储设备上的文件还需要操作系统、设备控制器和数据搬运等环节。主板上的 DDR 通道、PCIe 链路和网口速率分别约束不同路径。分清这些边界,才不会把一次 NVMe 读取的延迟全部归为“访存阶段太慢”,也不会用增加流水线阶段的方法解释外设吞吐变化。

3 冒险:数据、控制与结构

让指令重叠以后,前后关系就会变成约束。硬件中把可能阻止指令按预期推进的情况称为冒险。它不是概率很低的异常事故,而是正常程序中经常出现的依赖与资源争用。入门时先区分数据冒险、控制冒险和结构冒险,分别回答“值准备好了吗”“该取哪条指令”“资源够不够用”。

数据冒险最容易从寄存器依赖看出来。若前面的加载要写 R1,紧跟的加法要读 R1,那么加法必须拿到这次加载的新值。按程序顺序阅读汇编时,这种要求很自然;重叠执行后,加法可能在加载尚未写回时就到达 D。若直接读取寄存器里的旧值,程序就可能算错,所以必须有检测和等待或转发机制。

本课只重点讨论“前面的写、后面的读”这种真依赖。在当前顺序模型中,它决定后面的计算什么时候能开始。其他读写顺序问题与更复杂的执行方式有关,留到后续课程。也要注意,依赖本身不一定导致停顿:如果值已经产生,并且有可用通路及时送到消费者,执行就可以继续。

控制冒险发生在下一条指令地址尚未确定时。例如程序先比较报文长度,再决定走正常解析还是错误处理。分支结果尚未得到,F 就面临选择。可以等待结果,也可以先按某个方向取指;如果先取的方向错误,就要使较新的错误路径指令失效,并从正确位置重新取指。这里损失的是有效工作机会。

结构冒险则是多个阶段同时需要同一份、但容量不够的资源。假设某个简化处理器只有 1 个单端口存储器端口,F 正想读指令,M 又正想读数据,那么同周期只能满足其中的 1 次访问。即使两条指令完全没有寄存器依赖,也必须安排等待。分开指令与数据访问资源可以缓解这类争用,但会增加实现成本。

从资源、依赖和分支检查停顿原因
从资源、依赖和分支检查停顿原因

在真实机器上,这些原因可能叠加。网络处理程序遍历内存中的描述符,下一次加载地址依赖上次加载结果,同时还根据标志位选择分支。缓存未命中让值迟迟不返回,分支又可能反复改变方向。此时只说“有流水线气泡”还不够,需要继续说明是哪条依赖、哪类资源或哪次方向恢复让有效指令无法前进。

不要把不同冒险的处理方式互换。转发能解决某些值传递问题,却不能提前知道外部内存尚未返回的数据;增加内存带宽也不会自动消除错误分支。分析时先标出阻塞点,再选择证据与改进办法。为了让下一节的周期表可以复算,我们暂时排除缓存未命中、分支和端口争用,只保留加载后的数据依赖。

4 动手:画一个 5 级流水的冲突例子

取 4 条教学指令,依次编号为 I1 到 I4。I1 是 LD R1, 0(R2),I2 是 ADD R3, R1, R4,I3 是 SUB R5, R3, R6,I4 是 XOR R7, R8, R9。它们使用抽象指令记法,不要求对应某个真实指令集的汇编语法。我们要追踪的是 R1 与 R3 何时产生、何时被需要,而不是背诵助记符。

先写清规则:每周期每级最多容纳 1 条指令;按顺序推进;加载数据在 M 结束时可用;算术结果在 E 结束时可用;消费者在 E 开始时需要操作数;允许把结果转发到 E。寄存器写回发生在 W,取指和数据访问不争用端口。这些时点构成题目的条件,少写任何 1 项都可能让不同答案看似互相矛盾。

现在画横轴为周期、纵轴为指令的表。I1 从周期 1 的 F 推进到周期 5 的 W。若 I2 不等待,它会在周期 4 进入 E,但 R1 要到周期 4 的 M 结束才可用,已经错过 I2 当周期需要数值的时刻。即使有转发,也不能把周期末才产生的值送回同周期开始,因此这里必须停 1 个周期。

指令123456789
I1:LDFDEMW————
I2:ADD—FDD 停EMW——
I3:SUB——FF 停DEMW—
I4:XOR————FDEMW

周期 4 时,I2 留在 D,I3 的取指结果也保留在前端,E 接收 1 个无效槽位。这个无效槽位就是气泡,它随后经过 M 和 W,却不修改寄存器或内存。到周期 5,I1 的加载值可以转发给进入 E 的 I2;到周期 6,I2 的加法结果又可以转发给进入 E 的 I3,因此第 2 处依赖不再额外等待。

加载后使用产生的气泡与后续转发
加载后使用产生的气泡与后续转发

注意“停顿”和“气泡”的区别。停顿描述某条有效指令被留在原处;气泡描述下游出现没有有效工作的槽位。它们可能来自同一次控制动作,但不是把整台 CPU 在该周期都关闭。周期 4 中,I1 的 M 仍在正常工作;如果让 I1 也停住,加载值就无法按假设产生,周期表将失去自洽性。

这段代码完成共需 9 个周期,等于理想的 4+4 个周期再加 1 个停顿周期。练习时可以暂时去掉 I2 对 R1 的依赖,检查表能否缩短为 8 个周期。也可以把 I4 安排到 I1 与 I2 之间,观察独立工作是否填上了等待间隙。这样的调整必须保持程序含义,特别是不能随意跨越会影响地址或结果的操作。

周期表适合验证局部因果,却不直接代表复杂芯片测量结果。真实硬件可能同时处理更多指令,也可能遇到更长的数据等待。你应当把这张表用于回答“为什么这条依赖至少需要等待”,而不是宣称某台服务器运行这 4 条真实机器指令必定耗时 9 个周期。实验条件与推导结论要保持在同一层次。

5 转发与停顿的代价

转发是在结果正式写回寄存器之前,把已经产生的值直接送到需要它的位置。对相邻的算术依赖,生产者在周期末完成 E,消费者在下一周期开始 E,时间上恰好可以衔接。通路上的选择逻辑识别寄存器编号,决定使用寄存器读出的值还是较新的结果。它不是让指令忽略依赖,而是缩短满足依赖时绕行的路径。

如果完全没有转发,消费者就需要等生产者写回。具体等几个周期,还取决于寄存器文件能否在同周期先写后读。本课不指定另一套实现去背诵固定数字;在分析某个设计时,应当把读写时点补齐再画表。可以确定的是:去掉转发以后,原本连续执行的某些算术依赖也会产生额外等待。

加载后立即使用的例子说明了转发的边界。数据如果已经在 E 末产生,下一周期可用;如果必须等 M 末才产生,紧邻消费者就可能来不及。若访问还发生缓存未命中,等待甚至远超 1 个周期。把“带转发”理解成“数据依赖不会停顿”,会让性能估计对指针遍历和紧密依赖链过于乐观。

停顿的成本可以用每条指令平均花费的周期数 CPI 表达。在长指令流、单发射理想基线 CPI=1 的模型中,若平均每条指令额外承担 0.20 个加载使用停顿周期,CPI 就成为 1.20。这里的平均值不要求每条指令都等待 0.20 个周期,而是把整段执行中等待的总周期分摊到指令数上。

再加入分支:若分支占全部指令的比例为 b,分支预测错误率为 m,每次错误平均损失 p 个周期,则可用 CPI≈1+d×s+b×m×p 建立入门估算。d 是每条指令对应的加载使用停顿事件数,s 是每次此类事件的代价。本课取 s=1、p=2,并假定这 2 类损失不重叠,不包含缓存未命中及其他等待。

例如 d=0.20、b=0.20、m=0.10 时,CPI≈1.24,稳定阶段的 IPC≈0.81。这里 IPC 是平均每周期完成的有效指令数,在同一统计区间内与 CPI 互为倒数。若处理 1000000 条指令,频率固定为 2 GHz,估算需要 1240000 个周期,耗时约 0.62 ms;这还没有包括模型之外的系统与数据搬运成本。

转发也不是免费部件。更多数据通路、比较器和选择器会占用面积与能量,还可能影响时钟周期。入门阶段无需计算门级延迟,但应理解工程上是在硬件成本与停顿减少之间取舍。对程序开发者而言,更实际的问题是能否增加独立工作、改善数据局部性或减少难预测分支,而不是假设能从软件开关任意增加芯片内部转发线路。

6 常见坑:用理想 IPC 估真实性能

最常见的误用是拿“流水线填满后每周期完成 1 条”直接乘主频,再把结果当成应用速度。理想 IPC 是附带条件的上限,不包含依赖、分支、缓存等待和前端供应不足。在实际测量里,IPC 还与指令集、编译结果和工作负载有关。不同程序完成相同任务可能执行不同数量的指令,所以 IPC 更高也未必先完成任务。

估算 CPU 时间时,可先用 时间≈指令数×CPI÷频率。若优化后指令数从 1000000 增至 1200000,而 CPI 从 1.5 降至 1.3,在固定频率下,总周期反而从 1500000 增至 1560000。只报告 CPI 下降会隐藏这个变化。因此业务侧还要记录处理了多少条记录、多少字节或多少个数据块,才能比较完成同一份工作的成本。

从任务时间向指令、等待与外设证据逐层观察
从任务时间向指令、等待与外设证据逐层观察

另一个坑是把 3 GHz 理解成 3 倍于 1 GHz 的任务速度。主频影响周期长度,但芯片结构、内存等待、频率调节和指令组合也会变化。即使比较同一块 CPU,持续满载后的温度与功耗限制也可能改变实际频率。应记录运行期间的频率与散热条件,而不是只抄包装或固件页面上的最高频率。

机器形态会影响这些条件。一台薄型笔记本和一台有持续风道的机架服务器,短时测试可能接近,长时负载却可能出现不同的降频行为。内存容量相同也不表示通道数量和访问行为相同。要讨论流水线等待,需要先把这些外部变量约束住,否则运行时间的变化可能主要来自散热、内存配置或其他任务争用。

“存储很快,所以 M 应当不等”同样混淆层次。PCIe 4.0 x4 表示存储设备连接的链路代际和通道宽度,并不表示每次 CPU 加载都由该设备在 1 个周期内完成。10 GbE 的线速也不等于应用每秒能解析多少报文。小报文通常带来更多逐包工作,大数据块传输则可能更接近带宽约束,必须按负载判断。

若系统允许使用硬件性能计数器,可以观察执行周期、完成或退休指令数、分支数、分支预测失败数,以及相关缓存事件。不同芯片和工具对事件的定义可能不同,应查事件说明,再判断分母和统计范围。不能把所有名称带有 stall 的事件直接相加,因为它们可能互相重叠,也可能统计的是槽位而非完整周期。

实际报告可以保留几项容易核对的信息:固定输入下的耗时、每秒处理量、核心使用情况、有效频率和关键计数器比例。先确认 CPU 是否真是瓶颈,再解释是哪类等待。计数器是帮助检验假设的证据,不会自动给出完整因果;如果变化同时影响指令数、缓存和分支,仍需要进一步拆分实验。

7 案例:分支密集代码的流水线气泡

考虑一台使用 10 GbE 网卡的服务器,CPU 对已经进入内存的报文描述符进行校验。程序依次检查长度、类型和标志位,遇到不合规记录就跳到错误路径。这里讨论的是内存中的解析循环,测试时先把接收过程与循环本身分开计时,以免网络流量波动掩盖 CPU 行为;随后再回到完整链路验证收益。

若一批记录几乎都合法,某些分支长期朝相同方向,预测机制通常更容易形成有效规律。若合法与非法记录以缺少规律的顺序混合,相同代码的方向就可能更难预测。不过“分支很多”不等于“预测失败很多”,交替方向也不必然无法预测。预测结果取决于具体序列与处理器机制,本课不把某种输入模式当成通用失败证明。

动画使用明确的教学时序:分支 B 在周期 1 取指,在周期 3 的 E 结束得到真实方向。前端先沿错误方向取入 X1 和 X2,此时 X1 在 D,X2 在 F。发现方向错误后,这 2 条较新的指令失效,正确目标 T1 到周期 4 才开始 F。在这个无其他等待的模型中,错误方向造成 2 个有效发射机会损失。

错误路径指令失效后不能再改写程序可见的寄存器与内存。否则这不只是变慢,而会破坏正确性。动画只展示错误路径指令尚未进入 E 的简单情况;真实处理器可能已经让更多工作进入内部,需要更复杂的恢复机制。这里先抓住“保留正确路径的含义,丢弃错误路径的有效性”,高级内部状态管理留待后续。

分支判断、错误路径失效与目标重新取指
分支判断、错误路径失效与目标重新取指

为了检验气泡解释,准备 2 组记录,保持记录总数、大小和合法比例相同,只改变顺序。每组重复运行,交替测试顺序,并报告耗时分布。这样能减少把不同错误处理工作量误判为分支影响的机会,但记录顺序仍可能影响缓存,所以还应观察缓存相关事件。若无法固定数据访问,就必须保留其他解释。

假设测得某版本每条有效处理指令对应的分支比例约为 0.25,分支错误率从 0.02 升到 0.20。在 p=2 的教学估算中,分支项从 0.01 升到 0.10,增加约 0.09 CPI。这个结果只能说明简化模型中的方向与数量级;真实硬件的恢复代价需要测量或资料支持,不能看到实际变慢 30% 就硬套这 2 个周期。

优化可以从合并重复判断、提前处理高频情况和按类别批量处理入手,但必须检查语义与输入代表性。把判断改成额外计算有时会增加指令和访存,未必更快。若本地循环加速后整机吞吐没变,应继续看网口、内存搬运或其他线程是否成为限制。局部流水线改善需要在完整机器上兑现,才有部署意义。

8 把流水线效应写进性能假设

性能假设应写成可以被证据推翻的句子。例如:“在固定核心与频率条件下,这段描述符解析循环主要受难预测分支影响;改变记录顺序后,单位记录的分支错误数与周期数应同向变化,而执行指令数和缓存行为应大致稳定。”这比“CPU 流水线不够快”具体,因为它指出了输入变化、观察量和预期关系。

先记录机器与负载边界:CPU 型号及启用核心数、内存容量及通道配置、网卡速率和连接方式、存储接口、操作系统与编译选项、记录大小与数量。这些信息用于复现环境,不代表必须把所有外设都纳入流水线公式。若测试数据已经在内存,存储设备主要影响准备阶段;若边读边处理,则要单独量化读取等待。

然后把教学公式改写为明确的预算项:有效指令工作量、依赖等待、分支恢复,以及未纳入模型的其他成本。不要为了让预测贴合测量,就把所有差额统称为“流水线损失”。差额可能来自缓存未命中、线程迁移、系统调用、设备等待或频率变化。每增加 1 项解释,都应说明相应证据如何获得。

从现象到可证伪假设的排查路径
从现象到可证伪假设的排查路径

安排实验时尽量只改变 1 个关键因素。测试分支方向影响时保持记录内容与工作量接近;测试依赖链时保持循环输出一致;比较编译版本时保留优化选项与生成代码的信息。固定线程到某个核心有助于减少迁移影响,但仍要确认是否有其他任务共享执行资源。不能仅凭“绑核了”就认为环境完全稳定。

报告结果时同时展示单位工作量和系统结果。例如用每条记录的周期数描述 CPU 成本,再用每秒记录数描述吞吐,并单独给出完整网卡接收路径的端到端耗时。若局部周期下降而端到端耗时没有明显改变,结论应是该局部路径得到改善、当前系统收益受其他部分限制,而不是修改测试口径寻找更漂亮的数字。

还应给出模型失效的条件。若记录规模超过缓存容纳范围,主导因素可能从分支恢复变成数据等待;若启用更多核心,内存带宽或网卡队列可能开始限制扩展;若输入合法比例改变,实际执行的路径也会改变。性能假设不是永久属性,需要与数据规模、输入分布和机器配置一起保存。

真实硬件故障也要与流水线冒险区别开。内存纠错告警、PCIe 链路重训、网卡丢包和温度过高引发的降频,都可能表现为吞吐下降,却不是本课周期表里的普通气泡。遇到错误计数增长或链路不稳定,应先检查对应硬件与系统日志。保持这个边界,能避免把需要维修或配置修正的问题当成代码优化课题。

9 从流水线走向超标量(H20)

到目前为止,每周期最多进入 1 条指令,资源足够、没有冒险时也只追求每周期完成 1 条。自然会出现新的问题:如果同一时刻有多条互不依赖的指令,能否让它们并排进入执行资源?这就是走向超标量的起点。超标量增加每周期可处理的指令宽度,流水线则让不同阶段重叠;它们描述的是不同方向的并行。

例如 2 条独立加法可能分别使用不同执行单元。但把入口扩宽到 2 条,不代表所有代码的 IPC 都能达到 2。取指和译码要及时供给,操作数要准备好,执行单元要匹配,结果还要正确提交。任何环节的供应不足都可能让槽位空着,所以本课学习的依赖、资源和控制问题仍然存在,甚至更需要被明确描述。

可以先比较 2 类代码。连续独立地计算多个数组元素,可能提供较多可以重叠的工作;沿链表逐个读取节点时,后续地址必须等当前节点返回,依赖链限制了提前推进的范围。它们可以运行在相同 CPU、相同频率下,却呈现不同吞吐。芯片拥有更多执行资源,并不会让尚未得到的地址自动出现。

宽度增加还会让控制失误浪费更多潜在工作。若每周期能推进更多指令,错误路径上可能积累更多需要作废的操作。不过不能简单用“宽度乘本课 2 个周期”预测真实损失,因为实际分支判断位置、前端重定向和资源状态也会变化。正确的迁移方式是保留因果关系,重新查明新模型的时点与容量。

流水线重叠、超标量宽度与依赖约束
流水线重叠、超标量宽度与依赖约束

乱序执行则进一步面对“较早的指令在等待,较晚但独立的指令能否先做”的问题。为了既提高利用率又保持程序规定的结果,它需要额外机制。本课不展开寄存器重命名、调度窗口与提交结构,只先建立边界:顺序是教学模型的条件,并不意味着所有现代 CPU 都会让后续独立工作陪着等待。

这也解释了为什么真实测量与 5 级表格可能不同。表格准确表达了给定规则下的行为;实物芯片采用其他规则时,需要另外的模型。遇到差异时,先检查加载结果可用位置、允许的并行程度和分支恢复行为,而不是把表中所有空格直接换算成某颗芯片的固定惩罚。

进入 H20 前,可以先口头回答几个问题:为什么增加流水线阶段不保证降低单条指令延迟?为什么相邻算术依赖可能不用停,而加载后使用仍可能停?为什么 IPC 提高后任务时间仍可能增加?如果能分别从阶段时间、值可用时点和总指令工作量解释,就已经具备继续讨论超标量与乱序执行所需的基础。

放进方案里

在服务器性能方案中,给 CPU 流水线效应留出明确的位置。先写机器边界,例如使用 8 核 CPU、32 GiB 内存、PCIe 4.0 x4 NVMe 存储和 10 GbE 网卡,并注明内存通道、持续运行频率与散热条件。随后把数据准备、内存中的计算循环和网络收发分别计时,使读者能判断方案关注的是 CPU 执行成本还是设备供给能力。

为计算循环记录固定工作量,例如处理 1000000 条描述符,同时保存记录大小、合法比例和排列方式。先用“指令数乘 CPI 再除以频率”建立估算,并注明理想基线、加载使用停顿项和分支恢复项的适用条件。5 级教学模型中的 1 个加载停顿周期、2 个分支恢复周期,只能作为说明机制的假设;用于采购容量或上线承诺前,应替换为目标机器上的测量依据。

验证计划至少比较原始版本与候选版本,在相同输入和环境下重复运行,报告单位记录周期数、有效指令数、分支错误率以及完整路径吞吐。若候选版本减少分支却增加了执行指令或内存访问,应把这些变化一起列出。若计数器不可用,仍可保留固定输入的耗时对照,但应降低对具体内部原因的判断强度。

验收条件要落到系统目标,例如持续负载下达到约定的每秒处理量,同时尾部延迟与错误率满足要求。局部循环加速而网口吞吐不变时,继续检查其他限制,不据此承诺同等整机收益。记录缓存容量变化、输入分布变化和多核扩展时需要重新评估;出现内存纠错、链路重训或热降频证据时,转入对应的硬件与运行环境排查。

最后保留回退条件和可复现材料:原始实现、编译选项、输入生成规则、测量范围与结果分布。把“我们怀疑存在什么等待”“什么证据支持它”“优化在什么范围有效”连成完整说明,方案才便于复核,也能为 H20 中评估更宽的执行资源提供稳定基线。

10 小结:下一步超标量与乱序执行(H20)

流水线通过阶段重叠提高连续指令的吞吐,阶段数本身不等于性能倍数。数据、控制与结构冒险限制推进;转发能及时传递已有结果,停顿则为尚未满足的条件留出时间。加载后使用和错误分支的周期图,提供了从值可用时点推导气泡的方法。

读懂模型以后,还要把指令数、CPI、频率和完整任务时间联系起来。真实机器上的缓存、内存、外设和运行条件决定模型的适用范围。下一课 H20 将把每周期可推进的宽度扩展开,进一步讨论独立指令如何利用更多执行资源,以及乱序执行为什么仍须保持程序结果正确。

同阶段相关课

AI 答疑

默认关闭。启用后,只发送本课标题、最近阅读的屏幕内正文摘录(最多 6000 字)与本次问题。

配置自己的服务