21

似乎预取使用的一般逻辑是可以添加预取,前提是代码正忙于处理,直到预取指令完成其操作。但是,如果使用过多的预取指令,似乎会影响系统的性能。我发现我们首先需要有没有预取指令的工作代码。稍后我们需要在代码的各个位置对预取指令进行各种组合并进行分析,以确定由于预取而实际可以改善的代码位置。有没有更好的方法来确定应该使用预取指令的确切位置?

4

3 回答 3

19

在大多数情况下,预取指令几乎没有好处或没有好处,在某些情况下甚至会适得其反。大多数现代 CPU 都有一种自动预取机制,该机制运行良好,因此添加软件预取提示几乎无法实现,甚至会干扰自动预取,并且实际上会降低性能。

在一些罕见的情况下,例如当您流式传输大量数据而您几乎没有进行实际处理时,您可能会设法通过软件启动的预取来隐藏一些延迟,但很难做到正确 - 您需要在您将要使用数据之前启动数百个周期的预取 - 做得太晚,您仍然会出现缓存未命中,做得太早,您的数据可能会在您准备好使用它之前从缓存中被逐出。通常这会将预取放在代码的一些不相关的部分,这不利于模块化和软件维护。更糟糕的是,如果您的架构发生变化(新的 CPU、不同的时钟速度等),例如 DRAM 访问延迟增加或减少,您可能需要将预取指令移动到代码的另一部分以保持它们的有效性。

无论如何,如果你觉得你真的必须使用预取,我建议在任何预取指令周围使用#ifdefs,这样你就可以在有和没有预取的情况下编译你的代码,看看它是否真的有助于(或阻碍)性能,例如

#ifdef USE_PREFETCH
    // prefetch instruction(s)
#endif

不过,总的来说,我建议您在完成所有更高效和明显的工作之后,将软件预取放在次要位置,作为最后的微优化手段。

于 2010-06-26T07:05:07.600 回答
6

甚至考虑预取代码性能肯定已经是一个问题。

1:使用代码分析器。尝试在没有分析器的情况下使用预取是浪费时间。

2:每当您在关键位置发现异常缓慢的指令时,您就有了预取的候选者。通常,实际问题出在慢行之前的内存访问,而不是分析器所指示的慢行。找出导致问题的内存访问(并不总是那么容易)并预取它。

3 再次运行您的分析器,看看它是否有任何不同。如果没有取出来。有时我以这种方式将循环速度提高了 300% 以上。如果您有一个循环以非顺序方式访问内存,这通常是最有效的。

我完全不同意它在现代 CPU 上的用处不大,我发现完全相反,虽然在旧 CPU 上预取大约 100 条指令是最佳的,但现在我把这个数字更像 500。

于 2012-05-02T00:08:11.413 回答
1

当然,您必须尝试一下,但并不是说您需要在需要数据之前获取一些百周期(100-300)。L2 缓存足够大,预取的数据可以在那里停留一段时间。

这种预取在循环之前非常有效(当然是几百个循环),特别是如果它是内部循环并且循环每秒启动数千次甚至更多次。

此外,对于您的快速 LL 实现或树实现而言,预取可能会获得可衡量的优势,因为 CPU 不知道 jet 很快需要数据。

但是请记住,预取指令会占用一些解码器/队列带宽,因此过度使用它们会损害性能。

于 2010-07-16T21:26:40.653 回答