【问题标题】:Reducing Instruction Cache misses (in C++)减少指令缓存未命中(在 C++ 中)
【发布时间】:2012-11-01 03:48:50
【问题描述】:

假设我有一个 C++ 类,其实现如下所示:

// ...

MyClass::iterativeFunction() {
     for (int i = 0; i < 1000000; i++) {
          performAction(i);
     }
}

MyClass::performAction(int index) {
     // Block of code (non-inline-able)
}

// ...

在 C++ 级别,我是否可以控制这些方法的空间局部性,还是只希望编译器会注意到相关方法并相应地优化其程序集?理想情况下,我希望它们彼此相邻,以便将它们一起加载到指令缓存中,但我不知道如何让编译器知道我真的希望发生这种情况。

【问题讨论】:

  • “我希望它们彼此相邻,以便它们一起加载到指令缓存中。”这不是任何现代 CPU 的指令缓存的工作方式。它不会仅仅因为它恰好靠近其他代码而获取代码。它获取代码是因为调用了该代码。
  • 将“执行操作”标记为内联/_forceinline/__pleasepleaseinline?
  • 通过全程序优化,编译器很可能会发现MyClass::performAction 的唯一调用者是iterativeFunction,并且仍然内联它。只有一个调用者的函数的内联阈值要低得多。
  • 除非您有 >4kb 的可执行代码,在这种情况下,代码位置可能很重要,尽管处于完全不同的级别。

标签: c++ localityofreference


【解决方案1】:

在任何一种情况下,代码在进入缓存之前都无法运行。在任何一种情况下,对于代码流去向的 CPU 来说都是同样明显的,因为流是无条件的。所以它不会有任何区别。现代代码缓存不会在地址空间中提前获取,而是在指令流中提前获取,跟随无条件分支并根据需要预测条件分支。

所以没有理由关心这个。不会有任何区别。

【讨论】:

  • 嗯,好的,谢谢。我没有意识到指令获取遵循指令流。这让我的生活轻松多了。
【解决方案2】:

从技术上讲,没有。但是,在现代处理器上,您通常不需要像担心数据缓存那样担心指令缓存,除非您有一个非常大的可执行文件或到处都有非常可怕的分支。

原因是缓存行只有大约 64 字节长,这意味着如果您的方法大于 64 字节(并且确实如此),即使它们直接是 next 也需要将它们加载到多个缓存条目中在物理内存中相互连接。

【讨论】:

  • 在为任何现代 CPU 编码时,像 OP 一样思考是没有意义的。
【解决方案3】:

如果您需要这种级别的控制和优化,那么 C++ 不适合您。

但您的问题的实际答案是“否”。

【讨论】:

    【解决方案4】:

    不,据我所知,您无法指定方法的位置。 如果 C++ 允许嵌套过程,那将是确保被调用过程是本地的一种方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-05
      • 2015-08-27
      • 2022-01-20
      • 2010-10-02
      • 2020-10-06
      • 1970-01-01
      • 1970-01-01
      • 2017-10-03
      相关资源
      最近更新 更多