预取用法的一般逻辑似乎是,如果代码忙于处理直到预取指令完成其操作,则可以添加预取。但是,似乎如果使用过多的预取指令,那么它会影响系统的性能。我发现我们需要先获得没有预取指令的工作代码。稍后我们需要在各种代码位置中进行预取指令的各种组合,并进行分析以确定由于预取而实际可能改进的代码位置。有没有更好的方法来确定应该使用预取指令的确切位置?
答案 0 :(得分:17)
在大多数情况下,预取指令很少或没有任何好处,在某些情况下甚至会适得其反。大多数现代CPU具有自动预取机制,该机制运行良好,添加软件预取提示几乎没有,甚至干扰自动预取,实际上可以降低性能。
在极少数情况下,例如当您在流式传输大量数据时,您实际上只进行了很少的实际处理,您可能会设法通过软件启动的预取来隐藏一些延迟,但很难做到这一点 - 你需要在使用数据之前启动预取几百个周期 - 这样做太晚了,你仍然得到一个缓存未命中,过早做,你的数据可能会在你准备好使用之前从缓存中逐出。通常这会将预取放在代码的某些不相关的部分中,这对于模块化和软件维护是不利的。更糟糕的是,如果您的架构发生变化(新的CPU,不同的时钟速度等),使得DRAM访问延迟增加或减少,您可能需要将预取指令移到代码的另一部分以保持其有效。
无论如何,如果你觉得你真的必须使用预取,我建议#ifdefs围绕任何预取指令,以便你可以使用和不使用预取来编译你的代码,看看它是否实际上有助于(或阻碍)性能,例如
#ifdef USE_PREFETCH
// prefetch instruction(s)
#endif
总的来说,在你完成所有更高效和更明显的工作之后,我会建议将软件预取作为最后的微优化。
答案 1 :(得分:4)
甚至考虑预取代码性能必须已经成为一个问题。
1:使用代码分析器。尝试在没有探查器的情况下使用预取是浪费时间。
2:每当你在一个异常缓慢的关键位置找到指令时,你就有了预取的候选者。实际问题通常是在慢速行之前的行上的内存访问,而不是分析器指示的慢行。找出造成问题的内存访问(并不总是很容易)并预取它。
3再次运行您的探查器,看看它是否有任何区别。如果它没有把它拿出来。 有时我以这种方式加速循环> 300%。如果你有一个以非顺序方式访问内存的循环,这通常是最有效的。
我完全不同意它在现代CPU上没那么有用,我发现完全相反,虽然在较旧的CPU预取大约100条指令是最佳的,这一天我把这个数字更像是500。
答案 2 :(得分:1)
当然,你需要稍微尝试一下,但不需要在需要数据之前获取somme houndred周期(100-300)。 L2缓存很大,预取的数据可以保留一段时间。
这个预取在一个循环(当然是几个循环的循环)之前是非常有效的,特别是如果它是内循环并且循环每秒启动数千次和更多次。
此外,对于低速快速LL实现或Tree实现可以预取获得可衡量的优势,因为CPU不知道喷射是否需要尽快获得数据。
但请记住,预取指令会占用一些解码器/队列带宽,因此过度使用它们会因为这个原因而损害性能。