【问题标题】:Does x86_64 CPU use the same cache lines for communicate between 2 processes via shared memory?x86_64 CPU 是否使用相同的缓存线通过共享内存在 2 个进程之间进行通信?
【发布时间】:2016-03-02 15:33:12
【问题描述】:

众所周知,现代 x86_64 上的所有级别的缓存 L1/L2/L3 都是 virtually indexed, physically tagged。并且所有内核通过 QPI/HyperTransport 上的缓存一致性协议 MOESI/MESIF 通过 Last Level Cache - cache-L3 进行通信。

例如,Sandybridge 系列 CPU 具有 4 - 16 路缓存 L3 和 page_size 4KB,然后这允许通过共享内存在不同内核上执行的并发进程之间交换数据。这是可能的,因为高速缓存 L3 不能同时包含与进程 1 的页面和进程 2 的页面相同的物理内存区域。

这是否意味着每次进程 1 请求相同的共享内存区域时,进程 2 将其页面缓存行刷新到 RAM 中,然后进程 1 加载与缓存相同的内存区域 -进程1的虚拟空间中的页面行数?真的很慢还是处理器使用了一些优化?

现代 x86_64 CPU 是否使用相同的高速缓存行(没有任何刷新)通过共享内存在具有不同虚拟空间的 2 个进程之间进行通信?

Sandy Bridge Intel CPU - 高速缓存 L3:

  • 8 MB - 缓存大小
  • 64 B - 高速缓存行大小
  • 128 K - 行 (128 K = 8 MB / 64 B)
  • 16路
  • 8 K - 路数组(8 K = 128 K 线 / 16 路)
  • 13 位 [18:6] - 虚拟地址(索引)定义当前集合编号 (这是标签)
  • 512 K - 每个相同(虚拟地址 / 512 K)竞争同一组(8 MB / 16 路)
  • 低 19 位 - 对确定当前集数很重要

  • 4 KB - 标准页面大小

  • 只有低 12 位 - 每个地址的虚拟地址和物理地址相同

我们有 7 个缺失位 [18:12] - 即我们需要检查 (7^2 * 16-way) = 1024 个缓存行。这与 1024 路缓存相同 - 所以这非常慢。这是否意味着,缓存 L3 是(物理索引,物理标记)?

标签虚拟地址缺失位汇总(页面大小 8 KB - 12 位):

  • L3(8 MB = 64 B x 128 K 行),16 路,8 K 组,13 位标签 [18:6] - 缺少 7 位
  • L2(256 KB = 64 B x 4 K 行),8 路,512 组,9 位标签 [14:6] - 缺少 3 位
  • L1(32 KB = 64 B x 512 行),8 路,64 组,6 位标签 [11:6] - 无丢失位

应该是:

  • TLB 查找后使用的 L3 / L2(物理索引、物理标记)
  • L1(虚拟索引,物理标记)

【问题讨论】:

  • 回复:您的编辑。不,L3 绝对没有虚拟标记。它不会在转换时刷新,并且它确实支持一致性流量。唯一的问题是它究竟是如何做到这一点的。就像我在回答中所说的那样,我最好的猜测是它被物理索引以及物理标记。出于多种原因,这很有意义,其中包括:只有 L1 缓存需要同时关心虚拟地址和物理地址。在查询更高级别的缓存时,根本只需要将物理地址发送给它们。
  • David Kanter 的文章也没有提到 L2/L3 被虚拟索引。您应该从您的问题中编辑该错误陈述(以及我在回答开始时指出的那个)。如果你有可用的物理地址,那么虚拟索引没有任何优势,所以 phys/phys 很有意义。
  • @Peter Cordes 好的,我修好了。
  • @Peter Cordes 即我们有 3 个步骤:1. 核心同时向 L1 和 TLB-L1 发送查询,并同时从两者接收答案。 2. 如果 L1 包含所需的缓存线,我们会从 L1 接收数据,然后从 TLB-L1(100 条目 * 4 KB 页面大小 = 400 KB)我们接收此缓存线的物理地址如果它在 L2/L3 中。 3. 如果 L2 或 L3 不包含它,那么我们向 TLB-L2 发送查询,不是吗?
  • 不,二级 TLB 不是二级缓存的 TLB。这是TLB的第二级。如果 L1TLB 未命中,L1D$ 甚至无法检查其标签,直到 L2TLB 命中,或者发生完整的 TLB 未命中并且 CPU 遍历页表。 (并驱逐一个旧的 TLB 条目,用新找到的条目替换它。)

标签: multithreading concurrency x86 x86-64 cpu-cache


【解决方案1】:

这是可能的,因为缓存 L3 不能包含相同的物理 内存区域同时作为进程 1 的页面和进程 2 的页面 时间。

嗯,什么?如果两个进程都有一个页面映射,那么它们都可以在缓存中命中同一行物理内存。

这是英特尔多核设计使用大型包容性 L3 缓存的部分优势。一致性只需要检查 L3 标签即可在另一个内核的 L2 或 L1 缓存中找到处于 E 或 M 状态的缓存行。

在两个内核之间获取数据只需要写回 L3。我忘记了这是在哪里记录的。也许http://agner.org/optimize/What Every Programmer Should Know About Memory?。或者对于不共享任何级别缓存的内核,您需要在缓存层次结构的同一级别的不同缓存之间进行传输,作为一致性协议的一部分。即使线路“脏”,这也是可能的,新所有者负责最终写回与 DRAM 不匹配的内容。


映射到不同虚拟地址的同一缓存行将始终位于同一组 L1 缓存中。请参阅 cmets 中的讨论:L2 / L3 缓存是物理索引和物理标记的,因此别名永远不会成为问题。 (只有 L1 可以从虚拟索引中获得速度优势。在地址转换完成之前不会检测到 L1 缓存未命中,因此物理地址可以及时准备好探测更高级别的缓存。)

还要注意,cmets 中的讨论错误地提到了 Skylake 降低了 L1 缓存的关联性。事实上,Skylake L2 缓存的关联性比以前低(4 路,低于 SnB/Haswell/Broadwell 中的 8 路)。 L1 仍然是 32kiB 8 路:保持页面选择地址位在索引之外的关联性的最大大小。所以毕竟没有什么神秘的。

另见another answer to this question about HT threads on the same core communicating through L1。我在那里说了更多关于缓存方式和集合的信息。

【讨论】:

  • 你能扩展你的论点的数学吗?索引需要多少位取决于缓存大小、缓存行长度和缓存的关联性。所以对于一个 8MB 的 16 路缓存,每个缓存行 64 B,我们应该需要 log2(2^23/(2^4*2^6))=13 个索引位,但一个页面只覆盖 12 位。
  • “索引位的数量不会随着缓存大小的增加而增加” - 那是怎么回事?为简单起见,让我们使用直接映射缓存。如果我们有 8 个缓存桶,这意味着我们必须使用低 3 位进行索引。如果我们有 16 个,我们将需要低 4 位,依此类推。即使在集合关联缓存中,集合的大小也是固定的,这意味着您的缓存大小越大,您获得的集合就越多,这再次意味着您必须使用更多位来决定您想要哪个集合。
  • @Peter Cordes 谢谢。但是 64 位虚拟地址(12 位与物理地址相同)足以检查我们是否需要将 L3 刷新到 RAM,但 不足以检查这是否相同不使用TLB的物理地址。 IE。如果我们有一个物理 4KB 映射到两个不同的虚拟地址,那么要决定刷新/置换缓存行,或者重复使用它 - 我们在访问缓存时肯定需要使用 TLB。做这个处理器吗?
  • @Voo:哦,我知道我哪里出错了。我倒过来了。我计算的方式,每路的行数是固定的,而不是路数!所以更大的缓存将更具关联性。我仍然确定 CPU 以某种方式解决了这个问题(并且不能两次在缓存中拥有相同的物理行,不同的虚拟地址以不同的方式),但现在我不确定如何。有什么想法吗?
  • 我不知道任何具有虚拟索引 L2/L3 缓存的传统架构实例。 (The Mill 是(将是?)不寻常的单一地址空间,允许延迟翻译。)我不知道 Skylake 如何处理别名问题。使用 MESI,如果另一个缓存想要读取修改的行,则必须将其写回(而不是刷新)。提供 Forwarding 或 Owned 状态允许共享脏缓存行。 (我不记得英特尔何时从 MESI 转移到 MESIF。)顺便说一句,通知不适用于帖子(或至少是问题)。
猜你喜欢
  • 2011-11-06
  • 1970-01-01
  • 2011-06-26
  • 2016-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多