【问题标题】:Slowdown when accessing data at page boundaries?在页面边界访问数据时速度变慢?
【发布时间】:2019-11-16 11:55:42
【问题描述】:

(我的问题是关于计算机架构和性能理解的问题。没有找到相关的论坛,所以在这里作为一般问题发布。)

我有一个C 程序,它访问在虚拟地址空间中相隔 X 字节的内存字。例如,for (int i=0;<some stop condition>;i+=X){array[i]=4;}

我用变化的值X 测量执行时间。有趣的是,当X2 的力量并且大约是页面大小时,例如X=1024,2048,4096,8192...,我的性能会大幅下降。但是对于X 的所有其他值,例如10231025,没有减速。性能结果见下图。

我在几台个人机器上测试我的程序,所有机器都在 Intel CPU 上运行带有 x86_64 的 Linux。

这种放缓的原因可能是什么?我们在 DRAM、L3 缓存等中尝试过行缓冲区,这似乎没有意义......

更新(7 月 11 日)

我们在这里做了一个小测试,将 NOP 指令添加到原始代码中。放缓仍然存在。这有点否决了 4k 别名。冲突缓存未命中的原因更可能是这里的情况。

【问题讨论】:

  • 您可能需要提及它是哪个 CPU(Intel Atom 与 Netburst 非常不同,它们都与 Sandy Bridge 非常不同,后者与 Haswell 略有不同;甚至同一个微架构中稍微不同的 CPU 模型具有不同的缓存大小),另外,如果页面被填充/存在,阵列有多大(如果它太大以至于所有翻译都无法容纳在 CPU 的 TLB 和/或某些缓存中)如果 TLB 被“加热”。对于随机猜测,我会怀疑某处存在混叠情况(可能是 L2 数据缓存?)。
  • y 轴代表什么?显示用于生成图形的整个代码、它是如何编译的以及它在哪个 CPU 上运行。
  • 我认为 4k 别名对于纯商店来说并不重要,只是商店和负载的混合。可以将存储写入存储缓冲区,而无需确定它是否与较早或较晚的存储重叠。这就是为什么我在这里的回答中说 4k 混叠可能没有解释它,即使它通常是大步幅的问题。
  • 是的,我同意原因可能是缓存未命中并将更新 OP。
  • 添加 NOP 不会显示任何内容。加载和存储不一定要背靠背才能发生 4K 混叠。如果您不提供我在之前评论中要求的信息,则很难为您提供帮助。

标签: performance memory cpu-architecture cpu-cache


【解决方案1】:

这里有两件事:

  • 如果您只接触 4096 个地址的倍数,则设置关联缓存别名会导致冲突丢失。内部快速缓存(L1 和 L2)通常由物理地址中的一小部分位索引。所以跨越 4096 字节意味着这些地址位对于所有访问都是相同的,所以你只是 L1d 缓存中的一组,而 L2 中的一些小数字。

    跨步 1024 意味着您在 L1d 中仅使用 4 个集合,较小的 2 幂次使用逐渐增加的集合,但非 2 次幂分布在所有集合中。 (Intel CPU 长期以来一直使用 32KiB 8 路关联 L1d 缓存;每路 32K/8 = 4K。Ice Lake 将其提高到 48K 12 路,因此相同的索引集仅取决于页面下方的位编号。这对于希望与 TLB 并行索引的 VIPT 缓存并非巧合。)

    但使用非 2 次方步长,您的访问将分布在缓存中的更多集合上。 Performance advantages of powers-of-2 sized data?(答案描述了这个dis优势)

    Which cache mapping technique is used in intel core i7 processor? - 共享 L3 高速缓存可以抵抗大的 2 次方偏移造成的混叠,因为它使用了更复杂的索引功能。

  • 4k 别名(例如,在某些 Intel CPU 中)。尽管对于 only 商店,这可能无关紧要。这主要是内存消歧的一个因素,当 CPU 必须快速确定负载是否可能正在重新加载最近存储的数据时,它会在第一轮中通过仅查看页面偏移位来实现。

    这可能不是你要发生的事情,但有关更多详细信息,请参阅:
    L1 memory bandwidth: 50% drop in efficiency using addresses which differ by 4096+64 bytes
    Why are elementwise additions much faster in separate loops than in a combined loop?

这些影响中的一个或两个都可能是Why is there huge performance hit in 2048x2048 versus 2047x2047 array multiplication?的一个因素


另一个可能的因素是硬件预取在物理页面边界处停止。 Why does the speed of memcpy() drop dramatically every 4KB? 但是将步幅从 1024 更改为 1023 并不会起到很大的帮助。 IvyBridge 及以后的“下一页”预取只是 TLB 预取,不是下一页的数据。


对于这个答案的大部分内容,我有点假设 x86,但缓存别名/冲突未命中的东西通常适用。具有简单索引的集合关联缓存普遍用于 L1d 缓存。 (或者在较旧的 CPU 上,直接映射,其中每个“集合”只有 1 个成员)。 4k 别名的东西可能主要是英特尔特有的。

跨虚拟页面边界预取可能也是一个普遍问题。

【讨论】:

  • 循环中没有时间局部性,所以我认为缓存集映射无关紧要(除非数组的大小足够小以适合私有缓存,但又足够大以使写回可能通过导致 L2 和 L3 端口拥塞来影响性能)。阵列中显然没有负载,因此不会发生 4K 混叠。硬件预取和 TLB 未命中的预期影响与 OP 中的图表不一致。虽然我怀疑 OP 显示的代码不是用于生成图表的代码。
  • @HadiBrais:我假设这是在重复循环中,但这可能是一个错误的假设。我想知道与其他相当近期的商店同组的商店是否会产生某种影响。就像如果我们最终不得不等待回写,而我们不会这样做?或者可能是硬件预取完成的一些负载的早期驱逐,所以它们必须在存储提交之前重做?这可能会花费很多时间。
  • L1 写回的优先级低于其他事务,因此它们在总线可用时完成。但是,当 L1D 写回缓冲区已满时,写回获得更高的优先级,这可能会延迟其他事务(加载、RFO、直写存储)。 OFFCORE_REQUESTS_BUFFER.SQ_FULL 事件可用于计算发生这种情况的周期数。在 Pentium Pro 上,L1 写回缓冲区的数量是 1,并且在某个时候增加到 4,然后再增加到 6(在 Haswell/Broadwell/Skylake 上)。请注意,写回与其他事务采用相同的路径。
  • 在具有非包含 L3 的处理器上,L2 中的脏行可能会被写回 L3,但如果该行不再在 L3 中,则必须从其获取主节点,其成本包括内存带宽、L3 带宽和 L3 空间。
  • 为什么你认为下一页预取器只用于 TLB?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-25
  • 2023-01-12
  • 1970-01-01
  • 1970-01-01
  • 2010-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多