我正在编写一些音频代码,其中基本上所有内容都是一个小循环。据我所知,分支预测失败是一个足够大的性能问题,我很难保持代码分支的自由。但是只有这么远的时间才能带我,这让我想知道不同类型的分支。
在 c 中,固定目标的条件分支:
int cond_fixed(bool p) {
if (p) return 10;
return 20;
}
并且(如果我正确理解这个问题),无条件分支到变量目标:
struct base {
virtual int foo() = 0;
};
struct a : public base {
int foo() { return 10; }
};
struct b : public base {
int foo() { return 20; }
};
int uncond_var(base* p) {
return p->foo();
}
是否存在性能差异?在我看来,如果这两种方法中的一种明显快于另一种,编译器只需将代码转换为匹配即可。
对于那些分支预测非常重要的情况,了解哪些关于性能的细节是有用的?
编辑:x: 10?20
的实际操作只是一个占位符。分支之后的实际操作至少足够复杂,以至于两者都做效率低下。此外,如果我有足够的信息来明智地使用__builtin_expect
,分支预测在这种情况下将不是问题。
你没有提到你的编译器。我曾经在一个性能关键的应用程序中使用过GCC(实际上是我大学的一次竞赛),我记得GCC有__builtin_expect
宏。我在代码中检查了所有条件,最终获得了5-10%的加速,我发现这是惊人的,因为我几乎关注了我所知道的一切(内存布局等),而且我没有改变算法本身的任何内容。
顺便说一下,这个算法是一个非常基本的深度搜索。我在Core 2 Duo上运行了它,但不确定是哪一个。
旁注:如果你有一个代码
if (p) a = 20; else a = 10;
然后没有任何分支。编译器正在使用条件移动(请参阅:为什么条件移动不容易受到分支预测失败的攻击?)
如果语句更多地依赖于分支预测,而v表查找更多地依赖分支目标预测,那么
分支目标预测(BTP)与分支预测(BP)不同。我知道BTP会找到分支将跳转到的位置,而BP只是决定可能采取哪个分支。 BTP依赖BP吗,如果BTP不使用BP来预测哪个分支被采用,它怎么可能知道分支的目标呢? 我不明白为什么会有这么大的差异?一旦分支被预测为被占用,找到目标并不像读取指令中的地址一样简单吗?
编辑:我的困惑出现了,因为通过预测哪个分支,你肯定也在有效地进行目标预测?? 这个问题与我关于这个主题的第一个问题有内在联系: 分支预测与分支目标预测 无限循环 语句 或语句 语句的“then”子句结尾(跳过子句) 非虚函数调用 从函数返回 虚函数调用 函数指针调用 语句(如果编译为跳转表) 语句 语句(如果编译成一系列语句) 循环条件测试 和运算符 三元运算符 null 如果我有以下代码: (B
我的代码经常调用具有多个(不可预测的)分支的函数。当我分析时,我发现这是一个小瓶颈,大部分CPU时间用于条件JMP。 考虑以下两个函数,其中原始函数有多个显式分支。 这是一个新函数,我试图在其中删除导致瓶颈的分支。 然而,当我分析新代码时,性能只提高了大约20%,而且调用本身(对mem_funcs数组中的一个func)花费了很长时间。 第二个变量仅仅是一个更隐含的条件吗,因为CPU仍然无法预测将要
我正在读一本关于计算机体系结构的书,我在这一章讨论分支预测。有一个小练习,我很难把我的头缠绕在它周围。 考虑以下内部for循环 ------>内循环: b)1位分支预测缓冲器会改善性能吗(与a相比)?假设第一个预测是“未采取”,并且没有其他分支映射到该条目。 ----假设第一个预测是“不采取”,如果预测错误,则1位预测器反转该位。所以它将是NT/T/T。这是否使它具有与问题a)相同的性能?有1个未
我的问题是它们如何在现代CPU架构中共存和协同工作?