Cache(高速缓存)的发展是计算历史上最重要的事件之一。几乎所有的现代CPU内核,从ARM Cortex-A5这样的超低功耗芯片到最高端的Intel Core i9都使用cache。即使是更高端的微控制器也经常有小型cache,或作为选项提供,即使是在超低功耗设计中,其性能优势也实在是不容忽视。

 

缓存的发明是为了解决一个重要问题。在计算机发展的早期几十年里,主存非常慢,而且非常昂贵,但CPU也不是特别快。从20世纪80年代开始,这一差距开始迅速扩大。微处理器的时钟速度突飞猛进,但内存访问时间却没有明显改善。随着这一差距的扩大,越来越明显的是,需要一种新型的快速存储来弥补这一差距。

 

 

虽然只到2000年,但20世纪80年代开始差异越来越大,导致了第一批CPU cache开发出来。

 

 

Cache的工作原理

CPU cache是小型内存池,用于存储CPU下一步最可能需要的信息。哪些信息加载到cache取决于复杂的算法和对编程代码的某些假设。Cache系统的目标是确保CPU在寻找下一位数据时,已经将其加载到cache(也称为‘cache hit’)。

 

另一方面,cache miss意味着CPU不得不去别处寻找数据。这就是L2 cache发挥作用的地方,虽然它比较慢,但却更大。有些处理器使用inclusive cache设计(意味着存储在L1 cache中的数据也会复制到L2 cache中),而其他处理器则是exclusive的(意味着这两个cache从不共享数据)。如果在L2 cache中找不到数据,CPU就会继续往下找L3(通常仍在芯片上),然后是L4(如果存在)和主内存(DRAM)。

 

 

 

这张图显示了一个hit rate恒定的L1 cache与一个更大的L2 cache之间的关系。请注意,总hit rate随着L2大小的增加而急剧上升。一个更大、更慢、更便宜的L2可以提供大型L1的所有优势,但没有芯片尺寸和功耗的影响。大多数现代L1 cache的hit rate都远远高于这里显示的理论上的50%,Intel和AMD的cache hit rate通常都在95%或更高。

 

下一个重要的点是set-associativity。每个CPU都包含一种特定类型的RAM,称为tag RAM。Tag RAM是所有可以映射到任何给定cache块的内存位置的记录。如果一个cache是完全关联的,这意味着任何RAM数据块都可以存储在任何一块cache中。这种系统的优点是hit rate高,但搜索时间非常长,CPU必须在搜索主存之前查看整个cache以确定数据是否存在。

 

当然,还有直接映射的cache。直接映射的cache是指每个cache块可以包含一个且只有一个主存块。这种类型的cache可以被快速搜索,但是由于它是1:1映射到内存位置,因此hit rate很低。介于这两个极端之间的是n-way associative cache。2-way associative cache(Piledriver的L1是2-way)意味着每个主内存块可以映射到两个cache块中的一个。8-way意味着每个主内存块可以映射到8个cache块中的一个。Ryzen的L1指令cache是4-way associative,而L1数据cache是8-way set associative。

 

接下来的两图片显示了hit rate是如何随着set-associativity而提高的。请记住,像hit rate这样的东西是非常特殊的,不同的应用会有不同的hit rate。

 

 


为什么CPU的cache越来越大?那么,为什么首先要不断增加更大的cache呢?因为每个额外的内存池都会推迟访问主内存的需求,并且在特定情况下可以提高性能。

 

 


这张来自Anandtech的Haswell评论的图表很有用,因为它说明了增加一个巨大的(128MB)L4 cache以及传统的L1/L2/L3结构对性能的影响。每个阶梯代表一个新的cache级别。红线是带有L4的芯片。请注意,对于大文件,它的速度仍然几乎是其他两个Intel芯片的两倍。

 

那么,将大量的片上资源用于cache似乎是合乎逻辑的。但事实证明,这样做的边际收益是递减的。较大的cache既慢又贵。在每一位SRAM(6T)有六个晶体管,cache也很昂贵(就芯片尺寸而言,也就代表着成本)。过了某一点,把芯片的功率预算和晶体管数量花在更多的执行单元、更好的分支预测或额外的内核上会更有意义。下图是Pentium M(Centrino/Dothan)芯片,整个芯片的左侧被用于一个巨大的L2 Cache。在过去单线程CPU的时代就是这样,现在我们有了多核芯片和GPU,在很多情况下,整个CPU中用于cache的比例较小。

 

 

 

 

Cache设计如何影响性能

 

增加CPU cache对性能的影响与其效率或hit rate直接相关;反复的cache miss会对CPU性能产生灾难性的影响。下面的例子虽然被大大简化了,但应该可以说明这个问题。

 

想象一下,CPU必须连续100次从L1 cache加载数据。L1 cache的访问延迟为1ns,hit rate为100%。因此,CPU需要100ns的时间来执行这个操作。

 

现在,假设cache有99%的hit rate,但CPU第100次访问实际需要的数据却在L2中,有10-cycle(10ns)的访问延迟。这意味着CPU需要花99ns的时间来执行前99次读取,10ns的时间来执行第100次。Hit rate降低1%,却让CPU的速度降低了10%。

 

在现实世界中,L1 cache的hit rate通常在95%到97%之间,但在我们的简单例子中,这两个值对性能的影响不是2%,而是14%。请记住,我们假设丢失的数据总是在L2 cache中。如果数据已经从cache中被驱逐位于主内存中,访问延迟为80-120ns,那么95%和97%的hit rate之间的性能差异可能会使执行代码所需的总时间翻倍。

 

 

这张die shot,芯片中间的重复结构是20MB的共享L3 cache。

 

早在人们对AMD的Bulldozer系列与Intel的处理器进行比较时,cache设计和性能影响的话题就出现了很多。目前还不清楚Bulldozer低迷的性能有多少可以归咎于其cache子系统,除了有相对较高的延迟外,Bulldozer系列还受到大量cache争用的影响。如下图所示,每个Bulldozer/Piledriver/Streamroller模块共享其L1指令cache。

 

 

当两个不同的线程在同一内存空间中写入和覆盖数据时,cache会发生争用现象。这损害了两个线程的性能,每个核都被迫花时间把自己的首选数据写进L1,而另一个核却迅速覆盖了这些信息。即使AMD将L1代码cache增加到96KB,并使其成为3-way associative,AMD的旧版Steamroller仍然被这个问题所困扰。后来的Ryzen CPU没有以这种方式共享cache,这个问题也就没再发生。

 

 

这张图显示了Opteron 6276(原Bulldozer处理器)的hit rate在两个核都处于活动状态时是如何下降的,至少在一些测试中是这样。然而,很明显,cache的争用并不是唯一的问题,即使在两个处理器的hit rate相同的情况下,6276在历史上也很难超过6174的表现。

 

今天,Zen 2没有这类弱点,Zen和Zen 2的整体cache和内存性能比老的Piledriver架构好很多。

 

 

AMD最初的Ryzen首秀。Ryzen使用的cache系统与以前的AMD CPU非常不同。

 

现代CPU通常也有一个非常小的L0 cache,通常只有几KB大小,用于存储微操作。AMD和Intel都使用这种cache;Zen有一个2,048μOP的cache,而Zen 2有一个4,096μOP的cache。这些微小的cache pool的运作原理与L1和L2相同,但代表一个更小的内存池,CPU可以以比L1更低的延迟访问。通常情况下,公司会对这些能力进行相互调整。Zen 1和Zen+(Ryzen 1xxx、2xxx、3xxx APU)有一个64KB的L1指令cache,是4-way set associative的,还有一个2,048μOP L0 cache。Zen 2(Ryzen 3xxx desktop CPU,Ryzen Mobile 4xxx)有一个32KB的L1指令cache,是8-way set associative的,有一个4,096µOP的cache。将set associativity和µOP cache的大小增加一倍,使AMD能够将L1 cache的大小减少一半。这类权衡在CPU设计中很常见。

 

未来的创新

最近,IBM推出了Telum微处理器,cache结构很有趣且不寻常。Telum有一般的L1和L2,但CPU没有物理L3,而是部署了一个虚拟L3。下一代CPU不是完全驱逐CPU认为不再需要的L2数据,而是将其驱逐到同一硅片上不同CPU的L2 cache中,并将其标记为L3数据。每个核都有自己的32MB L2,整个芯片的虚拟L3是256MB。IBM甚至可以在多芯片系统中共享这种能力,创建一个虚拟的L4,总共有8192MB的数据存储。

 

 

这种类型的虚拟cache系统是独一无二的,它在x86方面没有可对应,它是一个有趣的例子,说明是如何推动cache设计的极限。虽然AMD的V-Cache提供额外的L3,而不是L2,但我们完全没有必要提及它。AMD 最近的成就以及有望在未来 Zen CPU 上出现的功能是大型 L3 cache,垂直安装在现有小芯片顶部,并通过芯片内硅通孔连接到它们。Cache在这一点上可能已经有40年的历史了,但是制造商和设计师仍然在寻找方法来改进并扩大其实用性的方法。

 

缓存的发展

 

随着研究人员不断去寻找从较小的cache中挤出更高性能的方法,cache的结构和设计仍在进行微调。到目前为止,Intel和AMD还没有大力推动更大的cache,也没有把设计一直扩展到L4。有一些Intel的CPU带有板载EDRAM,相当于一个L4 cache,但这种方法并不常见。这就是为什么我们在上面使用Haswell的例子,尽管该CPU比较老。据推测,对于大多数使用情况来说,大型L4 cache的优势性价比并不高。

 

不管怎么说,cache设计、功耗和性能对未来处理器的性能至关重要,任何一家公司如果可以在当前设计的基础上取得实质性改进都会获得非常大的优势。

 

 

[参考文章]

How L1 and L2 Caches Work, and Why They're an Essential Part of Modern Chips — Joel Hruska