Is there any portable way of doing branch prediction hints? Consider the following example:
if (unlikely_condition) { /* ..A.. */ } else { /* ..B.. */ }
Is this any different than doing:
if (!unlikely_condition) { /* ..B.. */ } else { /* ..A.. */ }
Or is the only way to use compiler specific hints? (e.g. __builtin_expect on GCC)
Will compilers treat the if
conditions any differently based on the ordering of the conditions?
Techopedia Explains Branch Prediction A CPU using branch prediction only executes statements if a predicate is true. One example is using conditional logic. Since unnecessary code is not executed, the processor can work much more efficiently. Branch prediction is implemented in CPU logic with a branch predictor.
The purpose of the branch predictor is to improve the flow in the instruction pipeline. Branch predictors play a critical role in achieving high performance in many modern pipelined microprocessor architectures such as x86.
Branch prediction buffers contain prediction about whether the next branch will be taken (T) or not (NT), but it does not supply the target PC value. A Branch Target Buffer (BTB) does this. The control unit looks up the branch target buffer during the “F” phase.
Branch prediction is a technique used in CPU design that attempts to guess the outcome of a conditional operation and prepare for the most likely result. A digital circuit that performs this operation is known as a branch predictor. It is an important component of modern CPU architectures, such as the x86.
The canonical way to do static branch prediction is that if
is predicted not-branched (i.e. every if
clause is executed, not else
), and loops and backward-goto
s are taken. So, don't put the common case in else
if you expect static prediction to be significant. Getting around an untaken loop isn't as easy; I've never tried but I suppose putting it an an else
clause should work pretty portably.
Many compilers support some form of #pragma unroll
, but it will still be necessary to guard it with some kind of #if
to protect other compilers.
Branch prediction hints can theoretically express a complete description of how to transform a program's flow-control graph and arrange the basic blocks in executable memory… so there are a variety of things to express, and most won't be very portable.
As GNU recommends in the documentation for __builtin_expect
, profile-guided optimization is superior to hints, and with less effort.
In most cases, the following code
if (a) { ... } else { ... }
is actually
evaluate(A) if (!A) { jmp p1 } ... code A jmp p2 p1: ... code !A p2:
Note that if A is true, "code A" is already in the pipeline. The processor will see the "jmp p2" command ahead, and will load p2 code to the pipeline.
If A is false, the "code !A" may not be in the pipleline, therefore it may be slower.
Conclusions:
:
evaluate(A) do more stuff if (A) ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With