【问题标题】:How can I prefetch infrequently used code?如何预取不常用的代码?
【发布时间】:2013-04-25 15:24:42
【问题描述】:

我想将一些代码预取到指令缓存中。代码路径不经常使用,但我需要它在指令缓存中,或者至少在 L2 中,因为在极少数情况下使用它。我提前通知了这些罕见的情况。 _mm_prefetch 是否适用于代码?有没有办法在缓存中获取这个不经常使用的代码?对于这个问题,我不关心可移植性,所以即使 asm 也会这样做。

【问题讨论】:

  • 你为什么要这个?听起来你减慢了你为租约编写代码的所有其他部分,就像被使用的部分一样。总的来说,我认为一切都会执行得更慢。
  • @andre 一个函数可能很少使用,但在使用时仍然对延迟非常敏感。
  • @andre 当有“这些罕见情况的提前通知”时,这可能是一种有用的技术。一些处理器有专门的指令。
  • 是的,我明白我想要什么。这适用于对延迟非常敏感的操作。想象一下,您正试图从一些传感器数据中识别爆炸,您需要尽快做出反应。谢天谢地,反应非常罕见,但感应/检查等非常频繁。
  • 相关:Bring code into the L1 instruction cache without executing it 想要做同样的事情,但要进行微基准测试,而不是在 L1I$ 中保持对延迟敏感的函数热。不过,您可以使用其中一些想法来保持 L1I$ 的准备状态,同时等待您需要做出反应的事件。

标签: c++ low-latency prefetch


【解决方案1】:

答案取决于您的 CPU 架构。

也就是说,如果您使用 gcc 或 clang,您可以使用 __builtin_prefetch 指令尝试生成预取指令。在 Pentium 3 和更高版本的 x86 类型架构上,这将生成一个PREFETCHh 指令,该指令请求加载到数据缓存层次结构中。由于这些架构具有统一的 L2 和更高的缓存,因此可能会有所帮助。

函数如下所示:

__builtin_prefetch(const void *address, int locality);

locality 参数应在 0...3 范围内。假设locality 直接映射到PREFETCHh 指令的h 部分,您希望传递1 或2,这要求将数据加载到L2 和更高的缓存中。请参阅Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 2B: Instruction Set Reference, M-Z (PDF) 第 4-277 页。 (Find other volumes here.)

如果您正在使用另一个没有__builtin_prefetch 的编译器,请查看它是否具有_mm_prefetch 函数。您可能需要包含一个头文件才能获得该功能。例如,在 OS X 上,该函数和 locality 参数的常量在 xmmintrin.h 中声明。

【讨论】:

  • 谢谢,这类似于 gcc 的 _mm_prefetch 操作,对吧?我想我需要预取更多我的函数才能真正看到任何好处。
  • 我相信 _mm_prefetch 是 gcc 和 clang 下 __builtin_prefetch#definePREFETCHh 指令可能请求一个缓存行,因此您将需要多条指令,除非您的函数适合一个缓存行(可能是 64 字节)。
  • 请注意,即使 L2 在代码和数据之间统一(现在经常如此),TLB 也很少共享。因此,存在时的预取指令很可能会使用数据 TLB(英特尔文档并不明确,但它在任何地方都使用“数据”一词)。因此,当代码开始运行预取字节时,它可能会产生 TLB 未命中,但解决它所需的条目将已经在 L2 中准备好(页面遍历条目像普通数据一样存储在 L2 中)。
  • 我没有在 gcc 上尝试过,但是在 clang 上 locality 0 映射到 prefetcht0 和 1 到 prefetchw。该参数不接受其他值。
【解决方案2】:

没有任何(官方 [1] x86)指令来预取代码,只有数据。我发现这是一个相当奇怪的用例,其中代码路径是事先知道的,但很少执行,并且预取代码有很大的好处。很高兴了解您在哪里得出的结论,即为这种特殊情况预加载代码有很大的好处,因为它不仅需要分析代码在没有被命中时显着变慢很长一段时间,但还要确定在处理器可以通过其正常的加载代码机制预取代码之前实际加载代码的空闲总线周期。

您可以使用prefetch 指令获取 L2,该指令通常在 I 和 D 缓存之间共享。

[1] 我知道有一些“秘密”指令允许处理器操作缓存内容,但由于这些指令需要大量额外的工作,即使您可以在用户模式代码中使用它们 [而且我期望这不是一些内核模式代码]。

【讨论】:

  • L2 缓存在代码和数据之间共享,因此使用相同的指令应该将其预取到 L2。
  • 为此添加了评论。
  • 我确实尝试过 _mm_prefetch(&func, _MM_HINT_T1) 也许我需要进一步预取到函数中。
  • 你测量过差异吗?它起到了什么作用?你确定内存是存在的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-09
  • 1970-01-01
  • 2015-11-17
  • 2020-04-05
  • 1970-01-01
相关资源
最近更新 更多