X86 CPU内部处理器架构细节—Nehalem

X86 CPU内部处理器架构细节—Nehalem

根据Nehalem架构了解CPU内部细节

Nehalem内核设计背景

Core架构具有一个移动计算的起源,它源自Banias Pentium M处理器,Pentium M处理器是以色列(Israel)的海法(Haifa)研究中心专门针对笔记本电脑的产品,特点是高效、低耗。Core架构之后迅速地成为Intel的主要架构,产品开始扩展到桌面乃至服务器产品线。Core架构古老的双核设计(4核是两个双核粘在一起,6核则是三个双核粘结)、过时的FSB总线以及没有充分为64位计算准备等等,让其无法获得很好的伸缩性,难以未来需要高性能多处理器需求的企业级市场。

Intel对Core架构作出了改动,首先它将原来的架构扩展为原生4核(甚至6核、8核)设计,并为多核的需要准备了新的总线QPI来满足巨大的带宽需求,结果就是Nehalem内核。

 

4核心Nehalem处理器架构

核心:功能区间划分

Nehalem是一款OOOE(Out of Order Execute)乱序执行的Superscaler超标量x86处理器。超标量的意思就是多个执行单元,可以同时执行多条没有相互依赖性的指令,从而达到提升ILP(Instruction Level Parallelism)指令级并行化的目的。乱序执行是指在多个执行单元的超标量设计当中,一系列的执行单元可以同时运行一些没有数据关联性的若干指令,只有需要等待其他指令运算结果的数据会按照顺序执行,从而总体提升了运行效率。

High-level diagram of a Nehalem core pipeline.

Core由以下部分组成:
in-order前端:拾取Intel64指令,使用四个解码器将指令解码为micro-ops,放入下游阶段的缓存中。
out-of-order执行引擎:输入数据和资源具备,每个时钟周期动态分配六个micro-ops到执行单元
in-order回退单元:确保micro-ops 的执行结果和结构状态(architected state )的更新符合源程序的顺序
以及多级缓存体系和地址转换资源

前端:指令拾取和解码

处理器在执行指令之前,必须先装载指令。指令会先保存在L1缓存的I-cache(Instruction-cache,L1D和L1I都是通过256bit的带宽连接到L2 Cache)指令缓存中,Nehalem的指令拾取单元通过访问 ITLB里的索引来从I-cache中读取指令。读取的指令做相应的 predecode 和 branch predication。结果送到指令队列 buffer(Instruction Queue)。再从 Instruction Queue fetch和decode,经过指令融和操作后,送调度单元分派指令。

The Core Front-End: Instruction Fetch

指令拾取单元(IFU,Instruction Fetch Unit) 由ITLB ( Instruction Translation Lookaside Buffer)、instruction pre-fetcher、L1 i-cache(L1 instruction cache)和指令预解码器(instruction pre-decoder)组成。IFU每个时钟周期从L1 i-cache拾取16字节的指令到 Instruction Length Decoder。IFU使用ITLB来定位L1 i-cache和指令预取缓存中的16字节块。当命中缓存时,16字节的指令将会传输给instruction pre-decoder。

**分支预测单元(BPU,Branch-Prediction Unit)**在分支指令(如if then这样的语句)结果确定之前预取和处理后续指令,使得处理器执行预测路径上的指令时不“stalling”。

**指令预解码器(ILD or “Pre-Decoder”,Instruction Length Decoder)**接收Intel64 instructions ,确定指令长度、解码指令前缀、为解码器标注指令类型(如branch指令)。

**指令队列(Instruction Queue)**缓存预解码后的指令,并每个时钟周期传递5条指令给指令解码器(Instruction Decoder)。

在将指令充填到指令队列之后,就可以进行解码工作了,解码是类RISC(精简指令集或简单指令集)处理器导致的一项设计。处理器接受的是x86指令(CISC指令,复杂指令集),而在执行引擎内部执行的却不是x86指令,而是一条一条的类RISC指令,Intel称之为Micro Operation——micro-op,或者写为µ-op,一般用比较方便的写法来替代掉希腊字母:u-op或者uop。相对地,一条一条的x86指令就称之为Macro Operation,或macro-op。
RISC架构的特点就是指令长度相等,执行时间恒定(通常为一个时钟周期),因此处理器设计起来就很简单,可以通过深长的流水线达到很高的频率。和RISC相反,CISC指令的长度不固定,执行时间也不固定,因此Intel的RISC/CISC混合处理器架构就要通过解码器将x86指令翻译为uop,从而获得RISC架构的长处,提升内部执行效率。Nehalem有3个简单解码器加1个复杂解码器。简单解码器可以将一条x86指令翻译为一条uop,而复杂解码器则将一些特别的(单条)x86指令翻译为1~4条uops。在极少数的情况下,某些指令需要通过额外的可编程microcode解码器(MS ROM for Complex Decoder)解码为更多的uops。

指令解码单元(IDU, Instruction Decode Unit)解码预处理后的Intel64指令(macro-ops)为uop,并将uop放入下游的 instruction decoder queue (IDQ)。

对于一组uop,IDU会有一些优化措施,如:
循环流监测器(Loop Stream Detection):假如程序使用的循环段(如for..do/do..while等)少于28个uops,那么Nehalem就可以将这个循环保存起来,不再需要重新通过取指单元、分支预测操作,以及解码器,Core 2的LSD放在解码器前方,因此无法省下解码的工作。
Micro-Fusion: 将多条uops聚合用于降低uop的数量,提高Front-End的吞吐量和reorder buffer(ROB)的使用效率

执行引擎:乱序执行

执行引擎从上游的IDQ中选择micro-ops,动态调度分配给下游的执行单元执行。执行引擎是“out-of-order”的动态调度,超标量流水线允许micro-ops在代码语义不冲突的情况下并行的使用可用的执行单元。

High-level diagram of a the out-of-order execution engine in the Nehalem core

执行引擎包含以下主要组件:
**Register Rename and Allocation Unit (RRAU)**:分配执行引擎的资源给IDQ中的micro-ops,并移动micro-ops给执行引擎。
**Reorder Buffer (ROB)**:追踪所有执行中的micro-ops。(没有结果的指令将在ROB等待)
Unified Reservation Station (URS):排队最大36条micro-ops直到操作资源ready,调度和分配ready的micro-ops到可用的执行单元。(没有数据的指令将在RS等待)
**Memory Order Buffer (MOB)**:支持推测、乱序load/store,确保正确的次序和数据写回内存
Execution Units and Operand Forwarding Network:每个时钟周期最多为一个micro-ops产生一个结果

在乱序执行架构中,不同的指令可能都会需要用到相同的通用寄存器(GPR,General Purpose Registers),为此Intel开始引入重命名寄存器(Rename Register),不同的指令可以通过具有名字相同但实际不同的寄存器来解决。

乱序执行从Allocator定位器开始,Allocator管理着RAT(Register Alias Table,寄存器别名表)、ROB(Re-Order Buffer,重排序缓冲区)和RRF(Retirement Register File,退回寄存器文件)。RAT将重命名的、虚拟的寄存器指向ROB或者RRF。RAT指向在ROB里面的最近的执行寄存器状态,或者指向RRF保存的最终的提交状态。当一条指令通过RAT发往下一个阶段确实执行的时候这条指令(包括寄存器状态在内)将被加入ROB队列的一端,在“乱序”之前,ROB的指令就已经确定了,指令并不是在ROB当中乱序挑选的(这在RS当中进行)。从执行单元返回的数据会将先前由调度器加入ROB的指令刷新数据部分并标志为结束(Finished),再经过其他检查通过后才能标志为完毕(Complete)。执行完毕的指令(包括寄存器状态)将从ROB队列的另一端移除(期间这些指令的数据可以被一些中间计算结果刷新),并提交寄存器状态。ROB担当的是流水线的最终阶段:一个指令的Retire回退单元;以及担当中间计算结果的缓冲区。提交状态的工作由Retirement Unit(回退单元)完成,它将确实完毕的指令包含的数据写入RRF(“确实”的意思是,非猜测执性、具备正确因果关系,程序可以见到的最终的寄存器状态)。RFF的数据最终先写入MOB(Memory Order Buffer,内存重排序缓冲区),再由MOB来完成写入L1D缓存。

猜测执行允许预先执行方向未定的分支指令。分支猜对了,其在ROB里产生的结果被标志为已结束,可以立即地被后继指令使用而不需要进行L1 Data Cache的Load操作。分支未能按照如期的情况进行,这时猜测的分支指令段将被清除,相应指令们的流水线阶段清空,对应的寄存器状态也就全都无效了。所以当指令和micro-ops在正确预测路径上才会发生状态的“Retirement”和“writeback”。Retirement处理满足以下两个条件:

1.与回退micro-op相关的所有micro-ops已经完毕”complete”,允许整条指令的Retirement。当一个指令的micro-ops的数量超大,填满回退窗口时,micro-ops可以回退。
2.正确预测路径上之前的指令的micro-ops已经发生回退。

这些保证处理器更新的状态与in-order执行的代码的micro-ops一致。

当之前的指令发生阻塞等待时,不会阻塞无依赖的新指令和micro-op执行。新指令的micro-ops将分配到执行单元,并且在ROB中等待执行完成。

Inter Core i7架构

目前Inter Core i7使用Nehalem微架构来实现CPU内部结构,而ARM微架构依然沿用Cortex。

Nehalem是一款OOO(Out of Order)乱序执行的Superscaler(超标量)的X86处理器。

超标量意味着CPU中有多个执行单元,可以在同一时刻执行多条无相关依赖性的指令,从而达到提升ILP(Instruction Level Parallelism)指令并行化的目的。

乱序执行则是指在多个执行单元的超标量设计中,一系列的执行单元可以同时运行一些没有数据以及逻辑关联的若干指令,只有需要等待其他指令运算结果的数据会依照顺序执行,从而提升执行效率。

 

Intel Nehalem arch

 

Inter Core i5

CPU PipeLine执行流程

取指与解码(Front-End In-Order)
  • Instruction Fetch:将主存中的指令集合(4K左右)加载到L1的Instruction Cache中
  • Prefetch Buffer:从L1的指令缓存装载16Byte长度的指令到Buffer
  • Predecode&Instruction Length Decoder:将上过程中Buffer的指令进行指令长度解析(确定指令长度,解码指令前缀,为解码器标注指令类型等)以及进行分支预测的处理(确定分支指令的的跳转,使用BTB保存分支预测指令的地址)避免处理器在执行预测路径上的时候不会'"stalling"

由于X86是CISC指令集的处理器,CISC的指令是变长指令集,所以在解码之前,需要将指令进行解析,确定指令的前缀、长度等等,而RISC指令集则不需要进行该处理,因为RISC是等长指令集。

  • Instruction Queue:将Predecode处理过后的指令进行指令对齐以及宏指令的融合(将可融合的指令送到解码器,生成新的指令,如比较判的分支X86指令集最终解码成单条micro Op,从而提升解码器的带宽,降低指令数量,提高运行效率)
  • Complex&Simple Decorder:将Instruction Queue中的指令进行解析,Complex Decoder负责解码复杂指令,将单条复杂的x86指令翻译成1-4条Micro Ops,Simple Decoder负责解码简单指令,将单条简单的x86指令翻译成1条类RISC指令的Micro Op

X86的CPU属于CISC指令集,由于CISC的指令长度不固定,而且执行时间也不固定,所以Nehalem架构会将CISC指令通过Predecode以及Decode处理成类RISC指令(也就是Decode完的MicroOp),因为RISC指令长度等长,执行时间恒定,通常一个cycle就能执行完,因此后续处理器设计就会比较简单,并且流水线的长度可以达到很长,使得CPU可以到达很高的频率。

  • Decoded Instruction Queue:接收到了解码后的Micro Ops后,会经过Loop Stream Decoder以及Micro Instruction Sequencer

Loop Stream Decoder会对循环段(如for,while,do...while)少于28个ops的情况下,会保存起来,而不需要再重新取指,进行分支预测以及解码等操作,并且Instruction Sequencer会将指令进行序列化

  • MicroOp Fusion:将多条Micro Ops进行融合,用于降低Micro Ops的数量,提高指令执行的吞吐量,以及Reorder Buffer的使用效率
执行引擎(Out-Of-Order Executor)

OOOE是为了直接提升ILP(Instruction Level Parallelism)指令集并行化的设计,在多个执行单元的超标量设计中,一系列执行单元可以同时执行一些没有数据关联性的若干指令,只有需要等待其他指令运算结果的数据会按照顺序执行。

  • 2 x Register Allocation Table:不同的指令可能都会需要用到相同的通用寄存器(GPR,General Purpose Registers),为了在这种情冲突的况下指令们也能并行工作,处理器需要准备解决方法。一般的RISC架构准备了大量的GPR,而x86架构天生就缺乏GPR(x86具有8个GPR,x86-64具有16个,一般RISC具有32个,IA64则具有128个),为此Intel开始引入重命名寄存器(Rename Register),不同的指令可以通过具有名字相同但实际不同的寄存器来解决(为了SMT同步多线程,这些寄存器还要准备双份,每个线程具有独立的一份)

寄存器重命名避免了机器指令或者微操作不必要的顺序化执行,从而提高了处理器的指令级并行的能力。

  • ReOrder Buffer:只能存放128条指令,将寄存器重命名后的指令按照编程的原始顺序重新排序成一个队列,把打乱了次序的指令们依次插入队列中。
  • Reservation Station:指令保留站,等待源数据到来,以进行OOOE乱序执行,而没有数据的指令,则在Reservation Station中等待,直到等待到了数据后,通过各个端口发送到ALU中进行运算和执行,最终将运算数据通过MOB存入L1的数据缓存中,并且将结果通过Result Bus分发到ROB中,如果运算已经完成,则会更新ROB中的指令结果,并且从ROB中移除已经完成的指令,将该指令放到RRF中。除了存放指令之外,保留站的作用是监听内部结果总线上是否有保留站内指令所需要的参数。需要读取L1/L2缓存乃至内存的指令或者需要等待其他指令结果的指令必须在此等待
  • Retirement Register File:从ROB中移出一条指令就意味着指令执行完毕了,这个阶段叫做Retire回退,相应地ROB往往也叫做Retirement Unit(回退单元),并将其画为流水线的最后一部分。该部件存储了被提交的体系寄存器的状态,通过逻辑寄存器的号来查询这个寄存器堆,用于进行寄存器是否可用的标识,为寄存器重命名查询寄存器状态以便提供空闲寄存器。

重要部件

CPU中分为以下重要的部件:

  • PipeLine
  • 超标量&超线程
  • Hardware Prefetch:根据历史操作预先加载以后会用到的指令来提高性能
  • 分支预测(Branch Prediction)
  • Macro Ops && Micro Ops指令融合(MicroOp Fusion)
  • LSD
  • Register Allocation Table
  • ROB
  • RRF
  • MOB
  • Cache:L1,L2,L3缓存
  • L1:分为指令缓存(Instruction Cache,32K)以及数据缓存(Data Cache,32K):(N路集合关联)
  • L2:每个核超线程共享一个256K缓存(N路组相连(N Way Set-Associative))等
  • L3:所有核共用同一个8M的缓存
  • 多核CPU的总线:QPI

 

参考文献链接

https://upload.wikimedia.org/wikipedia/commons/6/64/Intel_Nehalem_arch.svg

https://www.cyningsun.com/06-01-2016/nehalem-arch.html

https://zhuanlan.zhihu.com/p/671129546

posted @   吴建明wujianming  阅读(320)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2023-01-14 一些汇编指令寄存器杂谈
2022-01-14 HBM显存技术与市场前景
点击右上角即可分享
微信分享提示