导言
补充了后端内容,修改了相关表述,本文大概 9000 字。
简介
2024
年AMD
发布了变化巨大的一代微架构Zen5
,并宣称Zen5
微架构是未来几代微架构的基石。相比较Zen4
,Zen5
的IPC
增加了16%
,这个增长非常可观,同时还能实现高达5.7GHz
的频率,支持AVX512
变体以及FP-512
,Dispatch
宽度为8
,6 ALU
,取指和解码(Fetch/Decode)
均采用双流水线,本代预计采用TSMC 4/3nm
工艺,每个核具有2
个线程。值得注意的是,本代的Zen5
在投入更多逻辑以提升性能,却可以通过工艺的优化实现面积的平衡,于前代Zen4
相比面积基本一致。
每8
个Zen5
核组成一个Die
,服务器芯片EYPC9005
最多可以配置这样的16
个Die
,也就是128
个核,每个Die
共享32MB
的 L3缓存。相比于前代提供了更好的性能。而Zen5c
每个处理器则可以最多12
个Die
,每个Die
有16
个Zen5c
,同样是每个Die
共享32MB
的L3
缓存,可以配置的核数为96~192
。
取指单元(IFU)
Zen5
的IFU
相比较前代变化非常大,比较有特色的是采用双流水线,并且重新设计了预测器,对预测单元投入很大,前端的巨大改变是性能提升的关键因素。
预测器
考虑到后端增加了执行带宽,前端需要给出更多的指令来支持后端的需求,而预测器则是前端核心部件之一,所以本代AMD
就对预测器投入巨大,非常多的组件资源投入都在加倍。AMD 很多设计都是粗暴的增加组件的参数,本代了解到的是MMU
核预测器投入了巨量资源,基本践行“大力出奇迹”的设计理念。
Zen5
的分支预测错误惩罚是12-18cycle
,这里的预测惩罚相比较ARM
以及RISC-V
架构的一些旗舰核是非常大的劣势,一般情况下先进的核预测惩罚压缩到11cycle
,甚至有些核压缩到10cycle
以下,现代处理器的预测器预测精度目前提升缓慢,所以更多的架构师尤其是精简指令的架构师越来越倾向于压缩预测惩罚时间。但X86
毕竟是复杂指令集,并且需要实现非常高的频率(5GHz+
),流水线深度很难做到和RISC
一样的水准,并且它们的定位也不尽相同,各有自己的优劣。
预测地址的基本单位是Block
,每个Block
是64B
,如果按照4B
一个指令,那预测的带宽就是每周期16
指令,这对X86
架构的一些特性看(12
一个跳转分支,6
指令一个分支)属于相对比较合适的一个值,算是比较保守吧,如果后续能处理取指带宽的问题,估计会增大Blcok
的值(实际的取指带宽受限于Cache Line
位置和跳转分支位置),即使无法增大取指带宽,适当增加Block
也可以获得一些潜在的收益,具体大家可以查阅一些论文。
L1 BTB
是16K entry
大小,这是巨大的升级,相比前代Zen4
的1.5K entry
,升级到10
倍,有条件/无条件直接/相同目标的间接都是0
预测气泡,对于Return
和多目标的间接都是2cycle
预测气泡,考虑到其它主流厂商旗舰的 0 预测气泡预测L1 BTB
基本都在1K entry
左右,AMD
的设计可以说非常激进。L2 BTB
是8K entry
,如果L1 BTB MISS
则会有8
个预测气泡,这里非常奇怪,居然有如此巨大的气泡,因为L1 BTB
巨大,所以考虑功耗的角度也不会同时访问L1 BTB
和L2 BTB
,再者不同类型的指令可能也是顺序的访问,但8
个预测气泡还是远超过我的想象。比较RISC
的一些设计,大概在10-11
周期已经做分支执行了,即使在CISC
的角度,这个气泡还是感觉巨大,可能需要更多信息去评价这个问题。
间接目标预测器有3072 entry
,间接指令一般会有多个目标,预测会根据间接指令的历史从中选择一个目标。对于经常是一个目标的间接指令,一般用普通的 BTB 来预测结果,延迟也很低,这个特性如果普遍,微架构一般会在硬件上优化这个点。所以也说明代码使用间接类型的指令尽量不使用太多的目标,这对硬件来讲不友好,代码运行效率也低下。间接预测器的算法,我没有看到相关信息,但基本也是TAGE
的变体。有公开资料显示,间接指令目标地址长期不变(这里的长期需要自己去调整一个合适的值),会存入延迟较低的L1 BTB
。
方向预测使用TAGE
算法,官方描述是更大,目前比较典型的值是8-table
,有论文显示到12-table
后预测精度提升就不明显了,所以现在的优化也不是持续增加表长。在TAGE
的基础上做一些参数的优化,但现在一些很难预测的分支,它们的特性已经和TAGE
算法基本有些背离,也不能说背离,原来就是这样,只是当时TAGE
的算法没有到某个瓶颈点,现在需要挖掘不太符合TAGE
算法的一些分支规律以提升预测正确率。
有意思的是,Zen5
的BTB
使用双口的 SRAM 结构,这在预测器的设计中不常见,AMD
采用这个机制来实现每周期预测2-taken
的分支。并且实现这个2-taken/cycle
预测约束条件更少,而像其它的一些厂商会约束连续block
,不能跨cache line
等。这种设计思想来自 30 年前的论文:“Multiple-Block Ahead Branch Predictors” 对 AMD 架构师的采访:George Cozma: Can the branch predictor do two taken and two ahead branches in a cycle? Or is it 2 branches of total? Mike Clark: I mean it’s complicated, there’s rules around when we can do 2 ahead. But yes, in general I would say yes. George Cozma: So yes, to two branches per cycle, or yes to two ahead and two taken branches? Mike Clark: We can, in certain situations, do both.
AMD 实现的这个预测机制至少从理论上讲是很先进的,除了BTB
是双口,亦安之前写的文章说过ICache
也是双口,有3
个依据,“Multiple-Block Ahead Branch Predictors”论文中写的双口Cache
。AMD
架构师Mike Clark: They get fed from the dual ported instruction fetch to feed the decoder
。Decode
是双流水线恰好对应取指的机制(这里后来证实双流水线和取指双口无关),不然预测带宽可以取两个不连续的block
,取指不可以似乎有点奇怪。但C&C
文章说,核心在运行单个线程时只能使用一个解码集群,这让我觉得很迷惑,可能是将无序指令重新拼到微操作队列比较困难,但这点还是不太能理解为什么是线程独占的解码集群,有说法是因为Zen5
目标频率很高,所以做成共享的很困难,但AMD
又偏偏没采用8
宽单线程解码。后来我想了想,使用双口和双流水线的解码簇似乎是 2 个问题,后面也就没纠结这个问题了。顺便说一下,我之前曾说过双口ICache
基本没有人这样设计,实际不是,例如高通的核ICache
据说是双口 ,但还没查相关资料。
说回预测器,传统的预测流程大致是这样的,下图的i
是一个block
的有效指令起始位置,大的BTB
是SRAM
结构,访问需要下一个周期出结果,也就是一个cycle
只能拿到1
个block
。例如Aa
分支目标Bi
访问获得block B
,已知信息是block
有效指令的起始位置Bi
和block
的分支Bb
,然后再用Bb
的目标地址获得下一个block
的位置。并以此重复,每个周期只能拿到一个block
的信息。当然对于全相联结构DFF
构造的预测器当然可以在1cycle
做这些事情,但时序难。
而论文的方案是:使用Aa
分支(目标)来预测Ci
,而不是传统的Bb
来预测Ci
,使用Bb
来预测Di
。需要双口SRAM
。
具体的设计思想感兴趣的朋友可以参考论文,此处亦安不再赘述,设计本身比较有意思。其实在上个实际计算机体系结构发展迅速的时候,有非常多先进的体系结构思想被提出,但受限于工艺的发展,有些思想受限当时的应用目标的限制,而最近几年工艺发展迅速,也能支持厂商做一些激进的设计了。
取指窗口跟踪结构是FIFO
构造,存储分支预测信息,深度是128entry
,每个entry
最多存储一个Cache line
的信息,如果没有分支的话。但如果遇到分支,则需要另外的entry
来存储跳转的信息,也就是每个entry
存储的有效信息是不定的,这也很好理解,128entry
也是个相对的合适的值。这个指令跟踪FIFO
直到retire
才会释放,如果FIFO
满了,则取指流水线会stall
。
ICache
ICache
也属于前端的核心部件,对其研究非常多,像预取,替换算法,组织结构等等都有大量的论文。Zen5
的L1 Cache
是8
路组相联,具有32KB
大小,Cache Line
是64B
,每个周期可以取64B
的指令,需要2
个对齐的32B
块,这是一个瓶颈点,并且取指的双流水线不能共享,也就是如果只开一个线程,那么也不能吃满带宽,这是目前Zen5
的一个问题,但考虑到Zen5
要实现5GHz+
的频率,看上去又合理很多。L1 Cache
采用LRU
替换算法,校验使用奇偶校验方式,这两个选择都很常规,各家基本都是这么做的,替换算法如果做的很复杂,面积开销大,对于L1 ICache
收益没那么高,但L1 DCache
目前有些应用稍微复杂的算法。这里Zen5
取指带宽和Zen4
相比变为2
倍。前文也说过ICache
可能是双口的设计,但没那么确定。这里的取指带宽只是理论上的,有测试显示在某些情况下,取指带宽弱于Zen4
,考虑到前端变化巨大,有些设计非常激进,而双Decode
簇又不能双线程共享,这些可能都会造成Zen5
有些情况的性能瓶颈。
有意思AMD
和ARM
对ICache
设计理念的差异也体现双方对性能功耗面积取舍不同,ARM
自A76
开始ICache
都是4
路64KB
(大小有些是可配的),而AMD
自Zen2
一直到Zen5 ICache
均是32KB/8
路的设计,复杂指令集的指令信息密度更高,所以采用更小的Cache
也属于正常(尽管现在复杂指令集和精简指令集界限越来越模糊)。采用不同的结构对功耗,延迟以及命中率都有不小的影响。有一些相对通用模型显示,对于32KB
或64KB
的给定大小下,访问延迟均是8
路比4
路有明显的增加,而控制路数一定,仅增加Cache
大小,不管是4
路还是8
路,将Cache
大小从32KB
增加到64KB
,延迟仅有小幅度的增加。而当测试读取功耗时,同样的,一定Cache
大小,例如32KB
或者64KB
给定大小,8
路的读取功耗是4
路读取功耗的2
倍以上,当路数不变,将缓存大小从32KB
增加到64KB
,4
路和8
路功耗增加幅度均较小。从这个模型来看,似乎使用4
路而增加缓存大小对延迟和功耗平衡更好,但考虑到面积,命中率,以及有些厂商有定制工艺的角度,这种权衡不能下绝对的优劣结论,但可以看出,ARM
对能效的追求非常极致,而复杂指令集似乎对性能更加关注。亦安自己做了2
张图如下,实际数据可能有偏差,仅参考数据趋势即可。注意:考虑到路预测,解耦的TAG
和DATA
,实际的情况不会如此大差距。
关于回填,每周期可以回填一个
Cache Line
,也就是64B
,为了处理潜在的L1
核L2
之间的延迟,一般有两种比较主流的方式,更加复杂的预取算法,更加激进的预测带宽,也就是预测带宽比取指带宽大很多,这样可以提前将指令取到L1 ICache
,但是如果预测精度做的不好,性能可能下降。
Op Cache
OC
用于存储之前解码过的指令,OC
命中可以让流水线跳过取指和解码,对于复杂指令集来讲这几乎是必须要实现的特性,可以在命中时降低流水线深度,在预测错误需要恢复时如果命中也可降低惩罚周期。本代OC
具有6K entry
,低于前代的Zen4
,仅从数量上而言似乎是退步?这是因为增加了指令融合的机制,指令密度增大,属于OC
的常规优化。Zen5
的OC
每周期可以出12
条指令,如果没有命中OC
,每周期只能出4
指令/每线程,这大大提高了带宽,所以OC
的命中与否直接影响了性能。
OC
是64 set/16
路结构,每个set-way
(一个entry
)可以存储最多6
条指令或者融合指令,融合指令可以提高OC
的存储效率,其实各个SRAM
结构,例如BTB/TLB
,都有类似的来提升存储密度的微架构。OC
使用物理tag
,可以让OC
被双线程共享。
这个模块对流水线较深的处理器而言是个很常规的优化,不是近几年出的技术,对于RISC
而言,ARM
也曾出了几代类似的结构,但后来又放弃了,如果处理器的目标频率很高,流水线很深,那么这个结构还是属于必要的设计。
关于指令融合,提高信息密度,Zen5
支持的指令融合有reg-reg
的MOV
指令和ALU
指令。有如下要求:MOV
必须是reg-reg
,Opcode
是0x89
或者0x8B
ALU
跟在MOV
后面,并且MOV
和ALU
目标寄存器匹配
ALU
指令的源为寄存器或者immediate
数据,不能是内存源
ALU
指令只能获取 MOV\`\` 指令的源数据或目标数据
如果 ALU
指令有两个寄存器数据,则它们应该不同
内存管理单元(MMU)
L1 TLB
也在这里说,ITLB
是64 entry
全相联的设计,存储4KB
,2MB
,1GB
的页面,DTLB
是96 entry
全相联设计,存储4KB
,16KB
,2MB
,1GB
的页面。并且对4KB
的连续页面进行聚合,聚合4
个连续的页面。L1 TLB
的设计基本是业界常规的设计,也不会有特别花的设计方式。
L2 ITLB
是8
路组相联,具有2048 entry
,存储4KB
和2MB
页面,这里1GB
是不存到L2
的,仅存在L1 TLB
,对于指令而言,操作系统基本不会分配1GB
的页面,放到L2 ITLB
里面可能会增加潜在访问次数,从这个角度看,放到L1 ITLB
更合理(当然也可以)。
L2 DTLB
是16
路组相联具有4096 entry
,存储4KB
和2MB
,额外的4
路组相连结构的L2 DTLB
存储1GB
,具有1024entry
。这里的选择是PPA
的平衡,例如页面混装还是分开装的选择,分开TLB
装不同页面有利于降低延迟,同时访问增大了功耗。混合装页面有利于资源利用率,一个周期的功耗相对低(但完成一个任务的功耗未必低),可能需要多次访问,这里只是简单聊下,不展开讲,不同的场景这些利弊也可能不同,不是绝对的,但不会差的太远,这里的权衡不会像我讲的那么简单。
值得关注的是Zen5
的L2 TLB
非常巨大,给出个横向对比,今年(2024
年)ARM
的旗舰服务器核V3
的L2 TLB
是共享的2048 entry
,Intel
今年的Lion Cove
是1024 entry+1024entry
的大小,各家的设计基本都在2K
的样子,而AMD
则是指令2048 entry
,数据4096entry+1024entry
大小,4096 entry
的TLB
可以理解为采用了非常激进的预取,但尤其奇怪的是给1GB
的页面单独分配了一个1024
的TLB
,目前的软件生态真的会需要如此多的1GB
页面吗?这很难说,也许考虑到了CPU
的长期维护寿命。
可能会有人奇怪为什么X86
常规的页面是4K/2M/1G
,但TLB
会存储16K/4M
呢?如果大家关注过ARM
的微架构,也会有类似的情况,不同于架构常规定义的页面大小,这些大小的页面是因为有硬件聚合技术,smash
技术,连续技术等产生的。简单说硬件聚合就是将连续的 VA 和连续的PA
放入同一个TLB entry
来增加存储密度的,一般设计是4
聚合,即4
个4K
页面聚合存成16K
的大小。Smash
技术是大页面粉碎成小页面存到TLB
,这个我没有注意是不是架构支持的,如果仅是微架构支持的话可能维护需要稍微注意点。连续页面技术是架构支持的,软件配置标志位,表示连续的页面可以使用,例如RISC-V
的拓展可以实现16
个连续4K
实现64K
的页面,ARM
也有类似的机制,基本都是16
连续,只是更完善,连续的页面也更多。
硬件页面翻译,Zen5
有6
个并行的页面翻译模块,考虑到核内的TLB
是单核私有的,所以在相对短的时间不会有巨大的流量访问,一般6~8
个PTW
就属于相对冗余的设计值了。
PWC(page walk cache)
加速页面转换的过程,减少对Cache
的访问,常用的技术。
在CPU
上的MMU
相关的微架构都非常成熟了,不同于GPU
,CPU
各家做的差异不是很大,都是围绕那几个点权衡,架构上和软件上的支持倒是在不停跟进,目前笔者看到的论文都没有什么微架构的创新了,对安全/虚拟化的一些支持比较多,软硬件结合的技术也很多。
解码(Decode)
解码模块比较有特色的是采用双流水线,双流水线解码32byte x2
以支持ICache
最多出64byte
指令,每个decode
流水线有20
深度的队列IBQ
用于对预测/取指等单元的解耦。每个解码流水线可以扫描 2 个IBQ entry
,最多出 4 条指令。可惜双流水线只能给单线程使用,不可以共享,甚至当只有一个线程的时候,也只能使用一个解码簇,我不确定这个解码簇和Intel E
核的解码簇技术是否类似,从各方消息来看是不一样的。不能线程共享的解码簇是一个瓶颈,不过和intel E
核相比,毕竟Zen5
的目标频率更高,希望后续AMD
能处理掉这个问题。
两条Decode
流水线来自不同的基础block
,独立运行,并且这里发往Decode
流水线是乱序的,这和常规我们认为Rename
是乱序分界线的认知有些差异,因为X86
是变长指令,所以会有类似的解码簇技术将复杂指令转换为类似RISC
的微指令,来规避X86
的Decode
的一些固有的问题,AMD
的这个模块不清楚和Intel
的是否一样。
整数执行单元(IEU)
整数执行单元包含三个单元,调度器,执行单元,退休单元。整数Rename
宽度为8
,ALU Scheduler
和 AGU Scheduler
均可以每周期接受8 macro
,ALU Scheduler
每周期可以issue 6 micro-ops
,而AGU Scheduler
则是每周期可以 issue
`4 个
micro-ops`。
一共有6
个通用的整数执行流水线,其中ALU0/ALU1/ALU2
有multiply/CRC
能力,ALU3/ALU4/ALU5
具有PDEP/PEXT/shift/branch
执行能力,ALU3
额外具有divide
功能。考虑到Zen5
每周期可以预测2
个分支,配置3
个分支执行能力是一个比较合适的数值。整数multiply
单元可以处理最多64 bits × 64 bits
的乘法,并且是纯流水的3cycle
延迟。除法单元典型延迟是3cycle
,商每增加9bits
就会增加一个cycle
的延迟。
浮点执行单元(FPU)
该处理器原生支持 32
位单精度、64
位双精度和 80
位扩展精度主浮点数据类型,以及 128
位、256
位和 512
位压缩整数、单精度、双精度和 bfloat16
精度矢量浮点数据类型。浮点加载和存储路径宽度为 512
位。
浮点单元支持AVX-512
。
浮点单元具有96 entry
的NSQ
,浮点Rename
每周期可以接受6 macro ops
,调度器有3
个,均是38 entry
,每周期可以 issue
` 1 个
micro-op给流水线,一共
6个流水线。退休
queue`和整数单元共享。
访存单元(LSU)
访存单元用于处理数据访问,L1 Dcache
是12
路组相联,具有48KB
大小,和前代Zen4
的32KB/8
路相比,不管是容量还是路数都有提升,理论上讲命中率会有不少的提升,但是延迟保持的不错,DCache
有8
个Bank
。
LSU
每个周期支持最多4
个对Cache
的操作,所有的操作均可以是load
,支持最大2
个128/256bit
的load
或者1
个512bit
的load
,最大支持2
个store
操作,如果是512bit
的store
,则支持最多一个store
操作,带宽有了很大提升,是前代的2
倍。
LSU
可以跟踪64
个未完成的load
,并且不限制完成load
的数量,同时支持动态追踪操作,可以load bypass
更老的load
,也可以load bypass
不冲突的更老的store
,做这些操作确保不会违反架构规定的load
和store
顺序。同时LSU
可以跟踪124
个未完成的L1 MISS
。 关于访问延迟,简单的地址生成,L1 Cache
命中,有4cycle
的load-use
延迟,浮点有7cycle load-use
延迟。 简单的地址生成,L2 Cache
命中则14cycle
的延迟,浮点有17cycle
的延迟。L3
命中,简单地址生成有46cycle
的延迟,浮点有53cycle
的延迟。如果是复杂的地址生成模式,则在简单地址生成模式上增加一个周期的延迟。
二级缓存(L2C)
Zen5
的L2
是1MB/16
路,和Zen4
相比大小没有变化,相联度为Zen4 L2
的2
倍,考虑到这点,L2
的命中率应该会增加,AMD
在L2
的设计上和ARM/Intel
这些厂商相比向来是比较小的,AMD
更加重视L2
的访问延迟。但是坦白说,我自己的观点,L2
的容量是很重要的,延迟问题可以通过更好的预取,预测机制来覆盖,现在尤其是服务器的工作集越来越大,L2
能覆盖更大的数据和指令范围真的非常重要,L2
如果MISS
,很多时候代价昂贵。但AMD
的设计有自己的微架构考量,并且AMD
的3DV Cache
很受市场好评,所以这些问题可能通过3DV Cache
掩盖了。
L1
和L2
之间带宽增加到512bit
,并且优化了预取机制,官方介绍时新的2D stride
预取。
本代将8T SRAMs
改为6T SRAMs
,密度有很可观的提升,整个核在增大不少资源投入的情况下,面积没有明显增加。下图有个Zen4
和Zen5
的L2
和L3
的面积比较,相同容量,Zen5
的面积更小,当然这得益于工艺的提升,这可以让核内投入更多的资源去提高IPC
,而整个处理器的面积却不会变得很大。
Zen5 和 Zen4 比较
AMD
和自己架构的纵向对比,从Zen4
到Zen5
从参数上升级非常激进,像类似TLB
量的升级基本走了 ARM
`5 代的升级量,而某些部分的带宽升级
Zen5是
Zen4的两倍,
L1 BTB甚至是前代的
10倍,有些地方的设计让人觉得没那么关注细节,这种升级也秉承了
AMD设计的一贯“大力出奇迹”设计思路,尽管据测试显示,
Zen5有些方面在某些特定情况下性能甚至低于
Zen4,但如果能践行一些有趣的设计思路并且完善
Zen5的设计缺陷,后面的几代
Zen`系列架构依然值得期待。
END
作者:亦安QAQ
文章来源:亦安的数据小站
推荐阅读
更多 IC 设计干货请关注IC 设计专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。