解释为什么有效的 DRAM 带宽会随着 CPU 的增加而减少

Explanation for why effective DRAM bandwidth reduces upon adding CPUs

此问题是此处发布的问题的衍生问题:

我已经为配备 2 个 Intel(R) Xeon(R) Platinum 8168 的 ccNUMA 系统上的内存带宽编写了一个微型基准测试:

  1. 24 核 @ 2.70 GHz,
  2. 一级缓存 32 kB,二级缓存 1 MB 和三级缓存 33 MB。

作为参考,我使用了 Intel Advisor 的屋顶线图,它描述了每个 CPU 可用数据路径的带宽。据此,带宽为230GB/s.

带宽的强大扩展:

问题:如果你看强缩放图,你可以看到峰值有效带宽实际上是在33CPUs时达到的,然后添加CPUs 只会减少它。为什么会这样?

概述

这个答案提供了可能的解释。简而言之,所有并行工作负载都不会无限扩展。当许多内核竞争相同的共享资源(例如 DRAM)时,使用太多内核通常是有害的,因为 有一个点,有足够的内核来饱和给定的共享资源,使用更多内核只会增加间接费用.

更具体地说,在您的情况下,L3 缓存和 IMC 可能是问题所在。启用 Sub-NUMA Clusteringnon-temporal prefetch 应该会提高基准测试的性能和可扩展性。尽管如此,还有其他架构硬件限制可能导致基准测试无法很好地扩展。下一节将介绍 Intel Skylake SP 处理器如何处理内存访问以及如何找到瓶颈。


引擎盖下

Intel Xeon Skylake SP 处理器的布局在您的案例中如下所示:


资料来源:Intel

有两个插槽与 UPI 互连相连,每个处理器都连接到自己的一组 DRAM。每个处理器有 2 个集成内存控制器 (IMC),每个都连接到 3 个 DDR4 DRAM @ 2666MHz。这意味着理论带宽是 2*2*3*2666e6*8 = 256 GB/s = 238 GiB/s.

假设您的基准测试设计良好并且每个处理器仅访问其 NUMA 节点,我预计 UPI 吞吐量非常低,远程 NUMA 页面数量非常少。您可以使用硬件计数器进行检查。 Linux perf 或 VTune 使您能够相对轻松地进行检查。

L3 缓存分为 。所有物理地址都使用 哈希函数 分布在缓存片中(有关详细信息,请参阅 here)。此方法使处理器能够平衡所有 L3 切片之间的吞吐量。此方法还使处理器能够平衡两个 IMC 之间的吞吐量,以便 in-fine 处理器 看起来像 SMP 架构 而不是 NUMA 架构。这也用于 Sandy Bridge 和 Xeon Phi 处理器(主要是为了减轻 NUMA 影响)。

尽管散列并不能保证完美的平衡(没有散列函数是完美的,尤其是那些计算速度很快的函数),但它在实践中通常非常好,特别是对于连续访问。由于部分停顿,糟糕的平衡会降低内存吞吐量。这是您无法达到理论带宽的原因之一。

使用好的散列函数,平衡应该与使用的核心数无关。如果散列函数不够好,一个 IMC 可能会比另一个随时间振荡更饱和。坏消息是散列函数没有记录并且检查此行为很复杂:据我所知,您可以获得每个 IMC 吞吐量的硬件计数器,但它们的粒度有限且相当大。在我的 Skylake 机器上,硬件计数器的名称是 uncore_imc/data_reads/uncore_imc/data_writes/,但在您的平台上,您肯定有 4 个计数器(每个 IMC 一个)。

幸运的是,英特尔在像您这样的 Xeon SP 处理器上提供了一项称为 Sub-NUMA 集群 (SNC) 的功能。这个想法是将处理器分成两个 NUMA 节点,这些节点有自己的专用 IMC。这解决了由于哈希函数导致的平衡问题,因此只要您的应用程序是 NUMA-friendly,就会导致更快的内存操作。否则,由于 NUMA 效应,它实际上会慢很多。在最坏的情况下,应用程序的页面都可以映射到同一个 NUMA 节点,导致只有一半的带宽可用。由于您的基准应该是 NUMA-friendly,SNC 应该更有效。


资料来源:英特尔

此外,让更多内核并行访问 L3 会导致更多提前驱逐预取缓存行,需要在内核实际需要它们时再次获取它们(使用额外的 DRAM 延迟时间付费)。这种效果并不像看起来那么不寻常。事实上,由于 DDR4 DRAM 的高延迟,硬件预取单元必须提前很长时间预取数据,以减少延迟的影响。他们还需要同时执行大量请求。这通常不是顺序访问的问题,但是 更多的内核会导致访问看起来更随机 从缓存和 IMC point-of-view。问题是 DRAM 的设计使得连续访问比随机访问更快(应该连续加载多个 连续 缓存行以使带宽完全饱和)。您可以分析 LLC-load-misses 硬件计数器的值,以检查是否有更多数据 re-fetched 更多线程(我在只有 6 核的 Skylake-based PC 上看到了这种效果,但事实并非如此强度足以对最终吞吐量造成任何可见影响)。要缓解此问题,您可以使用 software non-temporal preetch (prefetchnta) 请求处理器将数据直接加载到行填充缓冲区而不是 L3 缓存中,从而减少污染( 是一个相关的答案)。由于较低的并发性,这可能会在内核较少的情况下变慢,但在内核较多的情况下应该会快一些。请注意,这并不能解决从 IMC point-of-view 中获取看起来更随机的地址的问题,对此没有什么可做的。

low-level 架构 DRAM 和缓存在实践中非常复杂。有关内存的更多信息可以在以下链接中找到: