Search code examples
c++attributeslanguage-lawyerc++20

What is the default probability of [[likely]]? Is it possible to change it?


What is the default probability of [[likely]]? Is it possible to change it?

Backgound: GCC has the following built-in functions:

  • long __builtin_expect(long exp, long c): the probability that a __builtin_expect expression is true is controlled by GCC's builtin-expect-probability parameter, which defaults to 90%.
  • long __builtin_expect_with_probability(long exp, long c, double probability): the last argument, probability, is a floating-point value in the range 0.0 to 1.0, inclusive.

What is the C++ definition of the term "likely"? 51%? 90%? What does the term "arbitrarily (un)likely" mean?


Solution

  • There is no "probability" for these things. They tell the compiler to rearrange code and tests around branches to optimize for the case where one path is more often taken than another. But that's all.

    These are not everyday tools you should be tossing into every loop and if statement. These are micro-optimization tools that are best used when one has a clear performance target in mind and one sees that the compiler is generating sub-optimal machine code in a performance-critical section of code. Only then do you employ these tools. And even then, you need to check the generated code to see if they fixed the problem you're trying to solve.

    These are compiler tweaks for cases where the compiler's usual methods of code generation around a branch does not produce optimal code. It's not about probability; it's about micro-optimization.

    Here is a quote from the paper adding this feature to the standard:

    Objection #1: Can this feature easily result in code pessimization?

    Yes, as shown by the conditional move example misusing a branch hint can definitely result in worse code with a much longer run time. This feature is primarily meant to be used after a hotspot has been found in existing code. The proposed attributes are not meant to be added to code without measuring the impact to ensure they do not end up degrading performance.

    Emphasis added. So please do not just throw these anywhere.

    One of the biggest dangers in adding these attributes by default is that the information is, conceptually, redundant. Something, somewhere decides what the likelihood of the branch actually is, and you're specifying that likelihood more directly.

    Redundantly-specified information can easily get out-of-sync. Non-local changes to code can change the likelihood of branches, which gets the two out-of-sync. And once that happens, the attribute becomes very bad for performance.

    So it's best to apply this in specific cases, with profilers handy, and with relatively mature code where the likelihood is unlikely to change.