解释为什么有效 DRAM 带宽在添加 CPU 后会减少

Nit*_*lly 3 parallel-processing performance intel cpu-architecture numa

这个问题是此处发布的问题的衍生问题:Measurement Bandwidth on a ccNUMA system

我为配备 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。

带宽的强大扩展: 在此输入图像描述

问题:如果您查看强扩展图,您可以看到峰值有效带宽实际上是在 33 个 CPU 上实现的,之后添加 CPU 只会降低峰值有效带宽。为什么会发生这种情况?

Jér*_*ard 5

概述

\n

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

\n

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

\n
\n

在引擎盖下

\n

在您的情况下,Intel Xeon Skylake SP 处理器的布局如下所示:

\n

处理器配置

\n

核心配置
\n来源:英特尔

\n

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

\n

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

\n

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

\n

虽然哈希并不能保证完美的平衡(没有完美的哈希函数,尤其是计算速度快的哈希函数),但它在实践中通常相当好,特别是对于连续访问。不良的平衡会因部分停顿而降低内存吞吐量。这是无法达到理论带宽的原因之一。

\n

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

\n

幸运的是,Intel在像您这样的 Xeon SP 处理器上提供了一种称为Sub-NUMA 集群(SNC)的功能。这个想法是将处理器分成两个拥有自己专用 IMC 的 NUMA 节点。这解决了哈希函数带来的平衡问题,只要您的应用程序支持 NUMA,就能实现更快的内存操作。否则,由于 NUMA 效应,它实际上可能会明显变慢。在最坏的情况下,应用程序的页面可以全部映射到同一个 NUMA 节点,导致只有一半的带宽可用。由于您的基准测试应该是 NUMA 友好的,因此 SNC 应该更高效。

\n

子 NUMA 集群
\n来源:英特尔

\n

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

\n

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

\n\n