Pentium II & Pentium III的流水线 (2)

Pentium II & III Instruction Pipeline Details

Front-End Pipeline Details

Pentium II & III处理器的指令流水线前端包括3个主要的部件:指令预取单元,译码器,和分支预测单元。

Instruction Prefetcher

指令预取单元总是积极地从指令缓存中预取指令流。Pentium II & III处理器总是从16字节对齐的地址边界上读取指令流。例如,如果有一个分支目标地址模上16之后等于14,则在第一个预取周期中,只能有2个字节的有用指令能被获取到(前14个无关指令字节会被废弃),随后的指令必须在接下来的预取周期中读取,这样有可能造成流水线饥饿状态,即缺少或无指令可以执行。

注意:指令预取总是期望读取对齐的16字节指令流。

Decoders

Pentium II & III处理器有3个译码器。在每个时钟周期,第一个复杂译码器可以将1条x86指令翻译成1至4条微指令。它可以处理最长达15字节的x86指令,但是9个字节或更长的指令需要额外的时钟周期。另外两个简单译码器可以各译码1条x86指令,将其各翻译成1条微指令,可以处理最长达8个字节的x86指令。对于译码后多于4条微指令的x86指令,需要多个时钟周期来译码。

简单的x86指令对应1至4条微指令;复杂的x86指令,例如CMPXCG指令,通常对应超过4条微指令,需要多个时钟周期来译码。

综上所述,在每个时钟周期内,最多可以译码3条x86指令。但是,如果是复杂x86指令或者指令长度超过7字节(TODO:校验7字节这个值),译码器只能译码更少的指令。

  • 每个时钟周期最多译码3条x86指令
  • 每个时钟周期产生最多6条微指令(复杂译码器4条+2个简单译码器各1条)

所以,当使用汇编语言进行程序设计时,尝试将x86指令调度(即指令设计顺序)成4-1-1微指令顺序,也就是生成4条微指令的x86指令后紧跟着两条只生成1条微指令的x86指令。这样这3条x86指令可以在一个时钟周期内译码完毕,达到最佳的译码吞吐量。

下面给出一个x86指令对应的微指令条数的参考,更详细的信息可以参考Intel文档,order#: 245127-01。

  • 寄存器到寄存器这种形式的简单指令对应1条微指令
  • 加载指令对应1条微指令
  • 存储指令对应2条微指令
  • 简单的读取-修改指令对应2条微指令
  • 寄存器到存储器这种形式的简单指令对应2至3条微指令
  • 简单的读取-修改-写回指令对应4条微指令

 

Branch Predication Overview

Pentium II & III处理器使用分支目标缓存区预测分支指令的方向和目标(基于分支指令的地址)。分支指令的地址在译码前就可获得,所以基于分支目标缓存区的预测机制可以尽可能早的进行分支预测,而从避免指令执行流进入错误的方向而产生停顿。拥有512个条目的分支目标缓存区存储着先前看见过的分支指令以及它们各自的目标地址。当1条分支指令被预取到时,分支目标缓存区为指令预取单元提供该指令的目标地址。一旦该分支被真正执行,实际跳转目标地址会被更新到分支目标缓存区中。因此,使用分支目标缓存区可以动态的预测以前见过的分支指令。

一旦分支指令被译码,分支的方向(前向或后向)也即获得。如果在分支目标缓存区中找不到某个分支指令,则静态分支预测器会根据分支指令的方向进行预测。

Dynamic Prediction

分支目标缓存区的预测算法包括模式匹配以及跟踪每条分支指令过去最近的4个分支方向。例如,4次或少于4次迭代的循环指令理论上可以被100%正确地预测。

此外,Pentium II & III处理器有一个返回栈缓存区,这个缓存区可以用于预测一系列过程调用的返回地址。对于含有过程调用的循环展开优化方法,这个缓存区增加了性能收益。它也缓和了对内联函数的使用需求,因为过程调用的返回时间成本降低了。

按性能损失的时钟周期数量化计算,Pentium II & III处理器对分支指令提供了3级的支持:

  1. 未采纳分支没有性能损失。本级适用于a) 被分支目标缓存区正确预测为未采纳的分支,b) 不存在于分支目标缓存区中的前向分支(默认被预测为未采纳)
  2. 被分支目标缓存区正确地预测为采纳的分支会有一个1时钟周期的微性能损失。与任何采纳分支一样,对紧跟着分支语句之后的指令进行的译码都将被废弃。
  3. 预测失败的分支会遭受严重的性能损失,读取指令至少是9个时钟周期(即流水线的有序前端的长度),加上额外的周期等待预测错误的分支指令终了。这个损失要看当时的执行环境。典型地,预测失败是10至15周期的损失,最长可达26周期。

 

Static Prediction

不存在于分支目标缓存区中的分支指令,但是被静态预测机制正确地预测的分支,会产生大于5至6个时钟周期的小性能损失(流水线起始到静态预测点的长度)。这适用于以前没有见过的无条件直接分支语句。

静态预测算法会将回跳条件分支指令(即分支指令具有负位移量),例如循环语句比较循环条件,预测为采纳。当第一次遇见这种分支指令时,会产生大约6个周期的小性能损失;随后的每次迭代,分支目标缓存区可以正确的预测回跳分支指令,只会有1个周期的微性能损失。前向跳转分支指令会被预测为未采纳。

不在分支目标缓存区中,但是被译码器正确预测的分支指令会有大约5个周期的小性能损失。

要充分利用前向分支不采纳以及回跳分支采纳的静态预测机制,代码应该被安排成最可能执行的代码紧跟着前向分支语句,即

if (condition)

{ likely_executable_code; } // forward branch predicted not

                            // taken by static predictor

else

{ unlikely_executable_code; }

猜你喜欢

转载自blog.csdn.net/qq_43401808/article/details/85316553
今日推荐