高通吧 关注:187,750贴子:5,115,124

66锐评——Oyron 3—黔驴技穷

只看楼主收藏回复

书接上文,我确实没能想到,在之前锐评过Oyron 1、2邯郸学步后,在今年还能对其最新架构有如此负面的评价,那么你们也应该能猜测出该架构有多么令人失望,那么,接下来的文章,在征得某不知名宝可梦老师的同意后,得以借用其逆向数据对Oyron 3的架构进行深入的分析,让我们看看,Oyron 3究竟在架构设计上表现如何,其与其友商的差距还有多远。
那么,我记得去年,应该是6月的时候,我写过一篇有关Oyron 1的文章,那时候我的结论就是邯郸学步,你从整体架构看完后只有一个想法,Firestorm V2,没错,就是这么朴实无华,一个20年的架构在和24年的架构抗衡,那这时候就有读者会想,啊,既然是Firestorm V2,为什么我看网络上的评测,其在GB6,SPEC17中并未落入下风呢?其实这个道理很好理解,毕竟还在20年的时候,Firestorm用着TSMC N5,第一代5nm工艺,只有2.99/3.2GHz的选择,而我们的Firestorm V2呢?在经历了4年半导体技术的发展,以及对D-cache进行一定的缩小确保时序,N3E搭配4.3/4.47GHz的频率加上Firestorm本身还不错的底子,其实在benchmark上并不会输多少。为什么呢?
或许是体系结构的悲哀吧,已经很多年没有什么活了,在体系结构方面做出许多的努力去提升IPC(不是benchmark score除以frequency的PPC),所带来的整体收益并没有直接的超频来的效果更好,在同样的工艺红利下,体系结构的新技术可能比超频吃掉的工艺红利更多,甚至需要用很大的代价去换一点点的提升,工业界在体系结构的创新上哪怕能够贡献3%-4%的IPC都要开香槟庆祝的当下,超频是相对最简单,也是相对最低成本抹平与友商技术差距的方式。但是,这个方向一定是正确的吗?体系结构的未来难道只会是频率战争吗?我们真的希望体系结构的结局是频率战争吗?
那么在经过开头后,我们也该分析一下今年的Oyron 3了,它究竟如何呢?那我们先从架构图说起吧。我们先来看看Oyron 3的P和E-Core。

从前端(front-end)设计出发,可以观察到Oyron 3依旧采用coupled front-end(耦合式前端)。和前代与Apple CPU前端的设计选择一样。该选择在分支预测精度、关键路径组织与实现复杂度方面具有一系列工程优势。
1、Coupled front-end的核心收益:更高的预测精度与更低的错误代价
在coupled front-end(耦合式前端)中,分支预测(BPU/BTB)与取指(fetch)可以并行推进:fetch PC的生成与指令访问在同一前端节拍内协同发生,因此前端能够以较低的额外流水级数完成“预测→取指→送往解码”的闭环。这带来两个直接结果:预测信息更“近”解码语义:耦合结构往往能更快获得与指令边界、控制流相关的解码辅助信息,从而降低在仅凭前端结构性线索进行预测时的歧义性,整体上有利于压低MPKI(mispredictions per kilo-instructions),即提升分支预测正确率。错误恢复成本更低:由于预测与取指并行且流水级数相对短,一旦发生误预测,其清刷流水与重定向(redirect)的距离更短,总体mispredict penalty(误预测代价)更可控。此外,coupled front-end在工程实践中往往更容易在较早阶段调出性能。


IP属地:陕西1楼2026-02-16 14:56回复
    前排


    IP属地:北京来自iPhone客户端2楼2026-02-16 14:57
    回复
      2026-04-22 20:27:06
      广告
      不感兴趣
      开通SVIP免广告
      2、Decoupled front-end的结构性代价:更大BTB覆盖、更深流水与更复杂的重引导
      相对地,decoupled front-end(分离式前端) 将“分支预测路径”与“取指/缓存路径”拆分,典型数据流为:fetch PC先经过BPU/BTB形成预测目标,再驱动I-cache访问。这一组织方式会引入若干结构性约束:
      (1)BTB/预测结构规模压力更大
      在分离式组织中,为保证预测路径能够持续向前推进并提供足够的控制流覆盖,BTB往往需要承担更强的“目标地址供给”能力。尤其当系统希望在该框架下开展更积极的instruction prefetch时,预测结构所需的控制流覆盖范围可能超过I-cache的有效覆盖范围,从而对BTB容量、关联度或层级化设计提出更高需求。
      (2)更长的前端流水级数与关键路径叠加
      Decoupled设计通常伴随longer stage pipeline(更长的前端流水):预测→队列化→取指→对齐/供给等环节被拆分为更多级。这固然有利于提高频率上限,但会引出典型的“频率–能效”权衡:流水变深可提升Fmax(最高频率),却可能因为更高的控制开销与更频繁的flush/redirect扩大能耗与性能损失;流水过浅则限制频率目标。该问题本质上是微架构设计的多目标折中(trade-off)。
      (3)误预测与BTB miss的恢复链条更长
      由于预测先行、取指后随,分离式结构中误预测的代价往往更高:错误路径被更早、更深地展开,导致需要清除的在途状态更多;同时,流水级数增加也可能把BTB miss等事件推向更关键的时序/延迟路径。当BTB未命中或目标地址需依赖decode/execution才能解析时,系统需要在decode(或更后阶段)产生目标并重新引导BPU(re-steer / re-direct),而在分离式框架下,这种“后端产生目标→前端重定向”的往返延迟通常更显著。
      (4)实现复杂度与时序收敛难度上升
      Decoupled front-end往往引入额外的队列与控制结构,例如FTQ(Fetch Target Queue)(如Figure1),用于在预测与取指之间缓存/排序fetch target、维护重定向与回滚语义。该类结构会显著增加控制逻辑复杂度、状态一致性验证成本以及timing closure难度。
      3.为什么decoupled仍是现代主流方向:高指令压力场景下的带宽与容错优势
      尽管分离式前端存在上述代价,它仍然被认为是现代高性能处理器前端的重要演进方向,原因在于其对“高指令压力(instruction-intensive workload)” 的适配能力更强:
      (1)在指令工作集巨大、I-cache miss更频繁的负载下,耦合式结构容易出现“取指阻塞向前端反压”的链式停顿:I-cache miss使pipeline stall,fetch queue产出不足进一步迫使BPU一同等待,前端整体吞吐受限。
      (2)而在decoupled组织中,BPU与fetch group / I-cache访问弱绑定:当I-cache/取指路径被miss拉长时,若BPU的预测推进速度仍高于fetch queue的实际产出速度,便可以利用“多出来”的预测信息窗口开展更积极的控制流探索与prefetch(例如对潜在目标路径进行提前准备),从而显著缓解高miss率下的前端饥饿问题。进一步地,将BP与fetch解耦也有利于前端进行更细粒度的流水化与更高频设计(在可接受的复杂度预算内),因此在追求高频与高吞吐的平台上具有现实吸引力。
      4.小结
      综上,coupled front-end体现了一种更偏向预测精度、恢复成本、实现可控性与早期性能调优效率的工程取向;而decoupled front-end尽管在BTB/队列结构、流水深度、误预测代价与时序收敛上成本更高,但其在I-cache miss频繁、指令供给压力极大的工作负载下,通过解耦带来的“预测先行+预取机会窗口”能够获得显著收益,因此仍被视为前端架构的主流演进路径之一。
      那么在了解了前端的细节之后,我们提到了BTB,那么现在,我们来看看BTB,很显然,Oyron 3-L只有一级的2048-entry的L0 BTB,M则为1024-entry的L0 BTB。如下面4图:


      IP属地:陕西3楼2026-02-16 14:59
      回复
        来了


        IP属地:广西来自Android客户端4楼2026-02-16 15:00
        回复
          我们能够发现,整个BTB的容量是一致的,不同分支长度和其循环数的乘积于拐点处的数值是一定的,这其实向我们展示了这个BTB的类型是R-BTB,什么是R-BTB,什么是BTB的类型,BTB分三类,I-BTB,R-BTB,B-BTB。
          I-BTB以“分支指令PC”为粒度建表,结构直观但在宽取指下往往需要对取指块内多条指令做多次查询,tag与能耗开销偏高;R-BTB以“对齐region(如一条cache line)”为粒度,一个entry内用若干slot记录该region内分支的offset/目标,查询次数少、tag摊薄但受slot数限制,分支密集时容易装不下;B-BTB以“基本块/取指流(fetch stream)”为粒度,一个entry覆盖连续指令并可容纳多分支信息,更匹配宽取指与多分支预测,但entry管理与更新更复杂,且可能产生一定冗余。
          总体来说,B-BTB无fetch瓶颈,但其利用率较低(重复存储指令多),使用均取决架构;R-BTB缺陷较大,分支密集会炸,fetch也有问题(例如分支密集时容易装不下),所以较少使用;i-BTB是老产品,I-BTB的每一个entry对应I-cache的一个指令,所以没有利用率低的问题,但是这样2-taken就很难实现。这也就是为什么Apple会在去年的架构(A19、M5)上使用Trace Cache去实现2-taken,毕竟I-BTB啥都好,就是2-taken不好搞,我记得M1、M2还是R-BTB,到了M3才改成I-BTB的。不过对于Oyron来说,自己做还不如抄。
          这里还需要引入一个课外知识点——MB-BTB,MB-BTB(Multi-Bank / Multi-Block Branch Target Buffer,多块式BTB)本质上是把传统“单体BTB”拆成多个并行可访问的bank,并且常配合按取指块(fetch block)/指令块(trace/基本块)来组织与返回BTB命中信息:一次前端取指通常会覆盖一段连续PC(例如16/32/64B取指窗口),这段窗口里可能同时包含多个控制流指令(条件分支、无条件跳转、call/ret、间接跳转等),MB-BTB通过banking +多路/多条目并行读,在一个周期内对多个候选PC(或多个指令槽位)做tag比较并返回多个target/类型/预测元数据,从而把“每周期只能预测/提供一个跳转目标”的瓶颈提升为“每周期可覆盖一个取指块内的多条分支”;其收益主要是:在宽取指/宽解码(甚至trace cache / block-fetch)前端里显著降低因BTB端口不足导致的fetch stall,同时提升多分支密集代码(if-else链、switch、异常路径、函数序言/尾声等)的前端供给能力;代价是:硬件更复杂(bank冲突仲裁、跨bank复用/复制策略、替换与一致性维护、能耗与面积上升),并且设计上常需要权衡“victim/包含关系(inclusive)”“bank hash/索引函数”“每块返回多少条分支”等参数来在命中率、吞吐和功耗之间折中。Mongoose M5因为MB-BTB结构,才能让L0和L1才能0cycle出结果。AMD的MB-BTB同理L0和L1,但L2为victim cache,不好说其结构。MB-BTB的问题是在后端瓶颈下,优势会急剧缩短,如果在后端跟的上的情况下可以做到接近I-BTB的水平。
          这里就需要讲讲Zen4和Mongoose M5了,首先讲讲Zen4,其L1 BTB拥有着低延迟,其做了一种优化,即通过previous fetch block优化,实现了1 cycle下能做出更大容量的L1 BTB,通过让BTB是用之前fetch block的地址去查询,而不再是当前fetch block的地址。用当前fetch block的地址查询BTB很好理解,要寻找某个地址开始的第一个分支,就用这个地址去查询BTB,Zen 1和Zen 2都是如此;用之前fetch block的地址,则是用更早的信息,去获取当前fetch block的信息。
          接下来说说Mongoose M5,其增加了Empty Line Optimization优化:检测没有分支的缓存行,如果确认缓存行没有分支,那就不用预测里面的分支了,可以节省功耗。


          IP属地:陕西5楼2026-02-16 15:01
          回复
            为了进一步优化taken branch的吞吐,在mBTB中记录分支的目的地址时,不仅记录在分支本身所在的mBTB entry中,还要记录在这条分支的前序分支的mBTB entry中:例如A跳转到B,B跳转到C,经典的实现是用A的地址找到A的BTB entry,entry中记录了A目的地址是B,接着用B的地址找到B的BTB entry,entry中记录了B的目的地址是C;而Exynos M5的设计是,C的目的地址,不仅要记录在B的BTB entry中,还要记录在A的BTB entry中。不过这里要求B的跳转是always-taken或者often-taken,因为并没有对第二条分支做预测,而是预测它一定会跳。通过这样的方法,可以在2-bubble的预测器的实现下,实现1 taken branch/cycle的吞吐,等效于一个0-bubble的预测器。下面是论文中对mBTB从2-bubble到1-bubble最终到0-bubble的变化的对比图:
            最左边的SHP 2-bubble就是最初的实现,它需要在B3得到分支是taken还是not taken的信息,如果和之前预测的不一样,那就需要flush掉流水线,B1重新从正确的地址开始,然后重复这个过程,由于每次都需要到B3才能得到正确的地址,所以三个周期一个taken branch。
            中间是改进的1AT 1-bubble实现,它在mBTB中记录了这个分支是否是Always Taken。因为mBTB在B2中读取,所以这个信息在B2就可以得知,例如图中A分支到达B2时,检测到它是Always Taken,下个周期的B1直接就从正确的地址B开始,同理B到达B2时,又发现它是Always Taken,下一个周期的B1又从C开始,所以两周期一个taken branch,前提是分支是Always Taken,通过避免分支预测来减少一个周期的bubble。
            右边是最后的ZAT/ZOT 0-bubble实现,它在mBTB中记录了后续两个分支的地址,例如X在mBTB中记录了A和B的地址。当B3发现X要跳转的时候,刷流水线,在接下来的两个周期里分别给B1提供了A和B的地址。当A到达B2时,A在mBTB里记录了B和C的地址,于是把C的地址转发到下一个周期的B1,依此类推,B2的B得到了D的地址,B2的C得到了E的地址,这样实现了每个周期一个taken branch。通过记录两跳的地址和避免分支预测(把Always Taken和Often Taken都预测为Taken),两个周期给出两个地址,减少两个周期的bubble。这时候就相当于有两个0-bubble预测器了,mBTB有0-bubble能力,uBTB也有,所以Exynos M5减少了uBTB的容量,换取更大的mBTB的预测器容量:SHP的表数量翻倍,GHR历史长度增加。
            虽然mBTB在特定情况下可以做到0-bubble,但是如果总是需要纠正预测错误,就会回退到三个周期一条分支的性能。为了解决这个问题,Exynos M5引入了Mispredict Recovery Buffer(MRB):针对比较难预测的分支,记录它后续最可能执行的三次fetch的地址,如果命中了MRB,那就直接从MRB中按顺序用三个周期把这三次fetch的地址放到B1,然后流水线去验证这三个fetch地址是否正确,节省了重复的B3到B1的重定向时间。这个思路有点像大模型的推测生成:用比较短的时间预测(在这里是直接用MRB记下来了)出一个本来是串行的过程的结果,然后再用流水线或者并行的方式去验证结果是否正确。利用的性质都是,串行生成慢,但是验证结果却比较快。


            IP属地:陕西6楼2026-02-16 15:03
            回复
              还有一个是IBM的设计,虽然在z15上已经取消了,但是我认为如果在服务器,或者前端分支压力非常高的环境下,比较合适的设计,这就是BTBP,整体思路上来说,大型工作负载的性能瓶颈往往不是“方向预测算法不够准”,而是BTB容量不足导致大量分支变成surprise branch(第一层没预测到,只能静态猜/晚到)。所以该设计的核心目标就是:在不牺牲一级预测器时延/功耗的前提下,把“有效BTB容量”做大。方案是一个两级层次化BTB:所有真正影响取指/前端控制的预测只从低延迟的一级发出;二级只在“疑似一级容量缺失”时被唤醒,并把一批相关分支信息批量回填到一级。
              所以,BTBP是什么?BTBP(Branch Target Buffer Preload Table)=一级预测器中的“预装载/缓冲BTB”,作用可以概括为三点:
              (1)BTBP与BTB1并行读参与预测:BTBP本身也是BTB(存tag、方向信息、目标地址),和BTB1同时被读来做预测。
              (2)其作为BTB1的“过滤器(filter)/预热层”:分支信息往往先写进BTBP;当BTBP的条目真的被用来做预测时,再“晋升”进BTB1。
              (3) 其作为BTB1的victim buffer:BTBP还能接住BTB1被替换出来的victim;并且在BTBP→BTB1晋升时,BTB1 victim会被送入BTBP和BTB2(形成回填—替换—下沉的流动)。
              总的来说,BTBP预加载表,在L1 BTB和BTBP并行访问时,进行预测。如果BP预测的内容是BTBP中的,则该内容会被移动到L1 BTB中,然后L1 BTB被替换出的表项会被写给L2 BTB/BTBP。L2 BTB半独占,因为完全独占压力太大,毕竟1-2cycle内做到使用对timing和power压力很大。面对超高压效果好。动态调节替换算法。如果BTBP写入L1 BTB时,L1 BTB被替换的表项写到L2 BTB中,LRU同时变成MRU(最近使用表项)因为L2 BTB中的LRU表项有可能会被L1 BTB被命中的表项插入,此时可以避免实现完全独占性所需要的额外写入。(通过替换的方式,避免额外写入。)可以相对应做大,不需在乎一定的latency。这样设计的缺陷是L2 BTB仅负责存元数据,不能直接参与分支预测。并且由于BTB1体积较大,可以用SRAM实现,但SRAM的读写端口数量有限(通常为1或2个读取和一个写端口,限制是同一周期内无法读写同一个bank),由于BTBP比BTB1小得多,因此可以用寄存器实现。BTBP可能拥有多个读写端口,可以同时使用。因此,多个分支预测信息源可以通过先写入BTBP来利用BTBP的写带宽。BTBP可以被构造为BTB1的滤波器。
              当然,这项技术起于IBM z12,终于z15,毕竟z14、15靠eDRAM搭了16k-entry L1 BTB和128k-entry的L2 BTB大力出奇迹后,BTBP其实作用有限了,毕竟其对面积和能耗来说是很大的问题,确实不太合适继续保留下去。毕竟eDRAM能够在不扩大面积情况下堆下更大的容量,大力出奇迹有时候并不是不好的情况,不过我看之前香山有在PPT提过这个技术,不过可能受限于他们还没有数据中心业务,应该是没做进去。


              IP属地:陕西7楼2026-02-16 15:04
              回复
                补充一下Intel L2 BTB的设计:专利提出一种“按分支类型分段”的BTB:把高频直接分支的目标放进hot cache,并进一步按“同页/跨页”分别用delta(位移)或page+offset(页号+页内偏移)来编码目标地址,同时用PC索引的BTB monitor快速指示目标存放位置;低频直接分支与间接分支则集中放在更小的target cache,避免被高频分支挤掉;再配合可选的ISA/编译器hint(如streaming、跨页、热门、phase等)来指导分配与替换,从而在相近甚至更小的存储成本下减少BTB miss/mispredict引起的前端重定向与停顿、提升整体性能。
                这项技术本质是“分层/分段BTB(segmented BTB)+目标地址的结构化编码(delta或page+offset)+可选软件hint的资源管理”:对高频直接分支优先放进hot cache,若目标与分支PC同页就只存一个小位宽的位移delta;若跨页则把目标拆成页号page +页内偏移offset分别缓存以便复用;而间接分支与低频直接分支集中放到target cache,避免被高频项“挤爆”,并通过一个PC索引的monitor指示该去哪个子结构取目标(必要时还允许ISA/编译器提供streaming/popular/phase等hint来影响分配与替换)。优点:对最常见的direct branch用更小位宽表示目标、提升有效容量与命中率;把不同统计特性的分支隔离,减少相互污染(pollution),降低BTB miss/错目标带来的前端重定向与停顿;page+offset还能利用跨页call的目标复用进一步省存储。缺点:结构更复杂(多子表+路由/一致性/更新策略),验证与时序闭环更难;需要并行查表或增加monitor命中路径,可能带来额外功耗/面积/延迟风险;若工作负载“同页/跨页/热度”分布与假设不符,分段可能出现容量错配(某段紧张而另一段空闲);软件hint若不准或缺失,收益会下降甚至造成错误的资源偏置。
                还有就是BTB-X,是一类学术提出的、以“节省BTB存储”为目标的BTB组织方案(Truls Asheim等人在2021的IEEE CAL提出,2023在HPCA扩展到更完整版本)
                BTB-X的核心思想是存“目标偏移”而不是存“完整目标地址”。传统BTB每个表项通常要存很宽的target address(例如48/52/57bit级别虚拟地址的目标),这在BTB面积里占大头。BTB-X的关键是:绝大多数分支的目标地址在虚拟地址空间里离分支PC很近,所以用“PC到目标的距离(offset)”编码,能显著减少target字段宽度。CAL版本明确写到:通过把目标编码为相对分支指令的offset,而不是完整target,可以带来“drastic storage savings”。HPCA版本同样强调:存target offsets(而不是full/compressed targets)能显著降低BTB存储成本,因为多数动态分支的offset只需要很少的bit。由于offset长度分布很不均匀(大量短跳转、少量长跳转),在实现上BTB-X不用“一刀切”的固定offset宽度,而是把一个逻辑BTB切成多个物理分区(或在实现上做成多路set-assoc的“不同大小way”),相应的,BTB-X表项里存的是offset,前端在命中时用branch PC + offset(以及forward/backward符号位等)恢复出真实target,然后用于取指重定向。所以其本质是“目标地址字段压缩+轻量重建”。
                总结:BTB-X =“用多档位的offset编码来存BTB target”,把BTB的主要存储开销(target字段)按分布做分层,从而用同样面积装下更多分支。
                不过很显然,我们高通在面对体系结构提出的诸多方案中,选择了弹幕最多的打法,抄袭(bushi)借鉴业界“先进”技术(人话:直接拿Firestorm的BTB增大一倍容量,完事。)。emm,人家高通还是个孩子,让一让怎么了。


                IP属地:陕西8楼2026-02-16 15:05
                收起回复
                  2026-04-22 20:21:06
                  广告
                  不感兴趣
                  开通SVIP免广告
                  说完了BTB,我们看看BPU中重要的一环——预测器,现阶段,预测器基本以TAGE为主,因为TAGE是目前MPKI,正确率,IPC,面积与能效的最优解,现代微架构都会在预测器上选择TAGE或者在TAGE的基础上对T0表或者每个entry的结构进行改进,那么,什么是TAGE?TAGE预测器(TAgged GEometric history length)是一类高性能的分支方向预测器。它的核心思想是:用多张表并行预测;每张表使用不同长度的全局分支历史(GHR);历史长度按几何级数增长(例如0、4、8、16、32、64、…);表项带tag(标签) 来避免不同分支/历史模式的别名冲突;
                  选择“最长历史且tag命中”的那张表作为主预测(通常再配一个“备选预测”机制)。它之所以强,是因为:短历史能快速捕捉局部相关性,长历史能捕捉跨循环/跨函数的长期相关性,而tag机制把多表并行带来的别名问题控制住。
                  而在今年CBP-25中,提出了一系列对TAGE的优化。首先,我们回忆一下CBP-2016,16年时候提出了一个TAGE的改进:TAGE-SC-L,其虽然在比赛上赢得了冠军,但其有相当多的问题不适用于工业界,这就是可怜的Intel为什么BP这么菜的原因,(就连比较学术的香山,都把TAGE-SC_L的L给撇了,Intel居然不知道?)。那么,我们来看看近10年,学术界在TAGE上又玩出了什么花。
                  首先,我们说说CBP-2016上的TAGE-SC-L有什么问题,其存在一系列“硬件不可接受”的要素:TAGE组件表太多、SC组件表太多、总预测延迟不现实、SC使用局部历史(OOO上投机局部历史管理极难),在当时,SC甚至发展出了MGSC这种小型预测器,已经相当偏离工业界了,在学术的道路上走的有点过于歪了。这个怪物是由6个组件组成,1个偏置组件和5个GEHL-like组件。
                  1个偏置组件:由PC和TAGE预测方向索引。由两个用不同哈希函数进行索引的表组成;当分支B在方向D上被预测时,并且已经观察到在大多数类似的情况下,B被错误预测,则偏置组件将指示恢复预测。
                  5个GEHL-like组件:分别使用全局条件分支历史(4个表)、返回堆栈相关分支历史(4个表)、一个256项局部历史(3个表)和2个16项局部历史(4个表和3个表)进行索引。其中全局条件分支历史组件在其索引中还使用TAGE输出。MGSC是普通SC面积的8倍,把一个关联表变成特化预测器,给TAGE做翻转用。这太疯狂了,不是吗?
                  所以作者在其2024“engineering cookbook”中提出“realistic”版本,定义为:面向激进前端(每周期预测一个指令块,最多4条分支且最多1条taken)时仍有希望落地的实现。关键工程化点是:物理tagged表数量限制到7张,通过“物理表共享多个逻辑表”维持精度、SC的计数表数量限制到1~5、预测延迟做到只比纯TAGE多一个mux(TAGE与SC并行访问,最后4:1选择)。
                  然而本文投稿的CBP2025版本刻意复刻了许多不利于硬件实现的特性(如大量不同表、TAGE完全交织、SC局部历史、不现实的预测延迟等),但吸收了cookbook中两类新优化:TAGE的分配/替换(allocation/replacement)策略优化、SC中IMLI相关组件的优化。
                  我们首先看看TAGE侧的优化:Base table加强:base(T0表)用3-bit counter(不是传统2-bit),并做“相邻项低位共享”、更宽tag:在高预算下用14-bit tag来降低别名冲突、更强的Useful位:U从1-bit提到2-bit(更适合高预算/更长驻留需求)、Path aliasing抑制:每条分支在path表示中使用5 bits,降低“不同路径折叠成同一历史”的问题、历史长度分布调整:最长历史1000、最短3,且不严格按几何级数,更偏重中间长度。时序方面:采用HCpred(“最高匹配且非低置信度”的命中)作为alternate prediction,有助于缩短TAGE预测计算关键路径。当然也有Ahead的方式(参考我之前写的Ahead Prediction文章)。


                  IP属地:陕西9楼2026-02-16 15:08
                  回复
                    还有最主要的:allocation / replacement策略优化,因为这些都发生在更新阶段(不在预测关键路径),因此更重要一些,弱provider失误时也更新alternate:当longest match counter很弱且发生误预测时,同时更新alternate entry,补足训练;一次误预测,多表同时分配(multi-allocate):mispredict时从多个历史长度表里同时分配多个entry;并把第一个新分配entry的U置1,防止在下一轮smooth U reset前被快速驱逐。分配过滤(allocation filtering)用概率控制“写表强度”:用probabilistic counters估计弱态provider的置信度;置信度越低,分配概率越小(例如1/16、1/4、1/2分级);置信度较高时,反而增加分配entry数量(更积极学习真正有价值的模式,同时减少污染);保护“最近有用”的entry:U直接置2:让条目跨过一次完整的smooth U reset间隔仍能存活;2-way skewed associative +重组织式替换/分配:Tagged表采用2-way skewed associativity,并在替换/分配时做类似Elbow Cache / ZCache的“重组织”,缓解冲突。
                    接下来是SC的优化:“只用TAGE输出特征”的SC(低成本高收益):一部分SC表只用PC + TAGE输出(HCPRED、LongestMatchPred等)来索引(例如PC、PC xor(TAGE输出)等),从而带来显著收益;
                    IMLI组件重工程化(替代/弱化loop predictor的价值来源)通过使用两类IMLI计数:
                    (1)BrIMLI:同一region内连续taken的backward branch次数(region例:64B)。
                    (2)TaIMLI:target落在同一region内连续taken的backward branch次数(同样64B)。
                    CBP2025版本还把IMLI“加倍”:额外加入4B region(即精确到branch address/target)的另一对表,但收益“边际化”。
                    增加GEHL风格的全局历史组件(两套不同索引方式):引入“贡献权重”动态调节:对IMLI与local-history相关贡献使用乘性因子,正确则增强、错误则减弱。
                    阈值拟合(threshold fitting)优化:只在SC sum大于阈值一半时更新阈值,减少噪声更新。
                    Local history:有用但不“值”:论文指出,local history带来的总体精度收益约3%,但真实硬件上投机管理复杂度很高,不推荐作为硬件实现优先项。
                    最后就是我们可怜的Loop被撇了,其确实用处不大,增益极小,且IMLI已覆盖多数loop predictor的收益来源,同时硬件实现也较复杂。
                    总结,TAGE侧用更聪明的分配/替换策略减少污染并加速学习;SC侧用“只依赖TAGE输出”的纠错+重工程化IMLI捕捉循环结构;同时明确弱化/规避local history与loop predictor的硬件不划算部分。
                    整体而言,在工业界,其实主要还是换T0表为主,毕竟2bit-counter的正确率还是太低,除了换成3bit-counter,就是换成bi-mode,对整体TAGE的正确率有所提升,当然,TAGE的启动时间也会相应的受到影响,3bit肯定没2bit启动快,更何况换成感知器或者多视角感知器,除了提升防侧道攻击的能力,并没有太大的收益,毕竟感知器不如TAGE精度高,启动也不快,过多的加权求和,延迟也低不下去,(ARM搞这玩意就是想保住性能同时提升安全水平)至于SC,除了intel还有一些RV喜欢,其他家好像对其并不怎么感兴趣。L的话,已经似了。
                    现在我们在看看Oyron的预测器设计,可以发现,上述所有的方案都没有用到,又是用了一招弹幕最多的打法,直接抄袭,为了找到这个证据,我翻遍了全网的论文,还真让我找到了,这篇叫:《Dissecting Conditional Branch Predictors of Apple Firestorm and Qualcomm Oryon for Software Optimization and Architectural Analysis》的论文向我们展示了Firestorm的TAGE结构,以及Oyron到底抄的有多彻底。具体的逆向内容因为篇幅就不讲了,我们具体说说结构。


                    IP属地:陕西10楼2026-02-16 15:10
                    回复
                      首先,我们从论文中的出第一个结论,Firestorm的TAGE总共有6个table,并且除这些带标签的历史表外,还包含一个基础的两位饱和计数器表(base predictor)用于无历史或极短历史的情况。Firestorm的6个PHT(Pattern History Table,模式历史表)按几何递减的历史长度配置,最长历史表利用最多的全局历史信息,最短历史表仅利用非常有限的历史信息。表中每一项存储一个部分标签(tag)和两位饱和计数器等信息,用于分支方向预测。当取指阶段需要进行分支预测时,分支指令的程序计数器(PC)会同时查索引基础预测表和所有6个PHT,各PHT根据自身配置的历史长度提取全局历史寄存器的相应比特参与索引计算和tag比对。如果某个PHT的索引组中存在与当前分支PC匹配的tag,则该表提供一个预测结果;若多个表命中,则优先采用历史最长的那一级表的结果。这种“最长匹配优先”策略确保了尽可能利用长历史关联提高预测准确度,同时保留短历史表用于训练尚未收敛的新分支模式。Firestorm中各级TAGE表的长度配置及结构参数如表1所示。
                      我们发现,上表可以看出对比学术界常用的GHR(Global History Register,全局历史寄存器),Apple这种在工业界对TAGE的实现上并没有使用传统GHR的方式,而是使用了PHR的方案,我们具体看一下该方案。在此之前我们先看看GHR。
                      如图1:TAGE分支预测器的结构示意图(以传统TAGE架构为例)。上图展示了TAGE预测器的基本组成,包括基础分支预测表(Base Predictor)和多级模式历史表(#1至#N)。每级PHT使用不同长度的全局历史寄存器内容(GHR/PHR[0:L-1])以及当前分支的PC通过哈希函数计算索引;查找得到相应组的多个候选项后,通过比较部分标签(Tag)确定命中项,据此给出分支方向预测。在多个PHT均命中时,选择历史长度最长的那个表的预测结果作为最终方向。例如,Base Predictor通常是不带标签的双位饱和计数器表,只利用PC索引;而后面的第1表、第2表等分别利用越来越长的历史记录(如图中从L1到Ln逐渐增大)。Firestorm和Oryon的TAGE结构与图中原理完全一致,但内部实现更为复杂:它们将全局历史拆分成PHRT和PHRB两部分,并在索引计算中采用了非常规的异或组合(非简单连接如图示)以提升散列效果。此外,由于它们的某些PHT为4路或6路组相联,上图中每级表实际上对应多个Tag/Counter存储单元并行比较。图中未画出的还有预测结果选择器(MUX):实际硬件中,如果短历史表命中而长历史表未命中,短历史表的预测会暂存,直到确认无更长历史命中时才用于输出方向 。这个过程在电路上由优先级选择逻辑完成。值得注意的是,图中只示意了方向预测;在现代实现中,为了同时提供跳转目标地址,还配有分支目标缓冲器(BTB)等单元协同工作,但这些单元独立于TAGE结构,在此图中略去。总的来说,图1形象地说明了TAGE预测器通过多级历史表协作来提高预测准确性的工作原理。


                      IP属地:陕西11楼2026-02-16 15:12
                      回复
                        Firestorm使用了路径历史寄存器(Path History Register, PHR)方案来记录全局分支历史。不同于传统只记录分支是否跳转的简单移位寄存器,路径历史寄存器综合了分支地址和目标地址等信息,通过移位和哈希异或更新,从而在有限长度的寄存器中压缩记录最近一系列分支的执行路径。具体而言,Firestorm实际上维护了两段并行的历史寄存器:一段记录目标地址相关历史(记为PHRT),另一段记录分支指令地址相关历史(记为PHRB)。每当遇到跳转执行的分支(无条件或条件为taken),处理器将这两个寄存器左移一位,然后将当前分支的目标地址和自身地址的若干比特映射成“特征值”(footprint),分别异或注入到PHRT和PHRB的最低位。对于AppleFirestorm,实验发现PHRT寄存器最大宽度为100位,意味着最多可保留最近100次分支跳转的历史踪迹。PHRB寄存器则宽度较小,为28位。这两段历史在每次更新时使用的地址比特也有所不同:仅分支地址的第5:2位(即去除低2位对齐后的4个低位比特)参与PHRB的异或更新,而目标地址的第31:2位(去除对齐位后长度为30位)则参与PHRT的异或更新。换言之,Firestorm的全局历史记录充分利用了执行路径信息:分支源地址低位编码了不同分支的大致位置,目标地址则提供了跳转去向,两者结合可较好地区分不同执行路径模式。这种设计远比早期Intel处理器仅使用简单分支方向或少量PC位更新历史的方案复杂,但能有效降低不同分支模式互相混淆导致的alias影响。
                        上述PHR更新机制可形式化描述为:如图1
                        其中<< 1表示寄存器左移一位,比特异或按位异或(bitwise XOR)的结果即为新注入的历史信息。由于Firestorm的PHRT有100位宽度,在连续发生100次分支跳转后,最早的历史位将被移出且对预测不再有影响,这对应了前述“记录最多100条最近分支”的实验证明。PHRB宽度28则意味着Firestorm对分支源地址的轨迹保留大约最新28次跳转的低位信息。值得一提的是,测试表明在Firestorm中,如果人为翻转分支地址中高于bit5的位,不会影响预测的命中率;而翻转bit5–2则会导致预测错误率显著变化。这验证了上述结论——Firestorm仅使用分支地址最低的4个有效位参与全局历史计算,更高位地址位不直接贡献于PHR footprint。这样做的原因可能是高位地址位变化往往对应代码段的不同,但对于全局模式相关性影响不大,且使用过多地址位会增加历史混乱度;而低位地址位能区分临近分支,提供适度的路径区分能力。
                        模式历史表(PHT)组成(图二):Firestorm的TAGE包含6个带标签的模式历史表(不计基础预测表)。前面的表1列出了这6个PHT的主要参数。可以看到,各表使用的历史长度逐级递减:第1表(历史最长)利用约100位目标历史和28位分支历史,即充分利用了PHRT和PHRB的全部长度;第2表使用约57位目标历史和28位分支历史;第3表约32位目标历史和28位分支历史;到第4表历史长度降为18位(目标和分支各18位);第5表11位;第6表仅约6位。这样设计实现了接近几何级数递减的历史长度序列,符合TAGE理论对历史长度选取的建议。其中较长的历史表擅长捕捉长距离的分支依赖关系,而短历史表则快速捕获局部模式并加速训练收敛。从硬件结构上,每个PHT采用组相联方式组织,以降低不同分支映射到同一索引产生冲突的概率。Firestorm的前4个PHT均为4路相联,每表的索引位长度在第1–3表为10位(即共有2^10=1024个索引,每个索引处有4个候选表项),第4表索引为11位(2048组)。值得注意的是,Firestorm的第5和第6表提高到了6路相联(索引长度仍为11位)。这意味着最后两个短历史表具有更多的表项容量(每表约2048×6=12288项),有助于降低经常跳转的简单分支发生冲突别名的概率,从而提高预测准确度。但增加至6路也提高了每次查找需要比较的tag数量,反映出Apple为提升预测命中率在硬件成本和复杂度上做出了更激进的设计取舍。


                        IP属地:陕西12楼2026-02-16 15:13
                        收起回复
                          索引与Tag计算:每个PHT的索引和标签(tag)都是当前分支PC与全局历史寄存器内容通过特定哈希函数计算得到的。在Firestorm中,研究者通过微结构测试恢复了各级PHT索引函数的大致形式。以历史最长的第1表为例,其索引使用了10位,由PHRT和PHRB中多组位的按位异或构成,其中包括两位来自分支PC。具体恢复的索引比特组合如:
                          位0 = PHRT[2]⊕PHRT[43]⊕PHRT[93]
                          位1 = PHRT[7]⊕PHRT[48]⊕PHRT[99]
                          位2 = PHRT[12]⊕PHRT[63]⊕PHRB[5]
                          位3 = PHRT[17]⊕PHRT[68]⊕PHRB[10]
                          位4 = PHRT[22]⊕PHRT[73]⊕PHRB[15]
                          位5 = PHRT[27]⊕PHRT[78]⊕PHRB[20]
                          位6 = PHRT[33]⊕PHRT[83]⊕PHRB[25]
                          位7 = PHRT[38]⊕PHRT[88]⊕PC[9]
                          位8 = PHRT[53]⊕PHRT[58]⊕PHRB[0]
                          位9 = PC[6]
                          上述索引函数中,可以看出Firestorm第1表的索引利用了广泛分布于100位历史寄存器中的位(PHRT和PHRB的多对位异或),并结合了分支PC的第6位和第9位。这种复杂的散列方式保证索引空间的分布均匀,降低不同历史模式映射到同一索引的冲突概率。相较之下,英特尔处理器据报道索引函数中仅使用极少的PC位(如1位)并配合简单的折叠算法;Firestorm显然采用了更复杂的自定义哈希函数来充分利用长历史,提高预测表的辨识能力。各级PHT的索引函数在结构上大同小异,只是选取的具体历史位和PC位不同且对应各自的历史长度设置。例如,对于较短历史的表,会选取PHR寄存器中低位的若干bit进行异或,而不会涉及更长历史中的位。需要强调的是,由于Firestorm使用了组相联结构,每个索引对应多个候选表项,因此还需要通过比较部分标签(tag)字段来确认命中的是不是目标分支。FirestormPHT的tag字段同样来源于PC和历史寄存器,但采用与索引不同的位组合。一项研究发现,PC的低位比特(如5:2位)仅参与了tag的计算而不出现在索引函数中。这意味着Firestorm通过tag包含了一些索引未用的信息(例如分支地址最低几位),提高在同一索引组中区分不同分支的能力。每个PHT表项一般存储数位的tag以及2位饱和计数器。此外,为实现TAGE的“有用性”位(usefulness counter)机制,用于替换控制和减少干扰,一些实现可能在表项中增加1~2位的u位;虽然Firestorm具体u位数量未公开,但可以推测类似机制存在于硬件中,以支持按需分配和替换不常用的表项。综上,AppleFirestorm的TAGE结构通过高度定制的PHR组织和索引/tag函数,实现了对不同分支模式的精细预测支持,体现出追求极致性能所投入的复杂设计。
                          那么Oyron呢?Oyron完美的继承了上述Firestorm的所有结构,在所有细节上以及hash function上都完全一样,具体来说,两者均采用6个PHT,历史长度形成几何级数分布,但具体数值略异。Firestorm的最短历史表覆盖约6个分支的历史,而Oryon为4个;Firestorm次短表用11位历史,Oryon为7位。并且由于两款预测器结构几乎完全一致,其索引和tag计算都属于高度定制的哈希。在Firestorm中,研究揭示了第1表索引包含PC[6]和PC[9]位 ,而Oryon第1表使用PC[6]和PC[7]。可见在具体选择哪些PC位参与哈希上有所不同。这可能是因为两者微架构流水线宽度或取指策略不同:不同位的PC在哈希中的作用可能对fetch块对齐、双分支预测等有所影响。另外,Firestorm显式地把PC低位用于tag而避开索引,Oryon也类似。这些微妙差异不会从根本上改变预测器性能,却反映出设计者在防止索引冲突和确保tag唯一性。


                          IP属地:陕西13楼2026-02-16 15:14
                          收起回复
                            finally my master released new post


                            IP属地:江苏14楼2026-02-16 15:15
                            收起回复
                              2026-04-22 20:15:06
                              广告
                              不感兴趣
                              开通SVIP免广告
                              总体来说,TAGE预测器之所以被广泛采用,关键在于其优秀的预测准确性。Firestorm和Oryon的具体设计都围绕提高准确率展开。首先,多级历史表+部分标签结构大幅降低了分支冲突alias和模式干扰。长历史表捕获了跨越数十上百分支的关联,能够正确预测诸如循环展开、函数间依赖等长距离模式;短历史表则快速学习局部分支模式,避免长历史未训练成熟时造成过多误判。这种长短结合的几何历史长度设置被证明可以显著减少各类分支的平均误判率。其次,两款预测器都显式利用了执行路径信息:通过将分支的目标地址融入全局历史(PHRT),有效地区分了在程序不同路径上出现的相似分支模式。例如,两个不同循环中的分支即使跳转行为相似,只要它们的目标去向不同,PHRT所记录的路径轨迹就不同,从而在PHT查找时会对应不同的索引/tag,不至于互相干扰。这一点相对传统仅记录“taken/not-taken”序列的方案是重大改进,减少了路径别名导致的错误预测。再次,Firestorm增加部分表的相联度、扩大表项数量,也是在降低冲突未命中的概率。尤其是短历史表因为很多分支都会映射到这些表,如果容量不足或冲突多会导致最近分支模式反复被挤掉、预测不稳定。Firestorm用6路相联、12288项的最后两级表来缓解这一问题,确保热门的短周期分支有足够条目“驻留”学习,从而减少反复替换导致的初始错误。而Oryon虽然仅最后一级6路,但其相对缩短的历史长度可能让更多短周期分支提前落在倒数第二级(7位历史)表中学习,以4路相联8192项的配置也基本够用,避免了额外的复杂度,或者说这是一种减少复杂的讨巧行为。从准确性角度,Firestorm的更大容量和相联度理论上能覆盖更丰富的分支模式并减少冲突,尤其在密集分支场景会略胜一筹。而Oryon采用更精炼的配置,虽未见明显劣势,说明其参数选择可能已足以应对主要的分支模式?并没有,这是20年的设计,其规模和table配置或许在当时受限工艺密度以及系统负载的需求下是很好的选择,但现在已经2026年了,新的工艺密度,更高的负载对预测器的需求,这80KB的容量已经完全不能够胜任,哪怕去年CBP-2025也已经给出了192KB的容量需求,工业界对容量的需求也不止这点,高通Oyron-3都维持的容量或许是自身水平不足,毕竟,后续的TAGE大小要变,因为大小变化各种hash function也要对应变的,这里面也包括了加table。于此同时可能稍微减少了过度设计带来的浪费?好像也没有。至少dieshot上,BPU的area优势是N3E/P SRAM密度优势所带来的。两者都具备在当年相当高的预测准确率(指2020年,在25和26年,这个正确率早就落伍了,Apple新架构正确率依旧遥遥领先,Oyron还和ARM有来有回,公版架构作为自研照妖镜,能在如此田地也能看出Oyron的无能),虽然据报告作者评估,这些顶尖预测器的平均MPKI在SPEC基准上已经相当低,但差距更多体现在极端难预测的分支上。并且Oyron这种完全抄袭的行为应该令人所唾弃,没有一点思想,只会照搬的行为是不道德的。


                              IP属地:陕西15楼2026-02-16 15:15
                              回复