解说员:L1与L2与L3缓存

2020-09-12 02:49:59

任何计算机中的每一个CPU,从廉价的笔记本电脑到百万美元的服务器,都会有一种叫做高速缓存的东西。更有可能的是,它也会拥有几个层次的信息。

它一定很重要,否则它为什么会在那里?但是缓存是做什么的,为什么需要不同级别的东西呢?12路集合联想到底是什么意思呢?

TL;DR:它的内存很小,但速度非常快,正好位于CPU的逻辑单元旁边。当然,我们还可以了解到更多关于缓存的知识。

让我们从一个想象中的、神奇的存储系统开始吧:它速度无限快,可以同时处理无限数量的数据事务,并且始终保持数据的安全。这并不是说任何东西都不存在,但如果它存在,处理器设计就会简单得多。

CPU将只需要具有用于加法、乘法等的逻辑单元和处理数据传输的系统。这是因为我们的理论存储系统可以立即发送和接收所需的所有数字;任何逻辑单元都不会等待数据事务。

但是,我们都知道,没有任何神奇的存储技术。取而代之的是,我们有硬盘或固态硬盘,即使是最好的硬盘,也不能远程处理典型CPU所需的所有数据传输。

原因是现代的CPU速度快得令人难以置信--它们只需要一个时钟周期就能将两个64位整数值相加,而对于运行在4千兆赫的中央处理器来说,这只需要0.00000000025秒或四分之一纳秒。

与此同时,旋转的硬盘驱动器仅在里面的磁盘上找到数据就需要数千纳秒,更不用说传输它了,而固态驱动器仍然需要数十或数百纳秒。

这样的驱动器显然不能内置到处理器中,所以这意味着两者之间将会有物理上的分离。这只会增加数据移动的时间,使情况变得更糟。

所以我们需要的是另一个数据存储系统,它位于处理器和主存储器之间。它需要比驱动器更快,能够同时处理大量数据传输,并且离处理器更近。

嗯,我们已经有这样一种东西了,它叫做RAM,每个计算机系统都有一些用于这个目的。

几乎所有这类存储器都是DRAM(动态随机存取存储器),它能够以比任何驱动器都快得多的速度传递数据。

美光是为数不多的DRAM制造商之一,它制造的一些最大的DDR4存储芯片可以容纳32G位或4 GB的数据;最大的硬盘可以容纳4000倍以上的数据。

因此,尽管我们已经提高了数据网络的速度,但仍需要额外的系统--硬件和软件--来计算出哪些数据应该保存在有限的DRAM中,为CPU做好准备。

至少可以在芯片封装中制造DRAM(称为嵌入式DRAM)。不过,CPU相当小,所以你不能往里面塞那么多。

Xbox360图形处理器左侧有10MB的DRAM。资料来源:中央处理器墓地

绝大多数DRAM都位于处理器旁边,插在主板上,它始终是计算机系统中距离CPU最近的组件。然而,它仍然不够快……。

DRAM仍然需要大约100纳秒才能找到数据,但至少它每秒可以传输数十亿比特。看起来我们需要另一个阶段的内存,才能进入处理器的单元和DRAM之间。

进入左侧阶段:SRAM(静态随机存取存储器)。DRAM使用微型电容以电荷的形式存储数据,而SRAM使用晶体管做同样的事情,这些晶体管的工作速度几乎与处理器中的逻辑单元一样快(大约比DRAM快10倍)。

基于晶体管的存储器比DRAM占用的空间大得多:对于同样大小的4 GB DDR4芯片,SRAM的价值不到100MB。但由于它是通过与创建CPU相同的过程制造的,所以SRAM可以直接构建在处理器内部,尽可能靠近逻辑单元。

基于晶体管的存储器比DRAM占用的空间大得多:对于同样大小的4 GB DDR4芯片,SRAM的价值不到100MB。

随着每个额外的阶段,我们已经提高了移动数据的速度,增加了我们可以存储的成本。我们可以继续添加更多的部分,每个部分都更快但更小。

因此,我们对什么是缓存得出了一个更技术性的定义:它是多个SRAM块,全部位于处理器内部;它们用于通过以超快的速度发送和存储数据,确保逻辑单元尽可能地保持忙碌。满意了吗?很好--因为从现在开始事情会变得复杂得多!

正如我们所讨论的,之所以需要高速缓存,是因为没有一个神奇的存储系统可以跟上处理器中逻辑单元的数据需求。现代CPU和图形处理器包含许多SRAM块,这些块在内部组织成层次结构--按如下顺序排列的高速缓存序列:

在上图中,CPU由黑色虚线矩形表示。ALU(算术逻辑单元)位于最左边;这些结构为处理器供电,处理芯片执行的数学运算。虽然从技术上讲它不是高速缓存,但距离ALU最近的内存级是寄存器(它们被组合在一起组成一个寄存器堆)。

它们中的每一个都包含单个数字,例如64位整数;值本身可能是关于某项内容的一段数据、特定指令的代码或其他一些数据的内存地址。

桌面CPU中的寄存器堆非常小--例如,在英特尔的酷睿i9-9900K中,每个内核中有两个寄存器组,而整数寄存器组只包含180个64位寄存器。另一个寄存器堆用于向量(小的数字数组),具有168个256位条目。因此,每个内核的总寄存器堆略低于7kB。相比之下,NVIDIA GeForce RTX 2080Ti的流式多处理器(GPU相当于CPU内核)中的寄存器堆大小为256kB。

寄存器是SRAM,就像高速缓存一样,但它们和它们服务的ALU一样快,在单个时钟周期内将数据推入和推出。但是它们并不是设计用来容纳非常多的数据(仅仅是其中的一部分),这就是为什么附近总是有一些更大的内存块的原因:这是一级缓存。

上图是英特尔Skylake台式机处理器设计的单核放大照片。

在最左边可以看到ALU和寄存器堆,以绿色突出显示。图片的中上部为白色,是一级数据缓存。它容纳的信息不多,只有32kB,但就像寄存器一样,它非常接近逻辑单元,并以与它们相同的速度运行。

另一个白色矩形表示1级指令高速缓存,大小也是32kB。顾名思义,它存储各种准备拆分成更小的所谓微操作(通常标记为μ操作)的命令,供ALU执行。还有一个用于它们的缓存,您可以将其归类为0级,因为它比L1缓存更小(仅能容纳1,500个操作),距离也更近。

你可能想知道为什么这些SRAM块这么小,为什么它们不是1兆字节大小呢?加在一起,数据和指令高速缓存在芯片中占据的空间量几乎与主逻辑单元相同,因此使它们更大会增加芯片的整体大小。

但它们只有几kB的主要原因是,查找和检索数据所需的时间随着内存容量的增加而增加。一级缓存需要非常快,因此必须在大小和速度之间达成折衷--最多需要大约5个时钟周期(浮点值需要更长的时间)才能将数据从缓存中取出,以备使用。

但是,如果这是处理器中唯一的缓存,那么它的性能将会突然碰壁。这就是为什么它们都在内核中内置了另一个级别的内存:二级缓存。这是一个通用的存储块,用于保存指令和数据。

它总是比一级处理器大得多:AMD Zen 2处理器最高可达512kB,因此较低级别的高速缓存可以保持充足的供应。不过,这种额外的大小是有代价的,与级别1相比,从该缓存查找和传输数据所需的时间大约是前者的两倍。

回到最初的Intel Pentium时代,二级高速缓存是一个独立的芯片,要么安装在小型插入式电路板(如RAM DIMM)上,要么内置在主板上。它最终以自己的方式工作到CPU封装本身,直到最终集成到CPU芯片中,比如奔腾III和AMDK6-III处理器。

紧随其后的是另一个级别的高速缓存,以支持其他更低级别的高速缓存,这是由于多核芯片的兴起而产生的。

这张英特尔Kaby Lake芯片的图像显示,4个内核位于左中(一个集成的GPU几乎占据了芯片的一半,在右侧)。每个内核都有自己的私有1级和2级高速缓存集(白色和黄色高亮显示),但它们还附带第三组SRAM块。

三级高速缓存,即使它直接围绕着单个核心,也完全与其他核心共享--每个高速缓存都可以自由地访问另一个三级高速缓存的内容。它要大得多(在2到32MB之间),但速度也要慢得多,平均超过30个周期,特别是当内核需要使用远处缓存块中的数据时。

下面,我们可以在AMD的Zen 2架构中看到单核:32kB的一级数据和指令高速缓存为白色,512KB的二级高速缓存为黄色,以及一个巨大的4MB的三级高速缓存块(红色)。

等一下。32 kB怎么会比512 kB占用更多的物理空间?如果1级存储的数据如此之少,为什么它按比例比L2或L3缓存大得多?

高速缓存通过加快向逻辑单元的数据传输并在附近保存频繁使用的指令和数据的副本来提高性能。存储在高速缓存中的信息分为两部分:数据本身和它在系统内存/存储器中的原始位置--该地址称为高速缓存标签。

当CPU运行想要从存储器读取数据或向存储器写入数据的操作时,它首先检查一级高速缓存中的标签。如果存在所需的数据(缓存命中),则几乎可以立即访问该数据。当所需标签不在最低高速缓存级别时,发生高速缓存未命中。

因此,在L1缓存中创建了一个新标记,处理器体系结构的其余部分接管,在其他缓存级别(如有必要,一直搜索回主存储驱动器)中查找该标记的数据。但是,为了在L1高速缓存中为这个新标签腾出空间,总是必须将其他东西引导到L2中。

这导致了几乎不间断的数据洗牌,所有这些都是在几个时钟周期内完成的。实现这一点的唯一方法是在SRAM周围有一个复杂的结构来处理数据的管理。换句话说:如果一个CPU核心只由一个ALU组成,那么L1缓存将会简单得多,但由于有几十个ALU(其中许多会同时处理两个指令线程),缓存需要多个连接才能使所有内容保持移动。

您可以使用免费程序(如CPU-Z)检查为您自己的计算机供电的处理器的缓存信息。但是所有这些信息意味着什么呢?一个重要的元素是标签集关联--这完全是关于如何将系统内存中的数据块复制到缓存中所实施的规则。

上述高速缓存信息适用于英特尔酷睿i7-9700K。它的一级缓存每个都被分成64个称为组的小块,每个小块又被进一步分成高速缓存线(大小为64字节)。组关联意味着来自系统存储器的数据块被映射到一个特定组中的高速缓存线上,而不是可以自由映射到任何地方。

8路部分告诉我们,一个块可以与一组中的8条高速缓存线相关联。关联性级别越高(即路越多),当CPU搜索数据时,获得高速缓存命中的机会就越大,并且高速缓存未命中造成的惩罚就越小。缺点是它增加了更多的复杂性、增加了功耗,并且还可能降低性能,因为一个数据块有更多的高速缓存线要处理。

缓存复杂性的另一个方面与如何跨不同级别保存数据有关。这些规则是在所谓的包容政策中设定的。例如,英特尔酷睿处理器拥有全包容式L1+L3高速缓存。例如,这意味着级别1中的相同数据也可以在级别3中。这看起来似乎浪费了宝贵的缓存空间,但好处是,如果处理器未命中,则在搜索较低级别的标记时,它不需要遍历较高级别来找到它。

在相同的处理器中,二级缓存是非包含性的:存储在那里的任何数据都不会复制到任何其他级别。这节省了空间,但确实导致芯片的存储系统不得不搜索L3(它总是大得多)来寻找遗漏的标签。牺牲性缓存与此类似,但它们用于存储从较低级别推出的信息--例如,AMD的Zen 2处理器使用L3牺牲性缓存,它只存储来自L2的数据。

缓存还有其他策略,例如何时将数据写入缓存和主系统内存。这些策略被称为写策略,今天的大多数CPU都使用回写式高速缓存;这意味着当数据写入高速缓存级时,系统内存使用其副本更新之前会有延迟。在大多数情况下,只要数据保留在缓存中,这个暂停就会一直运行--只有在它引导出来之后,RAM才会获得信息。

NVIDIA的GA100图形处理器,共配备20 MB一级缓存和40 MB二级缓存。

对于处理器设计人员来说,选择高速缓存的数量、类型和策略完全是为了平衡对更大处理器能力的需求与增加的复杂性和所需的芯片空间。如果有可能拥有20MB、1000路完全关联的一级高速缓存,而芯片不会变成曼哈顿的大小(并且消耗同样的功率),那么我们都会有配备这种芯片的计算机!

在过去的十年里,当今CPU中的最低缓存水平并没有发生太大的变化。但是,3级缓存的大小持续增长。十年前,如果你足够幸运地拥有一台价值999美元的英特尔i7-980X,你可以得到12MB的内存。现在只需要这个数字的一半,你就可以得到64MB。

简而言之,缓存:绝对需要的,绝对令人惊叹的技术。我们没有研究过CPU和GPU中的其他缓存类型(如转换查找缓冲区或纹理缓存),但由于它们都遵循简单的结构和级别模式,就像我们在这里介绍的那样,它们听起来可能不会那么复杂。

您是否拥有一台在主板上具有二级缓存的计算机?子板中的基于插槽的奔腾II和赛扬CPU(例如300A)怎么样?您还记得您的第一个共享L3的CPU吗?在评论区让我们知道。