对于典型的 x86 多核处理器,假设我们有一个具有 2 个内核的处理器
好的,让我们使用一些具有两个内核 (Conroe) 的 Intel Core 2 Duo 的早期变体。它们有 2 个 CPU 内核、2 个 L1i 缓存和共享的 L2 缓存。
并且两个内核在读取指令时都会遇到 L1 指令缓存未命中。
好的,L1i 中会出现读取下一条指令的缺失(L1d 中的缺失,当您访问数据时,工作方式类似,但只有从 L1i 读取和从 L1d 读取和写入)。每个未命中的 L1i 都会向内存层次结构的下一层、L2 缓存生成请求。
我们还假设两个内核都在访问位于不同缓存行中的地址中的数据。
现在我们必须知道缓存是如何组织的(这是经典的中间细节缓存方案,在逻辑上类似于真实硬件)。高速缓存是具有特殊访问电路的存储器阵列,它看起来像二维阵列。我们有很多sets(这张图片中有64 个),每个set 都有几个方式。当我们要求缓存从某个地址获取数据时,该地址分为 3 部分:标记、设置索引和缓存行内的偏移量。集合索引用于选择集合(我们的二维缓存数组中的行),然后将所有方式的标签与请求地址的标签部分进行比较(找到二维数组中的右列),这是由8个标签并行完成的比较器。如果缓存中存在与请求地址标签部分相同的标签,则缓存“命中”并且来自所选单元格的缓存行将返回给请求者。
方法和设置;二维缓存数组(图片来自http://www.cnblogs.com/blockcipher/archive/2013/03/27/2985115.html 或http://duartes.org/gustavo/blog/post/intel-cpu-caches/)
选择设置索引 2 的示例,并行标记比较器为方式 1 提供“命中”(标记相等):
一些内存或缓存的“端口”是什么?这是外部硬件块和内存之间的硬件接口,它有请求地址(由外部块设置,L1 由 CPU 设置,L2 - 由 L1 设置)、访问类型(加载或存储;可能固定为端口),数据输入(用于存储)和带有就绪位的数据输出(由内存设置;缓存逻辑也处理未命中,因此它会在命中和未命中时返回数据,但稍后会返回未命中的数据)。
如果我们想增加真正的端口数,我们应该增加硬件:对于原始 SRAM 存储器阵列,我们应该为每个位添加两个晶体管以将端口数增加 1;对于缓存,我们应该复制所有标签比较器逻辑。但是这样成本太高了,所以CPU中没有太多的多端口内存,如果有几个端口,那么真正的端口总数就很少了。
但我们可以模拟拥有多个端口。 http://web.eecs.umich.edu/~twenisch/470_F07/lectures/15.pdfEECS 470 2007 幻灯片 11:
并行缓存访问比并行 FU 更难
- 根本区别:缓存有状态,FU 没有
- 一个端口影响其他端口的未来
使用了几种方法
- 真正的多端口
- 多个缓存副本
- 虚拟多端口
- 多银行(交错)
- 行缓冲区
现代芯片使用多银行(有时称为切片)(“英特尔酷睿 i7 在 L1 中有 4 个银行,在 L2 有 8 个银行”;图 1.6 来自 ISBN 1598297546(2011 年)第 9 页)-https://books.google.com/books?id=Uc9cAQAAQBAJ&pg=PA9&lpg=PA9)。这意味着,有几个较小尺寸的硬件缓存,并且请求地址的一些位(集合索引的一部分 - 认为集合 - 行被拆分为 8 个部分或已着色为交错行)用于选择银行。每个bank的端口数(1)很少,功能就像经典缓存一样(每个bank中都有全套标签比较器;但是bank的高度-其中的集合数较小,并且数组中的每个标签都被路由仅用于单个标记比较器 - 与单端口缓存一样便宜)。
这两个内核会同时从 L2 到 L1 指令缓存中获取数据,还是会被序列化?换句话说,我们是否有多个端口用于不同内核的二级缓存访问?
如果两个访问被路由到不同的 L2 bank(片),那么缓存的行为就像多端口,并且可以同时处理两个请求。但是,如果两者都被路由到具有单个端口的单个 bank,它们将被序列化以用于缓存。缓存序列化可能会花费几个滴答声,并且请求将在端口附近停止; CPU 会将此视为访问延迟稍长。