this excellent paper的6.3.2中,Ulrich Drepper写了关于软件预取的信息。他说这是“熟悉的指针追踪框架”,我收集到的是他较早前对遍历随机指针所做的测试。在他的图中有道理,当工作集超过缓存大小时,性能会降低,因为那样我们将越来越频繁地访问主内存。

但是,为什么预取在这里只能提供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添加到项目设置中。我将Visual Studio 2012与i7 4770结合使用。在this thread中,一些人还谈到预取只能使速度提高1%。为什么预取对于随机访问主内存中的数据不起作用呢?

最佳答案

预取不能增加主内存的吞吐量,只能帮助您进一步使用所有内存。

如果您的代码在甚至从链表中的下一个节点请求数据之前就花费了许多计算周期,那么它就不会使内存100%处于繁忙状态。一旦知道地址,预取下一个节点将有所帮助,但是仍然存在上限。上限大约是您无需预取即可获得的上限,但是在加载节点和将指针追到下一个节点之间没有任何工作。即内存系统在100%的时间内获取结果。

根据该论文的图表,即使在160个工作周期之前进行预取也不足以使数据准备就绪。由于DRAM必须打开一个新页,一个新行和一个新列,因此随机访问延迟显然很慢。

我没有足够详细地阅读该论文,无法了解他如何可以预取 future 的多个步骤,也无法理解为什么预取线程比预取指令更能提供帮助。这是在P4上,而不是在Core或Sandybridge微体系结构上,而且我认为预取线程仍然不是问题。 (具有超线程的现代CPU具有足够的执行单元和足够大的缓存,因此在每个内核的两个硬件线程上运行两个独立的东西实际上是有意义的,与P4不同,P4中通常没有多余的执行资源可供超线程利用。) I缓存在P4中是个问题,因为它只有这么小的跟踪缓存。)

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

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

关于visual-studio-2012 - 为什么在此示例中预取速度没有提高?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23741246/

10-11 23:00