【问题标题】:branch prediction on a function pointer函数指针上的分支预测
【发布时间】:2014-12-02 02:20:47
【问题描述】:

我有一个反复运行的循环。该循环内的逻辑取决于程序所处的模式。为了提高性能,我认为可以初始化一个函数指针数组functionPtr [],这样就可以调用运行正确逻辑的functionPtrmode。循环将在许多周期内保持相同的模式(这个数字是未知的,但有数千个)。该程序仅在 intel x64 机器上运行,不需要可移植性。

我希望 CPU 会利用分支预测,但由于我的分支不是有条件的(在汇编级别上),但分支的位置确实取决于变量(functionPtr+mode)。 CPU 是否会尝试计算 functionPtr+mode 并在流水线中开始拉入这些指令?

【问题讨论】:

  • 与分支预测无关,但应该没问题 - 即使是间接函数调用也不应该出现管道停顿。
  • 我看到你正在使用 c++。你不能创建两个继承自同一个接口的类,然后根据模式实例化正确的类吗?
  • 如果只有少数情况,您可以将循环中的函数作为模板参数。在运行时选择(例如 switch 语句),一个包含循环的模板函数。请注意,这会增加代码大小。
  • @Vincent,我认为这有同样的问题,如果你有 foo[mode].run() 那么你仍然有一个指向 foo[mode] 的指针来计算和一个函数来调用。在我的情况下,无论哪种方式 run() 调用中所需的信息都会修改将在下一次 run() 调用中使用的变量,即使是不同的模式,所以将其保留在一个类中是有意义的。
  • @Neil,当模式在整个循环中不可预知地切换时,这听起来好像不起作用。

标签: c++ function-pointers branch-prediction


【解决方案1】:

是的,最近的处理器可以(至少是类似的)间接跳转的分支预测。

从 Pentium(英特尔第一个进行分支预测)到第一个 Pentium IV,所有用于间接分支的都是分支目标缓冲区 (BTB)。这意味着当(且仅当)目标与前一个目标完全相同时,他们会正确“预测”此类分支 - 这听起来适合您的情况。

从 Pentium M/Prescott(最后的 Pentium IV)开始,英特尔改进了间接跳转的分支预测,以使用两级自适应预测器。如果我正确理解了您的问题(即,您的循环将在多次连续迭代中使用相同的目标执行,而这些正是您所关心的)即使只是 BTB 也足以满足您的目的。如果(例如)您在连续数字的最低有效位上进行分支,那么两级预测器将变得更加有用,因此您有一个可预测的模式,即在一次迭代中跳转到一个目标,并在下一次迭代中跳转到另一个目标。对于这样的模式,单独的 BTB 总是会错误地预测分支,但当前处理器中的两级预测器会正确预测(在前几次迭代之后,因此可以检测到模式)。

【讨论】:

    【解决方案2】:

    来自 Intel、AMD 和 VIA CPU 的微架构 汇编程序员和编译器制造商的优化指南

    http://www.agner.org/optimize/microarchitecture.pdf

    第 3.7 节(对于 Sandy Bridge,其他处理器在其他部分) 间接跳转和调用的模式识别 间接跳转和间接调用(但不是返回)使用与分支指令相同的两级预测器进行预测。

    指向函数的指针是间接调用。

    【讨论】:

      【解决方案3】:

      分支预测是针对实际分支,直到评估分支时我们才知道,它告诉接下来要执行哪条指令。但是,由于在您的代码中,下一条指令取决于我们所处的模式,因此不需要任何预测,它们也不会在管道中等待。

      鉴于模式更改和指令选项之间有足够的时间,流水线每次都会成功地获取正确的指令,而无需任何额外的努力。

      【讨论】:

      • 间接分支仍然需要预测。当给定分支每次都相同时,这是一个简单的预测,但它仍然消耗 BTB(分支目标缓冲区)中的条目。来自内存/寄存器的数据在解码时不可用,更不用说在解码前的获取时,所以即使数据最近没有改变,仍然需要预测。除非您使用自修改机器代码来重写相关分支指令,否则目标在需要它的 CPU 部分并不容易获得。
      猜你喜欢
      • 2019-01-27
      • 1970-01-01
      • 2020-05-04
      • 2014-03-25
      • 2011-09-28
      • 1970-01-01
      • 2014-04-25
      • 2014-03-03
      相关资源
      最近更新 更多