【问题标题】:Evaluating worst case RAM effective bandwidth with discontinous memory access评估不连续内存访问的最坏情况 RAM 有效带宽
【发布时间】:2018-10-17 07:10:14
【问题描述】:

在最坏的情况下,我正在尝试评估从主内存到 CPU 的有效内存“带宽”(以字节为单位的数据吞吐量):由于连续地址中的距离很长,RAM 缓存完全低效正在接受治疗。据我了解,这里重要的是 RAM 延迟而不是其带宽(这是传输大连续数据块时的吞吐量)。

场景是这样的(假设您使用 64 位 = 8 字节的值):

  • 您在某个地址读取数据
  • 进行一些轻量级 CPU 计算(这样 CPU 就不会成为瓶颈)
  • 然后您在距离第一个地址很远的新地址读取数据
  • 等等

我想了解吞吐量(以字节为单位)。假设 RAM 具有典型 DDR3 13 ns 延迟的简单计算得出的带宽为 8 B/13 ns = 600 MB/s。但这提出了几点:

  • 这个推理(至少是示意性的)正确吗?
  • 是获取数据的时间正好是 RAM 延迟,还是您必须添加一些与缓存、CPU 或任何中间组件相关的时间?你知道多少钱吗?
  • 在多个线程中执行此操作时会发生什么?所有线程的带宽是否为 600 MB?

【问题讨论】:

标签: multithreading cpu ram bandwidth latency


【解决方案1】:

...有效内存“带宽”...在最坏的情况下从主内存到 CPU:

有两种“最糟糕”的情况:不使用(错过)CPU 缓存的内存访问和访问过远地址且无法重用打开的 DRAM 行的内存访问。

内存缓存

缓存不是 RAM 的一部分,它是 CPU 的一部分,并命名为 CPU cachememory hierarchy 的顶部)。

由于处理的连续地址中的距离很长,因此效率完全低下。

现代 CPU 缓存有许多内置的hardware prefetchers,可以检测多个内存访问之间的非随机步骤。许多预取器会检测对齐的 4 KB 页面内的任何步骤:如果您访问地址 1,则地址 1 + 256 字节,然后 L1 预取器将开始访问地址 1 + 256*2、地址 1 + 256*3 等。一些预取器可能会尝试预测超出 4 KB 范围。因此,仅在访问之间使用长距离可能是不够的。 (预取器可能被禁用https://software.intel.com/en-us/articles/disclosure-of-hw-prefetcher-control-on-some-intel-processors

据我了解,这里重要的是 RAM 延迟而不是带宽

是的,在某些模式下 RAM 访问受到延迟限制。

场景是这样的(假设您使用 64 位 = 8 字节的值):

您可以使用 8 个字节的值;但是您应该考虑内存和缓存与更大的单元一起使用。现代 DRAM 内存具有 64 位(8 字节)宽的总线(对于 ECC,64+8 为 72 位),并且许多事务可能使用多个总线时钟周期(DDR4 SDRAM 中的突发预取使用 8n - 8 * 64 位。 CPU 缓存和内存控制器之间的许多事务也更大,大小为完整的cache line 或缓存线的一半。 Typical cache line is 64 bytes.

you read data at an address
make some light weight CPU computation (so that CPU is not the bottleneck)
then you read data at new address quite far-away from the first one

这种方法不太适合现代无序 CPU。 CPU 可能会推测性地重新排序机器命令并在当前内存访问完成之前开始执行下一次内存访问。

cpu 缓存和内存延迟的经典测试(来自 lmbench http://www.bitmover.com/lmbench/lat_mem_rd.8.html 的 lat_mem_rd 和许多其他测试)使用填充了一些特殊伪随机指针模式的内存数组;读取延迟的测试就像 (https://github.com/foss-for-synopsys-dwc-arc-processors/lmbench/blob/master/src/lat_mem_rd.c#L95)

char **p = start_pointer;
for(i = 0; i < N; i++) {
      p = (char **)*p; 
      p = (char **)*p; 
  ... // repeated many times to hide loop overhead
      p = (char **)*p; 
}

因此,下一个指针的地址存储在内存中; cpu 无法推测下一个地址并开始下一个访问,它将等待从缓存或内存中读取数据。

我想了解吞吐量(以字节为单位)。

可以用每秒访问量来衡量;对于字节访问、字访问或 8 字节访问,将有相似的访问次数/秒,吞吐量(字节/秒)将乘以所使用的单元。

有时会测量到类似的值 - GUPS - guga-updates per second(内存中的数据被读取、更新和写回),测试为 Random Access。本次测试可以使用数百(或数万)台PC计算集群的内存-查看http://icl.cs.utk.edu/hpcc/hpcc_results.cgi?display=combo中的GUP/s列

假设 RAM 具有典型 DDR3 13 ns 延迟的简单计算得出的带宽为 8 B/13 ns = 600 MB/s。但这提出了几点:

RAM 有几个延迟(计时) - https://en.wikipedia.org/wiki/Memory_timings

而 13 ns CAS 仅在您访问打开的行时才相关。对于随机访问,您通常会访问封闭的行,并将 T_RCD 延迟添加到 CAS。

【讨论】:

  • 谢谢。它使画面更清晰。知道在进入主内存之前缓存未命中是否会引入一些延迟吗? Sandbridge 文档对我来说有点太神秘了……
  • @BenoitSanchez, 7-cpu.com/cpu/SandyBridge.html 文档说内存访问是“RAM 延迟 = 28 个周期 + 49 ns(对于打开的 RAM 页面)。”和“RAM 延迟 = 28 个周期 + 56 ns(对于随机 RAM 页)。”其中 28 个周期用于完整的 L3 缓存延迟(来自内存的数据通过 L3、L2 和 L1 管道转发)。 28 个周期来自 3.3 GHz 的 CPU 频率(因为高速缓存为其计时),因此 L3 延迟增加了 10 ns,内存延迟增加了 50-56 ns。 60-66 ns 相当于每秒 15-16 百万次访问;对于 1 字节访问 = 16 MB/s;对于 4 字节访问 = 64 MB/s;对于 8B =128
  • 在多线程的情况下,会用到一些bank并行,也会有bank争用。您可能会期望增加 4 倍或 8 倍(查看您拥有的银行数量)
猜你喜欢
  • 1970-01-01
  • 2017-06-26
  • 1970-01-01
  • 2012-11-09
  • 2013-06-19
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多