【问题标题】:Why is prefetch speedup not greater in this example?为什么在这个例子中预取加速不是更大?
【发布时间】:2014-07-07 14:52:42
【问题描述】:

this excellent paperUlrich Drepper 的 6.3.2 中,写了关于软件预取的文章。他说这是“熟悉的指针追踪框架”,我收集的是他之前给出的关于遍历随机指针的测试。在他的图表中,当工作集超过缓存大小时性能下降是有道理的,因为那时我们将越来越频繁地使用主内存。

但是为什么预取在这里只有 8% 的帮助呢?如果我们准确地告诉处理器我们想要加载什么,并且我们提前告诉它足够远(他提前 160 个周期),为什么缓存不能满足每个访问?他没有提到他的节点大小,所以当只需要一些数据时,可能会因为获取一整行而造成一些浪费?

我正在尝试将 _mm_prefetch 与一棵树一起使用,但我没有看到明显的加速。我正在做这样的事情:

_mm_prefetch((const char *)pNode->m_pLeft, _MM_HINT_T0);
// do some work
traverse(pNode->m_pLeft);
traverse(pNode->m_pRight)

现在这应该只有助于一侧的遍历,但我认为性能没有任何变化。我确实将 /arch:SSE 添加到项目设置中。我正在使用带有 i7 4770 的 Visual Studio 2012。在this thread 中,一些人还谈到预取仅能获得 1% 的加速。为什么预取对随机访问主存中的数据不起作用?

【问题讨论】:

  • 在现代 CPU 上很难击败自动预取,除非 (a) 您有不寻常/可预测的访问模式,(b) 您真的知道自己在做什么, (c) 您已准备好针对特定 CPU 进行调整,并且 (d) 您有可用的内存带宽。
  • 嗯,但是图表呢?如果他准确地告诉处理器他接下来要读取什么地址,他如何仍然获得 1000 个周期/元素?似乎在稳定状态下,无论工作集大小如何,他都应该回落到 200 个周期/节点以下。当他在每个节点上进行工作时,所有的获取都应该发生。我知道我的心智模型一定遗漏了很多,只是不确定是什么。
  • @Philip 不,因为随着您的数据集变大,您将从主内存中预取,缓存命中次数会减少很多。小型工作集可能完全驻留在缓存中。
  • @Anycom,对,但预取的整个想法是在需要之前从主内存启动传输。在他的示例中,他在每个节点上执行 160 个工作周期。不是 200 个周期的数量级的主存储器获取吗?那么,如果您在需要 160 个周期之前启动 200 个周期,为什么需要 1000 个周期呢? paul-r 和 Ulrich 报告的内容与我的经验一致,没有太大帮助,但似乎应该有很大帮助。
  • @Philip 这不仅仅是原始内存延迟,例如 TLB 未命中非常昂贵。

标签: visual-studio-2012 intel sse


【解决方案1】:

您要预取的节点有多大?因为 prefetcher 不能超过 4K 页面边界:如果你的节点比较大,你只会预加载一部分数据,而剩下的数据只有在一次未命中事件后才会加载。

【讨论】:

    【解决方案2】:

    预取不能增加你的主存的吞吐量,它只能帮助你更接近于使用它。

    如果您的代码甚至在从链表中的下一个节点请求数据之前就在计算上花费了很多周期,那么它不会使内存保持 100% 繁忙。知道地址后立即预取下一个节点会有所帮助,但仍有上限。上限大约是您在没有预取的情况下得到的,但在加载节点和追逐指向下一个节点的指针之间没有工作。即内存系统 100% 的时间获取结果。

    根据那篇论文中的图表,即使在 160 个工作周期之前进行预取,也不足以提前准备好数据。随机访问延迟显然非常慢,因为 DRAM 必须打开一个新页面、一个新行和一个新列。

    我没有详细阅读这篇论文,看他如何提前预取多个步骤,或者理解为什么预取线程比预取指令更有帮助。这是在 P4 上,而不是在 Core 或 Sandybridge 微架构上,我认为预取线程仍然不是问题。 (具有超线程的现代 CPU 具有足够的执行单元和足够大的缓存,因此在每个内核的两个硬件线程上运行两个独立的东西实际上是有意义的,这与 P4 中不同的是,在 P4 中,通常未用于超线程的额外执行资源较少。尤其是. I-cache 在 P4 中是个问题,因为它只有很小的跟踪缓存。)

    如果您的代码已经基本上立即加载下一个节点,预取不能神奇地使其更快。预取有助于增加 CPU 计算和等待内存之间的重叠。或者也许在您的测试中,->left 指针从您分配内存时开始大部分是连续的,所以硬件预取有效?如果树足够浅,在向左下降之前预取 ->right 节点(进入最后一级缓存,而不是 L1)可能是一个胜利。

    软件 仅当 CPU 硬件预取器无法识别访问模式时才需要预取。 (它们非常好,可以以相当大的步幅发现模式。并跟踪大约 10 个前向流(增加地址)。请查看http://agner.org/optimize/ 了解详细信息。)

    【讨论】:

      猜你喜欢
      • 2013-06-13
      • 2013-05-15
      • 1970-01-01
      • 2012-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-23
      • 1970-01-01
      相关资源
      最近更新 更多