ARM打败X86?当我们在谈CPU性能时,我们在谈什么

引入

当我们在说Apple M1 Pro/Max比Intel 11代CPU强的时候,我们究竟在说什么? 我们在说Intel 12代CPU追上Zen 3的时候,我们在说什么?为什么同主频的CPU,Intel的x86 Atom比树莓派的BCM系列性能要好?

本文会揭示CPU的核心职责,以及其性能评估的关键指标。

CPU的核心职责

传统上,我们把CPU称作「中央处理器」,将「运算」和「控制」作为其核心职责。

但到了现在,承载「运算」职责的并不仅仅是CPU了,而是一整套体系。有适合并行计算的GPU,也有用于特定目的的DSP、ASIC。慢慢的,「控制」和「以控制为目的的计算」和「通用计算」成为了其核心价值。

因此,为起到控制目的,CPU需要具备以下特性:

  • 低延迟
  • 多且高速的IO

而为了实现通用计算目的,CPU需要具备以下特性:

  • 单核高纯计算速度
  • 单核尽量高的流水线满载率
    • 低指令空载率: 分支预测准确+超线程
    • 低数据空载率: 兼顾容量速度延迟的访存体系
  • 多核提高并行计算能力
  • 整体提高单位功耗下的计算能力

关键指标

以下列举以下上面特性所对应的关键指标。

高时钟频率

时钟频率是单位时间内,CPU时钟一秒振荡多少个周期。一般以1s内震荡多少个周期来算,如4GHz意味着一秒钟CPU时钟震荡4,000,000, 000次(40亿次)。时钟频率是衡量CPU单位时间内计算能力的基础。

需要注意的是,一个时钟周期并不一定与执行一条指令相对应,所以不同架构设计的CPU一般无法通过其时钟频率直接对比其纯计算能力。如同样是3.7GHz,代号Prescott的Pentium 4与代号Alder Lake的Core i5-12600K的单核在单位时间内执行的指令数完全无法直接比较。

那我们如何比较单核在单位时间内执行的指令数呢? 下一个参数可以解决我们的问题。

高IPC每周期指令数

IPC(Instruction Per Clock)表示每(时钟)周期运行多少个指令。单个核心每个时钟周期运行的指令数,乘以其时钟频率,就等于其单位时间内可以执行的指令数。

「单位时间内可以执行的指令数」引申出一个参数即MIPS,衡量CPU每秒能运行多少个百万指令。需要注意的是,MIPS高不意味着实际执行运算的时候单位时间实际执行的指令数就高。这是为什么呢?

一般而言,指令的执行是分步骤的,如「取指->译码->执行->访存->写回」,即一条指令的执行需要多个时钟周期。而且为了做更多的针对性优化,往往需要分更多的步骤,即为了提高性能需要将一调指令的执行经历更多的时钟周期。一条指令经历前后连续的步骤被执行,就像上了一条流水线,随着时钟周期的跳动向前走。

到这里,问题来了。由代码所生成的指令序列的执行并非纯线性的,而是存在分支的。所以存在这样一种情况。CPU分支处理的指令执行结束后,发现代码发生了跳转,流水线上前面步骤的处理工作全部都废掉了,不得不跳转到新的位置,重新执行。此时流水线上就出现了空档,效率就降低了。

那这个问题怎么解决呢? 下面的指标可以解决我们的问题。

低流水线指令空载率

低流水线指令空载率主要是靠「分支预测」和「超线程」两项技术来解决的。接下来分别进行叙述。

分支预测

我们目前面临的问题是,在分支跳转时,流水线存在空转的情况。但现实中存在二八定律,用在两个分支的情况下,就是两个分支虽然是对等的,但其中一个命中的概率是80%,另一个只有20%。所以我们可以基于分支跳转往往存在高概率的分支和低概率的分支的假设,使用分支预测器来命中高概率分支,降低分支跳转所引起的流水线空转,来提高单位时间上实际执行的指令数。

但是,分支预测器是有极限的,极限是什么呢? 就是二八定律并非100%适用,一个系统的性能底线往往决定于其在最差的情况的表现。如果实际情况是两个分支的概率是各50%,那么分支预测器除了白白耗电之外,将不会起到任何作用。那么如何解决分支预测器必然失败所引起的流水线空转呢?

超线程

此时,一个新东西产生了,即超线程技术。超线程技术本质是,针对一条流水线上的一个「执行->访存->写回」阶段步骤,配备两组「取指->译码」前置步骤。为什么要这么做? 因为计算的需求是大于计算能力供给的,且线程数是多于核数的,所以如果「执行」后发现分支预测器给错了分支,执行单元要空转了怎么办? 不要紧,还有另一组「取值->译码」给出的微指令可以执行,这样就填上了流水线空转的坑。所以最后我们来看,因为配备了超线程,最差情况变成了单个核心在原始线程和超线程上同步同时出现分支预测未命中时,流水线才会空转,这种概率是极低的。所以超线程技术不应当理解为一个「鸡肋的核心」,而是理解为一个「充分利用执行器以增加性能降低功耗」的手段。

这里需要引入一段历史。就是为什么执行单元现状是过剩的,在没有分支预测和超线程的时候容易空转。这里除了固有的不可预测性之外,还存在历史因素。在很长一段历史时期中,CPU的主频是显著高于内存系统的速度的。在这种条件下,SIMD(单指令多数据)就出现了。其本质是在访存系统速度和容量是瓶颈的前提下,以低的访存代价执行单条指令进行更多的计算,以达到更好的性能。SIMD本身就需要更多的执行单元。另外,为了实现在不依赖于软件增加对架构感知的条件下提高计算性能,从内存里进行「指令预取」和「数据预取」,并且通过「挖掘指令间的不相关性」进行更高效的「并行执行」,通过「在不影响单线程结果的前提下重排指令的读写」进行更快的「乱序执行」就都出现了。「并行执行」和「乱序执行」都需要更多的执行单元。所以在一段历史时期中,执行单元过剩是「SIMD」和「挖掘串行指令序列的并行性」路径下的必然产物。

但是,流水线指令填满了,计算就能顺利进行了么? 非也,我们往往发现,有些时候即使是用了SIMD这种多数据的指令,性能也没有任何提高,到头来发现,指令是填满了,但是要读取的数据迟迟拿不到,流水线还在空转。

这个问题怎么解决呢?

低数据空载率

低流水线指令空载率主要是靠「兼顾容量速度延迟的访存体系」来解决的。目前,其主要瓶颈在于「高速低延迟缓存的容量不足」和「内存速度不够」。接下来分别进行叙述。

大缓存容量

为了解决高速CPU与低速内存的速度不匹配问题,高速缓存出现了。高速缓存具有速度高、延迟低的特点。目前,随着代码容量与需要反复计算的局部性数据的不断膨胀,数据在缓存未命中的情况下通过内存读写导致流水线却数据空转,成为了一个显著的性能瓶颈点。因此,我们需要更大的缓存,以解决缓存未命中问题。但大缓存意味着更多的晶体管,更大的发热量和更低的良品率,在CPU制程不够先进的情况下,是不可能做到很大的。例如可以观察到Intel在14nm的时候,消费级CPU的缓存大部分都是个位数,直到最近Intel 7(10nm Enhanced SuperFin)工艺,12代的i9-12900K的缓存才到了30MB。与之相对应的,使用了台积电7nm(TSMC 7nm FinFET)的AMD 5950x就敢上64M三级缓存,这就是制程差异带来的区别。

所以我们如果想期待更大的缓存容量,必须在制程显著提高的条件下才能做到。

但是,大缓存能解决一切问题么?并不是的。面对高速流计算,即大量的新鲜数据流入计算流出,大缓存并不能解决问题,我们可以显著的观察到CPU在等待内存的数据读写。这应该如何解决呢?

高访存速度

因为瓶颈发生在了「内存速度」上,我们必须提高内存的速度才能让CPU不花过多的时间等待数据。从SDR一路走到DDR4,我们看到内存的读写速度一直在提升。但是到了DDR5这里,问题来了。目前在不提升或少量提升内存核心频率的前提下,是不可能实现「高吞吐带宽」与「低访问延迟」的兼得的。但提升内存核心频率,意味着制程提高,意味着成本增大。而先进制程的产能是十分有限且价格昂贵的,所以内存不得不选择了「提高一定的访问延迟,换取更高的带宽」的做法。这个做法,同样需要大缓存的支持以降低缓存未命中带来的CPU流水线数据未命中概率,最终降低性能损失。因为虽然带宽高了意味着一切正常时单位时间内可以处理更多的数据,但增大访问延迟,即意味着缓存未命中访存需要等待的时间增长了,未命中带来的性能损失更大。

到这里,尽量利用好单核的计算能力就到头了。

上文提到了,制程是我们目前的极限,在制程难以降低的条件下,我们很难再通过提高时钟频率的方式来提升性能。那我们怎么解决这个问题呢?

多核提高并行计算能力

答案就是引入多核。我们可以知道,真正需要前后依赖的线性计算的场景是有的,但始终是少的。像是目前的游戏引擎这样单线程为核心的设计,以后必然不是主流。我们可以观察到,充分发掘计算任务之间的独立性,将其拆解成多个并行执行的任务,使用多核来分别计算,才是可行的办法。目前我们已经看到消费级的CPU在AMD的努力下,已经进化到了64核128线程。目前在核数上,应当讲硬件是远远走在软件前面的。后面需要很长的时间,由软件入手,更好的利用好多核,才能获得更好的实际体验。

做到这些就足够了么?不是的。我们目前看到,Intel的12代CPU的顶级型号i9-12900K最大功耗可到241W,这个功耗远远高于我们目前移动计算的需求。如果你的笔记本里装这么个东西,一来散热器可能比机器还沉还大,二来电池估计十分钟就耗尽了。即使在桌面或数据中心,现在的CPU的产热能力,其实也接近了一个合理成本散热方案的极限。所以这个问题如何解决呢?

整体提高单位功耗下的计算能力

最近Intel发布了12代CPU,使用了新的Intel 7工艺,同时采用了新的架构设计。引入了「性能核/能效核」的设计。根据极客湾的评测,其能效核在同频率下,与苹果M1不相上下。

如何才能提高能耗比?要点是将能耗比当作主要因素去重新设计核心,代替掉之前以高单核性能为主要考虑因素的设计。我们可以从Intel的能效核的新思路看出来。12代4个能效核组成一个簇,其面积与1个性能核相当,但其单核性能相当于9代i7,可见其能耗相当之高。可以预见,如果Intel 12代移动端发售,将引起笔记本能耗的一次大幅降低,续航届时将得到显著改善。

IO数量、带宽与速度

说到底,在控制上,CPU必须具备足够的IO数量、带宽和速度。在这一点上,对于PCIE 5.0的支持和更多的通道,决定了机器的IO能力。

总结

看到这里,对于CPU性能到底是什么相信你已经有了一个比较全面的认知了。

并不是ARM打败了X86,而是ARM与生俱来的「高能耗比」更好的契合了当下CPU发展的瓶颈,而X86在Intel痛定思痛重新设计能效核的行动下,也再次表现出了全新的生命力。ARM长期低能的帽子,也由苹果M1系列CPU一举打破。

说到底,ARM和X86只是两个指令集,其根本性差异在其产生的时代分别代表了在内存低速度与CPU高速度为主要矛盾的时代背景下,低功耗与高性能两个场景通过不同指令集的选取来更好的满足自己的需求。时间回到现在,在电池技术与散热技术短期内不可能有突破的前提下,能耗比成为新的主要矛盾。在此背景下,ARM和X86沿着各自的路线发展到今天,殊途同归,重新站到了一起。

如今的指令集差异,更多意义是通过固化的二进制代码,产生所谓「基于指令集的生态」,形成壁垒来产生利润,而不再是技术先进与否、生产力高低之别的指标了。如果你问我谁最终会胜出,我的答案是谁与客户合理分配存量以维持发展,谁能持续活下来;谁通过榨取客户更多存量来盈利,谁最后一定死;谁帮助客户产生更多增量来盈利,谁最后会胜出。胜出者甚至可能不是ARM或X86,或许是RISCV,或许还未出现。

这是一个全新的历史时期,我们都是见证者,也是参与者。

发表评论

为防机器,验证码请直接输入4个数字1

*