文/图黄博文
ARMPPT中的性能与功耗对比TIPS什么是乱序多发射?
所谓“多发射”(multiple-issue)指的是处理器在一个时钟周期内能够同时执行大于等于两条指令,“乱序”是乱序执行的简称,指的是处理器能够动态地调度指令,把程序规定必须后置执行、但是实际上并不存在执行冲突的指令提前执行。这两个结构设计技术需要对整个执行流程进行非常复杂精细的控制和调度,因此乱序多发射被视为是现代高性能处理器微结构的基石。第一代的乱序多发射设计起源于上世纪60年代的超级计算机CDC6600和IBM360/91的中央处理单元。
发射宽度不是一切
作为编号上大于Cortex-72且同属于Cortex-A7X系列的产品,为什么A73选择了双发射设计?这里面的原因也颇有意思,首先,Cortex-A73和Cortex-A72虽然编号差距只有1,却来自两个不同的设计团队。Cortex-A系列的高性能处理器核心由两个团队设计,Cortex-A15,Cortex-A57,Cortex-A72这些追求最高性能的IP都来自于ARM的美国德克萨斯州奥斯丁团队(Intel、NVIDIA、IBM等公司也在德州奥斯丁有类似的CPU设计团队),而Cortex-A12,Cortex-A17,Cortex-A73来自于ARM在欧洲的设计团队;其次,从产品路线上看,ARM的欧洲设计团队追求的目标与美国德州奥斯丁团队有明显不同,欧洲团队追求的不再是极致性能,而是性能与功耗、面积的一个良好平衡。
在ARM的PPT上我们可以看到,Cortex-A73的功耗性能比进一步下探(意味着性能功耗比的提高),而IPC基本与Cortex-A72持平,通过实现更高的主频来达到超越Cortex-A73的性能。ARM的官方数据是,将10nm工艺下的Cortex-A73与16nm下的Cortex-A72对比,Cortex-A73的频率最高可达2.8GHz,性能提高30%,能耗效率提升30%。
可能有人会发出疑问,这可能做到吗?难道双发射不是先天劣于三发射或者四发射吗?
虽然双发射在发射宽度上确实先天劣于三发射或四发射,实则最终性能并不尽然。发射宽度只是微结构上众多重要设计指标中的一个,其他重要设计指标还有很多,例如:
1、分支预测的速度。一般要求极少的周期数就要做出分支指令是否跳转的判断,分支预测判断速度越慢,可能引入的取指令流水线空泡就越多。
2、分支预测准确率。预测准确率直接关系到取上来的指令是否正确,若不正确则需要冲刷流水线,既浪费了功耗也拉低了性能。
3、指令缓存访问命中率和吞吐量。即便分支预测器快速而准确地指明了指令读取地址,但是指令缓存如果不能快速供应待取指令,也会拉低性能。
4、寄存器堆的读写口数目和共享仲裁。提供多端口并行读写能力的寄存器堆是乱序宽发射引擎的核心部件之一。但是多端口的寄存器堆占用面积也较大,在实际设计中经常使用读写端口共享的方式来削减所需要的读写口数目,这样一来读写口的使用权利仲裁也成为不可忽视的性能设计要素。
5、发射队列(保留站)的设计。发射队列同样是乱序多发射引擎中的核心部件,它的设计有很多可供量化的性能指标,例如项数(深度),框架(多个集中式发射队列或共享式发射队列),亦有难以量化的指标,例如发射队列和其他部件之间的数据前递(Bypass)网络等。
6、访存重排序和地址分析能力。从性能上来说,访存(包括cache和memory组成的访存子系统)是非常重要的一个问题,现在的设计一般会将访存指令也进行乱序执行,但按照内存模型的规定,乱序的访存必须进行地址的反别名分析(MemoryDisambiguation)来确保执行结果正确。激进的反别名预测可以通过少量可纠正的内存模型违规错误来换取可观的性能提升。
由此可见,发射宽度这个指标只粗略衡量了核心性能的一部分,因此在市场上我们不难看到同样的发射宽度而性能差距却被拉开的例子,例如本文中介绍的乱序双发射Cortex-A73和乱序双发射Cortex-A9。同样地,也有发射宽度更低却能在IPC上基本打平更高发射宽度的例子,例如乱序双发射Cortex-A17与乱序三发射Cortex-A15,以及Cortex-A73和Cortex-A72。
那么这到底是怎么做的呢?我们来对比分析一下Cortex-A73与Cortex-A72的核心流水线。
ARM展示的官方对比数据
Cortex-A72核心流水线核心流水线变化
让我们先来看看Cortex-A72的核心流水线部分。Cortex-A72是一个乱序三发射设计,每周期取指令宽度为128比特(意味着4条ARMv8-A指令),每周期解码宽度为3条指令。ARMv8指令经过解码以后会打散成粒度更小的微指令(micro-ops或μops),每个周期会把5个微指令分派(Dispatch)给7个发射队列(IsQ),这意味着Cortex-A72是独立发射队列的设计,其中两个简单整数操作执行单元前分别配置了一个可保存8条微指令的发射队列。一个复杂整数操作执行单元前也配置了一个可保存8条微指令的发射队列,两条SIMD/浮点操作单元前也分别配置了一个可保存8条微指令的发射队列,专门处理分支指令的分支执行单元前配置了一个可保存10条微指令的发射队列,两个地址生成单元(AGU)分别负责装载(load)和写入(store)地址的生成,共享一个可保存16条微指令的发射队列。以简单整数操作的流水线长度为度量,约为15级流水。
Cortex-A73对比Cortex-A72做了不少精简。首先,取指令所需的周期数从5个周期提高到了4个周期,解码宽度从3条指令降低到了2条指令,但是所需的周期数也从3个周期降低到了1个周期,分派宽度调整为4+2=6个微指令,其中一般整数指令享用4条微指令的分派宽度(Cortex-A73核心流水线图的中间上半部分)。而SIMD指令和浮点指令在经过额外的解码周期后,会走一条独立的2条微指令宽度的分派通道(Cortex-A73核心流水线图的中间下半部分),呈递给由两个SIMD/浮点操作单元共享的一个发射队列。分派逻辑每个周期最多可以往任意一个发射队列分派两条微指令。整数执行单元集群也有所调整,主要表现为:
1、执行单元的通用化。例如Cortex-A72中简单整数执行单元与复杂整数执行单元是独立的,但Cortex-A73中是整合的,Cortex-A73中的两个整数执行单元既能执行简单整数操作也能执行复杂整数操作,其中一个可以执行整数乘法,另一个可以执行整数除法。此外,Cortex-A73的地址生成单元也不再区分装载和写入,两个地址生成单元都能够执行装载和写入。
2、发射队列的共享化。Cortex-A73的发射队列多为两个执行单元共享,例如两个整数执行单元共享一个发射队列,两个地址生成单元共享一个发射队列,两个SIMD/浮点执行单元共享一个发射队列。对比Cortex-A72来看,Cortex-A72更加独立的发射队列设计有利于提高容量利用率,但如果发射队列容量不够的话也容易导致性能减退。
以“Cortex-A73核心流水线”图中执行周期最短的分支指令计算,Cortex-A73的核心流水线深度也缩减为11~12级。另一个值得注意的趋势是,ARM的默认一级指令缓存大小一直在提高,Cortex-A15的默认一级指令缓存大小为32KB,Cortex-A57和Cortex-A72都改为48KB,Cortex-A73则改为64KB,并且使用了4路组关联,64字节的Cache字块粒度。
在先前的设计中,即便指令读取前端正确预测了指令流走向并且指令缓存也以最大吞吐量提供了数据(意味着每一个bank/subbank都没有停顿),在指令分解成微指令时仍有流水空泡产生。ARM声称在Cortex-A73核心中引入了提前检测这种气泡是否产生的能力,并在出现这种情况时提前解码微指令避免产生气泡。这一设计的特征与Intel的uopscache比较吻合,笔者据此猜测这里可能引入了类似于uopscache的设计。
在分支预测上,Cortex-A73使用了更加先进的分支预测器,分支目标地址缓存(BTAC)更大,这一结构通常被用来加快分支预测的判断速度。一般来说,分支预测器使用的各种表结构做得越大,可以保存的分支历史信息越多,分支指令的预测干扰就越少,因此分支预测准确率就越高,IPC就越高。但是当表项结构做得太大时,访问记录表所需的时间也会拉长,由此延长了分支预测的决断时间,因此对性能是有害的。在一定程度内提高记录表大小,但同时控制住分支历史记录表的访问周期数不至于延长时,IPC会得益于分支预测准确率而提高,但是如果分支历史记录表的访问周期数被延长,IPC就会有跳水式的下跌。
Cortex-A73核心流水线
180nm和100nm工艺下,分支历史记录表的大小与IPC的关系为了同时提高分支预测所需记录表的大小,同时又缩短访问延迟、从而控制分支预测所需时间,一般处理器微结构中会使用如同多级高速缓存一样的多级记录表。通常第一级记录表容量较小但速度很快,保存最常用的记录,而后级记录表就做得比较大,保存尽可能多的记录。Cortex-A73也使用了一样的设计思路,其分支目标地址缓冲区使用了多级设计,第一级仅能保存64条分支目标地址记录,值得一提的是ARM在Cortex-A72中也使用了”micro-BTB”的描述,这暗示着Cortex-A72的BTB也使用了多级结构。对比Cortex-A17,Cortex-A73中也引入了新增的间接分支预测器,据称为2路组关联*256项的组成结构,但缺失其他相关信息的情况下,暂不清楚这个间接分支预测器与Cortex-A72中的设计有何不同。
在寄存器重命名的方法上,ARM声称进行了“乱序执行方法的哲学性改变”,这指的是使用了基于物理寄存器堆的寄存器重命名方法。这一改变对于ARM来说确实是一个可以值得夸耀的进步,但是AMD早已经于第一代推土机(Bulldozer)架构、Intel已经于2010年的SandyBridge架构转向了物理寄存器堆的设计。所以这一设计对于业界来说已经不能算是前沿,更多的是ARM作为高性能先进微结构设计的后来者补上了又一个空缺。先前Intel一直使用着基于数据复制的寄存器重命名方法,这一做法的好处是成熟而实现简单,其历史可以追溯到上世纪60年代的超级计算机IBMSystem360/91上。但其坏处也显而易见,就是数据搬移的功耗。在64位指令集中一个普通数据的复制就意味着64位的复制,当Intel在SandyBridge上引入AVX这种SIMD指令集时,这一缺憾就再也不能忍了,而物理寄存器堆的好处是,整个乱序执行引擎中只要对每个数据保留一个副本即可,而且移动数据时只需要移动物理寄存器堆的指针,这样就大大减少了移动数据的功耗开销。
综上,经过精简加强的Cortex-A73核心能够在相同工艺的前提下实现25%的核心面积缩减,达到与Cortex-A53类似的核心面积水平。
TIPS分支指令的预测干扰(Interference)
所有的分支预测器都依赖于保存分支指令的历史记录进行预测。例如,当某个分支指令发生跳转/不跳转时,分支历史记录表中就会记录这一信息,如果发生连续的跳转/不跳转,就可以认为这一分支具有明显的偏向性,分支预测器就会据此做出预测。但是程序执行周期中会碰到的动态分支指令数是一个天文数字,而底层受限于物理限制,分支历史记录表不可能做到无限大,于是就会出现许多分支指令共享分支历史记录表中的一个表项的情况,这个情况下就会出现相互干扰,导致预测失准。经典的一个反干扰技巧是在索引分支历史记录表时使用哈希(hash)函数将分支记录尽量散开到表中的不同位置,这一技巧最早发表于上世纪90年代,目前已经应用于各大主流处理器微结构当中。
访存子系统
访存子系统的改变从load/sotrebuffer就开始了。ARM声称Cortex-A73的load/storebuffer可以动态地检测指令发射模式,并且在发生一些特定事件时动态改变指令发射策略。例如检测到流访存(stream)模式时,store操作就会以最快的速率发射出去,这一做法可能是为了方便执行后端在一级缓存层面,或者是更下层的二级缓存、一致性单元部分做写合并来缩减带宽需求。
在TLB上,ARM为Cortex-A73的主TLB加上了面对流访存的预取器,这样一来在流访存跨越页边界时,主TLB早已准备好了新的TLB表项,保证TLB在这种场景下不发生缺失。Cortex-A73的TLB现在支持2个同时处理的TableWalk。并且提供了非阻塞式访问的能力,在进行TableWalk时TLB还能够继续接受其他请求并能够输出TLB命中。
在一级缓存上,ARM终于从物理索引+物理标记(PIPT)的设计改成了虚拟索引+物理标记(VIPT)。在介绍TLB时我们曾提到,理论上每一次访问高速缓存都需要进行虚拟地址到物理地址的转换,比较慢但是同时也比较稳妥的做法是,等待虚拟地址翻译到物理地址的过程完成后再访问高速缓存,这样一来就拉长了高速缓存的访问路径,提高了命中延迟,对性能有害。能不能使用虚拟地址直接访问高速缓存呢?答案是可以,这种设计被称为虚拟索引+虚拟标记,但使用这种设计需要非常小心,因为虚拟地址是可以重复的,这会带来内存地址别名问题导致程序甚至整个系统崩溃。同时兼顾物理索引+物理标记的稳妥,和虚拟索引+虚拟标记的性能,就是虚拟索引+物理标记(VIPT)。这种设计利用了页面偏移和页号编码与高速缓存地址索引有部分重叠的特性,在高速缓存内部使用物理地址作为对比标记(Tag),但访问高速缓存时使用虚拟地址索引躲开TLB的延迟,在高速缓存的标记阵列访问完毕,输出了一整组高速缓存的地址标记后,TLB的虚实地址转换也并行地完成了,就能够在不产生内存地址别名的情况下快速判断高速缓存是否命中。
Cortex-A73的一级和二级缓存都配备了独立的预取器,并且比ARM先前的设计支持更大的预取步长。ARM声称这一预取器可以帮助Cortex-A73在流式访存下获取接近理论最大值的带宽。Cortex-A73的二级缓存最大可配置为8MB大小,为Cortex-A72的两倍,同时Cortex-A73的二级缓存为包含式设计,这种设计能够简化多核心处理器下的缓存一致性处理,但是也会带来缓存数据副本的问题,亦即二级缓存始终包含上层一级缓存的数据,使得缓存空间被浪费,如果是严格包含式设计的话,还会出现多核心互相干扰的问题,例如核心1占用了一块二级缓存,导致二级缓存把核心2保存在此处的数据替换掉时,由于严格包含式设计的规定,二级缓存必须通知核心2把一级缓存中的数据也丢弃掉,这就会造成性能损失。
结论分析
虽然Cortex-A73从3发射降级到2发射,但是通过加强其他方面,ARM声称它的SPEC性能将与Cortex-A72近似,同时在BBench上同频性能提高近10%,使用FFMPEG编码器测试的NEONSIMD性能提高5%(Cortex-A73的下一代会提高更多),使用64位模式的JMC流复制测试的访存性能提高15%,而功耗下降20%。
值得一提的是,在Cortex-A35中首次引入的硬件功耗状态管理也在Cortex-A73上出现了。此前的设计方案使用粗粒度的软件管理,但绝大部分厂商并不买账,如果ARM这一次推行Cortex-A73的硬件功耗状态管理能够成功形成影响力的话,其动态功耗还能够进一步下降。
ARM声称使用Cortex-A73作为主核心的SoC在今年年末前就能见诸市场,这个核心如果真的能够做到ARMPPT上发布的数字的话,将会给其他通过指令集授权来开发自研核心的厂商如高通的猫鼬Kyro和三星的金环蛇Mongoose带来更大压力。缩减了发射宽度的Cortex-A73能否从Cortex-A72手中扛过大旗,让我们拭目以待。
TIPSTLB是什么?
现代的计算机系统通常使用虚拟内存。虚拟内存和物理内存地址的转换就是通过页表进行,而页表一般放在内存中由操作系统维护。理论上每一次访问高速缓存都需要页表的介入进行地址翻译,如果每一次访问都去内存里面取用页表就太慢了,于是TLB应运而生,TLB实际上是页表翻译在处理器内部的缓存,处理器无需访问内存就能够知道一些常用虚拟地址对应的物理地址,大大加快了翻译速度。
同工艺同频率的Cortex-A73与Cortex-A72性能对比