有效,极不可能的条件?

时间:2014-11-30 20:33:27

标签: c++ performance

我有一些性能关键代码会在极不可能的情况下崩溃和刻录(例如,当中间double等于0.0时,该双倍的可能性不会比任何其他价值)。

当然,一种选择是吹口哨并忽略角落的情况,并祈祷它永远不会出现。但是如果可能的话,我想抓住它;另一方面,我并不太热衷于将条件添加到性能关键代码中。添加表格检查是否有任何技巧

if(val == 0.0)
{
    // extremely unlikely code path
}

以最小化性能损失的方式?在一些编译器上,它可以通过CPU分支预测提示,但我听说这些对现代处理器不再有任何影响吗?

3 个答案:

答案 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.

我倾向于假设如果在时间关键代码中存在性能问题,那么应该追究实际问题。 在诊断证明之前,不要假设有条件的伤害。