我有一些性能关键代码会在极不可能的情况下崩溃和刻录(例如,当中间double
等于0.0
时,该双倍的可能性不会比任何其他价值)。
当然,一种选择是吹口哨并忽略角落的情况,并祈祷它永远不会出现。但是如果可能的话,我想抓住它;另一方面,我并不太热衷于将条件添加到性能关键代码中。添加表格检查是否有任何技巧
if(val == 0.0)
{
// extremely unlikely code path
}
以最小化性能损失的方式?在一些编译器上,它可以通过CPU分支预测提示,但我听说这些对现代处理器不再有任何影响吗?
答案 0 :(得分:3)
使用可能,不太可能
在Linux内核中,它们被定义为
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
__builtin_expect宏是使用分支预测的GCC特定宏;它们告诉处理器条件是否可能是真的,这样处理器就可以在正确的方面预取指令"分支机构。
您应该将定义包装在ifdef中以确保在其他编译器上进行编译:
#ifdef __GNUC__
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
答案 1 :(得分:1)
您可能希望查看this question的答案。 如果你有任何在Windows上运行的概念,你可能想要 look at this也是如此。
看看分支预测的解释几乎肯定值得您花些时间 在this question的答案中。 (请注意,在该问题中观察到的行为不仅在编译器之间,而且在各种语言中都很常见,如Java和C ++中的示例所示。)
据我了解,
的问题if (val == 0.0)
{
// extremely unlikely code path
}
是分支预测器最初会假设条件为真,
也就是说,它将开始执行你极不可能的事情
第一次遇到这种情况时的代码路径。
分支的成本并不是val == 0.0
的评估。
但是当val == 0.0
证明是假的时候退出不太可能的分支的成本。
然而,在它遇到分支语句几次之后,
分支预测器将猜测条件为假,并执行
就像你告诉编译器" false"分支是
可能的人。
在这样的环境中运行,您不需要一般地优化分支, 因为它会为您优化。 您可以对分支进行的唯一优化是优化第一次 当它被调用时(可能还有几次,具体取决于什么 分支预测算法寻找)。 如果您的应用程序对性能至关重要,那么您无法承担该成本 对于运行函数的前一两次,你应该用C ++编程吗?
为了鼓励分支预测器第一次采取正确的路径, 但是,你可以写
if (val != 0.0)
{
// stuff you want to do almost every time
}
else
{
// extremely unlikely code path
}
这有两个好处:首先,它是便携式的,
第二,它得到了极不可能的代码
让你可以更容易地看到代码通常应该做的事情。
缺点是它增加了另一级别的缩进
// stuff you want to do almost every time
。
我承认自己已经使用过这种技术。
答案 2 :(得分:0)
你需要知道在那里有条件是否实际上在很大程度上损害了性能。 This is the method I use.
我倾向于假设如果在时间关键代码中存在性能问题,那么应该追究实际问题。 在诊断证明之前,不要假设有条件的伤害。