缓存怎么能这么快?


37

这是缓存基准的屏幕截图:

AIDA64缓存和内存基准测试结果

在基准测试中,L1缓存的读取速度约为186 GB / s,延迟约为3-4个时钟周期。这样的速度怎么达到?

在这里考虑内存:理论上的最大速度为665 MHz(内存频率)x 2(双倍数据速率)x 64位(总线宽度),大约为10.6 GB / s,接近于9.6 GB / s的基准值。 。

但是,使用L1高速缓存,即使我们可以在处理器的最大频率(3 GHz)的每个周期读取数据,我们也需要大约496条数据线来实现这样的吞吐量,这听起来是不现实的。这也适用于其他缓存。

我想念什么?我们如何根据其参数计算缓存的吞吐量?


14
您是否考虑过L1,2,3高速缓存有多小?物理上它所在的位置是否相等。提示,如果您拥有整个芯片,则无需担心总线标准
JonRB

2
另外:基准测试是否知道它在做什么,以确保测试的某些数据不会直接保存在寄存器中?
rackandboneman

7
@rackandboneman:AIDA64是一个受人尊敬的基准测试,不是有人刚刚用C破解并让编译器优化了一些负载!我假设微基准测试零件是用SSE或AVX版本组装而成的。
彼得·科德斯

1
@Peter Cordes令人满意的答案-一个必要的问题。
rackandboneman

1
只是为了将思维纳入物理视野:光在1.4纳秒内传播约一英尺半。这意味着,如果缓存位于主板的另一侧,则这样的延迟可能会破坏相对性。或者是测量误差
亚瑟

Answers:


35

该CPU具有...

2个内核每个内核32 KB指令和32 KB数据一级缓存(L1)

由于有两个内核,我们可以期望基准测试可以并行运行两个线程。虽然他们的网站提供的信息很少,但是如果我们在这里查看,具有更多内核的CPU似乎可以提供更高的L1吞吐量。因此,我认为显示的是所有内核并行工作的总吞吐量。因此,对于您的CPU,我们应该将一个内核和一个缓存一分为二:

Read   93 GB/s
Write  47 GB/s
Copy   90 GB/s

现在,“复制”比“写入”快2倍的事实令人高度怀疑。它怎么能比写速度快?我敢打赌,基准显示为“ copy”的是读写吞吐量的总和,在这种情况下,它将以45 GB / s的速度进行读取和写入,但是显示90(因为这是基准),并且到底谁信任基准?因此,让我们忽略“复制”。

Read   93 GB/s => 30 bytes/clock
Write  47 GB/s => 15 bytes/clock

现在,一个128位寄存器为16个字节,足够接近,因此听起来该高速缓存可以执行两次128位读取,每个时钟一次写入。

这正是您真正想要简化这些SSE数字处理指令的过程:每个周期两次读取和一次写入。

这很可能用大量并行数据线来实现,这是在芯片内部非常快速地处理大量数据的常用方法。


4
在文档的第55页上,@ next-hack指向其链接“在内部,访问最多为16个字节。每个循环可处理两次加载操作和一次存储操作”。这就解释了为什么读取速度快两倍-它可以在同一操作中执行两次读取,同时执行一次写入。
汤姆·卡彭特

2
是的,它显然是在计算副本BW =读写。这似乎与替代方法一样有效,因为它具有读写可并行执行的意义。请注意,L2 / L3的OP编号的拷贝数不高于写入数,而对于存储器则较低。DDR3内存总线不是全双工的:读取和写入需要相同的数据线。(有关NT商店与常规商店的x86 memcpy / memset带宽的更多信息,请参见stackoverflow.com/questions/43343231/…)。
彼得·科德斯

6
您猜测IvyBridge可以在同一时钟周期内进行2次读取 1次写入。您碰巧是对的,但仅在非常有限的情况下。IvB仅具有2个AGU端口,因此通常每个时钟它仅限于2个内存操作,最多可以存储1个。但是256b AVX加载/存储需要2个周期才能在加载/存储端口中执行,而在第一个周期中只需要AGU。因此,存储地址uop可以在256b负载的第二个周期内在端口2/3上运行,而不会花费任何负载带宽。(存储数据uops在端口4上运行。)来源:agner.org/optimize microarch pdf
Peter Cordes

2
AMD Bulldozer系列或Ryzen CPU会为您提供相同的读取= 2倍的写入次数,但实际上每个时钟它们仅限于2个内存操作(最多可以进行一次写入)而没有漏洞。读/写/复制不能检测出差异,但是Triad可以(a[i] = b[i] + c[i])。顺便说一句,Intel Haswell及更高版本在端口7上具有一个store-AGU,它可以处理简单的(非索引)寻址模式,因此它们每个时钟可以执行2次加载+ 1次存储。(到L1D的数据路径为256b,因此它使L1D带宽增加了一倍。)请参阅David Kanter的文章:realworldtech.com/haswell-cpu/5
Peter Cordes

1
@AliChen:OP在询问带宽有多快之前就明确提到了IvyBridge的4周期负载使用延迟。
彼得·科德斯

27

@peufeu的答案指出,这些是系统范围的聚合带宽。L1和L2是Intel Sandybridge系列中的每核专用高速缓存,因此数量是单个核可以达到的2倍。但这仍然给我们留下了令人印象深刻的高带宽和低延迟。

L1D缓存直接内置在CPU内核中,并且与加载执行单元(和存储缓冲区)紧密耦合。同样,L1I高速缓存就在内核的指令获取/解码部分的旁边。(我实际上没有看过Sandybridge的硅平面图,因此从字面上看可能并非如此。前端的问题/重命名部分可能更接近“ L0”解码的uop缓存,从而节省了功耗并具有更好的带宽比解码器。)

但是使用L1缓存,即使我们可以在每个周期读取...

为什么停在那里?自Sandybridge起的英特尔和自K8起的AMD可以每个周期执行2次加载。多端口缓存和TLB是一件事情。

David Kanter的Sandybridge微体系结构文章有一个不错的图(它也适用于您的IvyBridge CPU):

(“统一调度程序”保留ALU和内存微件,等待它们的输入准备就绪,和/或等待其执行端口。(例如,vmovdqa ymm0, [rdi]解码为必须等待rdi先前add rdi,32尚未执行的加载uop ,对于例子)。 英特尔时间表微指令到在发布/重命名时间端口。此图仅示出了用于存储器微指令的执行端口,但未执行ALU的uop争夺这一点。该问题/重命名阶段增加了微指令到ROB和调度他们一直停留在ROB中直到退休,但直到调度到执行端口才在调度程序中使用(这是Intel的术语;其他人使用issue并以不同的方式调度)。 AMD为整数/ FP使用单独的调度程序,但是寻址模式始终使用整数寄存器

David Kanter的SnB内存图

如图所示,只有2个AGU端口(地址生成单元,采用类似寻址方式[rdi + rdx*4 + 1024]并产生线性地址)。每个时钟可以执行2个存储器操作(每个存储器128b / 16个字节),最多可以存储1个。

但它有一个窍门:SnB / IvB运行256b AVX作为单个uop加载/存储,在加载/存储端口中需要2个周期,但在第一个周期只需要AGU。这样就可以在第二个周期内在端口2/3的AGU上运行存储地址uop,而不会丢失任何负载吞吐量。因此,使用AVX(Intel Pentium / Celeron CPU不支持:/),SnB / IvB(理论上)可以在每个周期中承受2个负载 1个存储。

您的IvyBridge CPU是Sandybridge的缩影(具有一些微体系结构上的改进,例如mov-elimination,ERMSB(memcpy / memset)和下一页硬件预取)。此后的一代(Haswell)通过将执行单元到L1的数据路径从128b扩展到256b,使每时钟L1D带宽增加了一倍,因此AVX 256b负载可以每个时钟维持2个。它还为简单的寻址模式添加了一个额外的store-AGU端口。

Haswell / Skylake的峰值吞吐量是每个时钟加载并存储96字节,但是英特尔的优化手册建议Skylake的持续平均吞吐量(仍然假设没有L1D或TLB丢失)每个周期约为81B。(根据我在SKL上的测试,一个标量整数循环可以在每个时钟上承受 2个负载+ 1个存储,从4个融合域uops中每个时钟执行7个(非融合域)uos。但是使用64位操作数而不是使用它会减慢速度32位,因此显然存在一些微体系结构资源限制,这不仅仅是将存储地址地址调度到端口2/3并从负载中窃取周期的问题。)

我们如何根据其参数计算缓存的吞吐量?

除非参数包含实际的吞吐量数字,否则您不能这样做。如上所述,即使是Skylake的L1D也无法完全满足256b向量的加载/存储执行单元的需求。尽管它很接近,并且可以用于32位整数。(加载单元的数量比缓存中读取端口的数量多是没有道理的,反之亦然。您只剩下那些永远无法充分利用的硬件。请注意,L1D可能有额外的端口来发送/接收线路到/从其他内核,以及从内核内部进行读/写。)

仅查看数据总线的宽度和时钟并不能为您提供全部信息。 L2和L3(以及内存)的带宽可能受L1或L2可以跟踪的未命中次数的限制。带宽不能超过延迟* max_concurrency,并且延迟L3较高的芯片(如多核Xeon)与相同微体系结构的双/四核CPU相比,单核L3带宽要少得多。请参阅此SO解答的“延迟绑定平台”部分。Sandybridge系列CPU具有10个行填充缓冲区以跟踪L1D丢失(也由NT商店使用)。

(在大型Xeon上,具有多个活动内核的L3 /内存总带宽巨大,但是在相同的时钟速度下,单线程代码的带宽要比四核处理器差,因为更多的内核意味着环形总线上的停止更多,因此更高延迟L3。)


缓存延迟

这样的速度怎么达到?

L1D缓存的4周期负载使用延迟非常惊人,特别是考虑到它必须以开头的寻址模式[rsi + 32],因此必须在它具有虚拟地址之前进行加法。然后,它必须将其转换为物理,以检查缓存标签是否匹配。

(寻址模式不是[base + 0-2047]在Intel Sandybridge系列上花费额外的时间,因此AGU中有一个用于简单寻址模式的快捷方式(通常是指针加载的情况,在这种情况下,低负载使用延迟可能是最重要的,但通常也很常见) (请参阅英特尔的优化手册,Sandybridge第2.3.5.2节L1 DCache。)这还假定没有段覆盖,并且段基地址为0,这是正常的。)

它还必须探查存储缓冲区,以查看它是否与任何较早的存储区重叠。即使尚未执行较早的(按程序顺序)存储地址uop,也必须弄清楚这一点,因此未知存储地址。但是大概这可能与检查L1D命中同时发生。如果事实证明不需要L1D数据,因为存储转发可以从存储缓冲区提供数据,那么这没有损失。

英特尔几乎像其他所有人一样使用VIPT(虚拟索引物理标记)缓存,使用标准技巧,使缓存足够小且具有足够高的关联性,以VIPT的速度表现得像PIPT缓存(无锯齿)(可以建立索引)与TLB虚拟->物理查询并行)。

英特尔的L1高速缓存是32kiB,8路关联的。页面大小为4kiB。这意味着“索引”位(用于选择可以缓存任何给定行的8种方式中的哪一组)都在页面偏移量以下;也就是说,这些地址位是页面的偏移量,并且在虚拟和物理地址中始终相同。

有关此内容的更多详细信息以及为何小/快速缓存有用/可行(以及与较大的慢速缓存配对使用时效果很好)的其他详细信息,请参阅我关于L1D为什么比L2D小/快的答案。

小型高速缓存可能会执行大型高速缓存中过于耗电的事情,例如与获取标签同时从集合中获取数据阵列。因此,一旦比较器找到了匹配的标签,就只需复用已经从SRAM中获取的8个64字节高速缓存行之一。

(这并不是真的那么简单:Sandybridge / Ivybridge使用具有八个16个字节块的存储体的存储L1D高速缓存。如果在不同高速缓存行中对同一存储体的两次访问尝试在同一周期中执行,则会出现高速缓存-存储体冲突。 (有8个存储体,因此这可能发生在地址间隔为128的倍数时,即2个缓存行。)

只要IvyBridge不跨越64B高速缓存行边界,它对不对齐访问也不会造成任何损失。我猜想它会根据低位地址找出要读取的存储体,并设置为获得正确的1至16字节数据而需要进行的任何移位。

在高速缓存行拆分中,它仍然只是单个uop,但是可以进行多个高速缓存访​​问。除4k分割外,罚款仍然很小。Skylake甚至使4k分割变得相当便宜,延迟约为11个周期,与具有复杂寻址模式的普通高速缓存行分割相同。但是4k拆分的吞吐量显着低于cl-split非拆分。


资料来源


1
这非常清楚,详尽且写得很好!+1!
next-hack

8

在现代CPU上,高速缓存位于同一芯片(芯片)上与CPU相邻的位置,它是使用SRAM制成的,它比PC中用于RAM模块的DRAM快得多。

单位内存(位或字节)SRAM比DRAM贵得多。这就是为什么DRAM也用于PC的原因。

但是由于SRAM的制造技术与CPU本身相同,因此它与CPU一样快。另外,只有内部(CPU上)总线要处理,因此如果需要496行宽的总线,则可能是这样。


谢谢你的关注。我在几本书中看到,寄存器访问速度超过300 GB / s,在这种情况下,对于3 GHz处理器,寄存器吞吐量为100 B /周期,这是不可能的,因为寄存器通常为64/128位宽,他们不能输出那么多。这就是我所关心的。GB / s是表达吞吐量的正确方法。
骑士

3
@Knight请记住,IvB(作为任何高性能处理器)每个周期执行几条指令,例如3个ALU操作,2个加载和1个存储。这些寄存器中的大多数可以占用2个输入(对于索引寻址,甚至可以装入3个负载),而装入甚至需要3个输入。这是13个寄存器,每个寄存器8个字节,104个字节(可能是不允许这种史诗组合的情况,但是没有迹象表明IvB就是这种情况,尽管它无法持续)。如果您还考虑向量寄存器,则该数字会进一步增加。
哈罗德

@harold:相关:Haswell和Skylake似乎确实对每个时钟的寄存器读取有限制,尽管这可能是在前端,并且在某些输入准备就绪后不会影响执行突发。也许这是其他一些微体系结构的限制,但是我发现代码中的瓶颈应该能够使每个时钟维持更多的操作。 agner.org/optimize/blog/read.php?i=415#852。在Haswell上,我的最佳情况是每个时钟周期读取约6.5个整数寄存器(持续)。我还设法在Skylake上的每个时钟调度/执行中获得了7微秒的持续时间(商店是商店地址+商店数据)。
彼得·科德斯

@PeterCordes一定是前端吗?从历史上看,这也是IIRC的问题(PPro到Core2),我不确定小数在其他方面如何有意义。虽然我的电话无论如何还是有点
过时-harold

@harold:是的,我很确定这是某种前端瓶颈,可能是重命名。P6的寄存器读取瓶颈在“冷”寄存器上,必须将其从永久寄存器文件中读取到有争议的ROB中。最近修改过的寄存器仍在ROB中,并且没有瓶颈。我没有对HSW / SKL上的冷调节器和热调节器进行过多研究,因为出于某种原因,我没有想到使循环的大小大于4 oups /理想情况下每次迭代均大于1 c。哎呀 IDK转发与PRF读取之间有多少差异(这必须在执行时发生,而不是发出/重命名)。
彼得·科德斯

4

L1缓存是相当广泛的内存结构。可以在本手册中找到Intel处理器中L1缓存的体系结构(由next-hack提供)。但是,某些参数的解释不正确,“高速缓存行大小”不是“数据宽度”,它是原子数据访问的串行块的大小。

表2-17(第2.3.5.1节)指出,在加载(读取)时,每个CYCLE的高速缓存带宽为2x16 = 每个内核32字节。仅此一项就可以在3GHz内核上提供96 Gb / s的理论带宽。目前尚不清楚所引用的基准测试报告是什么,看起来它可以测量两个并行工作的内核,因此两个内核可以达到192 Gbps。


2

登机口延误是什么?10皮秒?整个流水线操作的周期时间为333皮秒,在下一个时钟周期开始之前,具有各种解码和总线活动以及触发器对数据的捕获。

我预计读取缓存的过程中最慢的活动是等待数据线移动得足够远(可能这是差分的:一个参考和一个来自读取位的实际电荷),从而可以为比较器/锁存器提供时钟,以实现正-反馈动作,将微小的电压转换成较大的轨到轨逻辑电平摆幅(约1伏)。


1
请记住,4个周期的L1D延迟包括地址生成(用于的简单寻址模式[reg + 0-2047]),TLB查找以及标记比较(8路关联),并将产生的多达16个未对齐字节放入加载单元的输出端口,用于转发到其他执行单元。像这样的指针追逐循环的延迟为4c mov rax, [rax]
彼得·科德斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.