"Finishing" __builtin_expect FAQ

Source: Internet
Author: User

Reproduced from: https://my.oschina.net/moooofly/blog/175019

Recently see GLIB code encountered this dongdong, online search a circle, found that a lot of people have written this, their own today to study, shame a bit, literacy a point, leave this record as evidence.

First, read one of the most official explanations:

======
Likely () and unlikely ()

What are they?
In Linux kernel code, one often find calls to likely () and unlikely (), in conditions, like:

BVL = Bvec_alloc (Gfp_mask, Nr_iovecs, &idx);
if (unlikely (!BVL)) {
  Mempool_free (bio, bio_pool);
  Bio = NULL;
  goto out;
}
In fact, this functions are hints for the compiler this allows it to correctly optimize the branch, by knowing which is T He likeliest one. The definitions of macros, found in Include/linux/compiler.h are the following:
#define LIKELY (x)       __builtin_expect (!! (x), 1)
#define UNLIKELY (x)     __builtin_expect (!! (x), 0)
The GCC documentation explains the role of __builtin_expect ():
--Built-in Function:long __builtin_expect (long EXP, long C) you could use ' __builtin_expect ' to provide the compiler  With branch prediction information. In general, your should prefer to use actual profiles feedback for this ('-fprofile-arcs '), as programmers are  oriously predicting how their programs actually perform.

     However, there are applications in which this data are hard to collect.  The return value was the value of EXP, which should be a integral expression.  The value of C must be a Compile-time constant.
     The semantics of the built-in are that it is expected that EXP = C.

     For Example:if (__builtin_expect (x, 0)) foo ();  Would indicate that we don't expect to call ' Foo ' and since we expect ' X ' to be zero. Since you are limited to integral expressions for EXP, and should use constructions such as if (__builtin_

     Expect (PTR!= NULL, 1)) error (); WhenTesting pointer or floating-point values. 
How does it optimize things?
It optimizes things by ordering the generated assembly code correctly, to optimize the usage of the processor. To does so, they arrange the "code so" likeliest branch is executed without performing any JMP instruction (which has The bad effect of flushing the processor pipeline).

To and how it works, let's compile the following simple C user spaces program with GCC-O2:
#define LIKELY (x)    __builtin_expect (!! (x), 1)
#define UNLIKELY (x)  __builtin_expect (!! (x), 0)

int main (char *argv[], int argc)
{
   int A;

   /* Get the value from somewhere GCC can ' t optimize * *
   a = atoi (argv[1));

   if (unlikely (a = = 2))
      a++;
   else
      a--;

   printf ("%d\n", a);

   return 0;
}
Now, disassemble the resulting binary using objdump-s (comments added by me):
080483b0 <main&gt://Prologue 80483b0:55 push%EBP 80483b1:89 e5   mov%esp,%ebp 80483b3:50 push%eax 80483b4:50 push                %eax 80483b5:83 e4 F0 and $0XFFFFFFF0,%ESP//Call Atoi () 80483b8:8b 45 08                mov 0x8 (%EBP),%EAX 80483bb:83 EC 1c Sub $0X1C,%ESP 80483BE:8B 48 04          mov 0x4 (%eax),%ecx 80483c1:51 push%ecx 80483c2:e8 1d FF FF FF Call 80482e4 <atoi@plt> 80483c7:83 c4 Add $0x10,%esp//Test the VA Lue 80483ca:83 F8 CMP $0x2,%eax//---------------------------------------------  -----------//If ' a ' equal to 2 (which is unlikely), then jump,//otherwise continue directly, Without jump, so IT//doesn ' t flush the pipeline. --------------------------------------------------------80483cd:74 JE 804                      83e1 <main+0x31> 80483cf:48 Dec%eax//Call printf 80483d0:52                      Push%edx 80483d1:52 Push%edx 80483d2:50 Push%eax 80483d3:68 C8 push $0x80484c8 80483d8:e8 F7 FE FF FF Call 80
 482d4 <printf@plt>//return 0 and go out.                      80483dd:31 C0 xor%eax,%eax 80483df:c9 leave 80483E0:C3 Ret
Now, in the previous program, replace the unlikely () by a likely (), recompile it, and disassemble it again (again, comment s added by me):
080483b0 <main&gt://Prologue 80483b0:55 push%EBP 80483b1:89 e5                      mov%esp,%ebp 80483b3:50 push%eax 80483b4:50       Push%eax 80483b5:83 e4 F0 and $0XFFFFFFF0,%ESP//Call Atoi () 80483b8:       8b mov 0x8 (%EBP),%EAX 80483bb:83 EC 1c SUB $0X1C,%ESP 80483BE: 8b mov 0x4 (%eax),%ecx 80483c1:51 push%ecx 80483c2:e8 1d f             F FF FF call 80482e4 <atoi@plt> 80483c7:83 c4 add $0x10,%esp//              --------------------------------------------------//If ' a ' equal 2 (which is likely), we'll continue// Without branching, so without flusing the pipeline.
 The//Jump only occurs when a!= 2, which is unlikely.         //    ---------------------------------------------------80483ca:83 F8 cmp $0x2,%eax 80483CD: Jne 80483e2 <main+0x32>/Here the a++ incrementation has been Optim                      ized by GCC 80483cf:b0 mov $0x3,%al//Call printf () 80483d1:52 Push%edx 80483d2:52 push%edx 80483d3:50 PU  SH%eax 80483d4:68 C8 $0x80484c8 80483d9:e8 f6 FE FF FF call 80482D4
 <printf@plt>//Return 0.                      80483de:31 C0 xor%eax,%eax 80483e0:c9 leave 80483E1:C3 Ret
How should I use it?
Should use it cases the likeliest branch are very very very likely, or when Unlikeliest branch Very very unlikely.

======

Read the most authoritative, the following look at the "folk" saying:

======
likely,unlikely macros and GCC built-in functions __builtin_expect ()

The description of __builtin_expect () in the GCC Handbook is as follows:

Because most programmers do poorly on branch predictions, GCC provides this built-in function to help programmers deal with branch predictions and optimize programs. The first argument exp is an integral expression, and the return value of the built-in function is this exp, and C is a compile-time constant. The semantics of this function are: you expect the value of the EXP expression to be equal to constant C, so GCC optimizes the program for you and places the branch in the right place. In general, you might prefer to use GCC's parameter '-fprofile-arcs ' to collect actual feedback about the execution process and branching direction that the program runs.
Because this program only provides an integer expression, you can use the form of pointers if you want to optimize other types of expressions.

Likely and unlikely are processor-related macros for GCC extensions:
#define  likely (x)        __builtin_expect (!! (x), 1) 
#define  unlikely (x)      __builtin_expect (!! (x), 0)
Now the processor is the assembly line, some of which have more than one logical unit of operation, the system can take many instructions in parallel processing, but encountered jumps, you need to fetch instructions, this is relative to the command to reduce the speed.
Therefore, the introduction of likely and unlikely, the purpose is to increase the accuracy of conditional branch prediction, the CPU will be loaded in advance the following instructions, encountered conditional transfer instructions in advance to predict and load a branch of instructions. Unlikely says you can confirm that the condition is rare, whereas likely indicates that the condition will occur in most cases. The compiler produces the appropriate code to optimize CPU execution efficiency.

So programmers can optimize the processor's finger-pointing operation according to the probability of judging the condition when they write the code.
For example:
int x, y; 
if (unlikely (x > 0)) 
    y = 1; 
else 
    y =-1;
The instructions in the above code that GCC compiles will read the y =-1 instruction in advance, which is a small probability that the value of x is greater than 0. If the value of x is greater than 0 in most cases, you should use likely (X > 0) so that the compiled instruction is to read the y = 1 instruction in advance. This allows the system to reduce the point of anaphora when it is running.


======
Likely () and unlikely () in the kernel

First, be clear:
if (likely (value)) is equivalent to the if (value) if (unlikely (value)) is also equivalent to if (value) __builtin_expect () is GCC (version >= 2.96) provides For programmers, the goal is to provide "branch transfer" information to the compiler so that the compiler can optimize the code to reduce the performance degradation caused by the instruction jump.

__builtin_expect ((x), 1) is more likely to indicate that the value of x is true;
__builtin_expect ((x), 0) is more likely to indicate that the value of x is false.

That is, with likely (), the chances of executing the statement following the IF are greater, using unlikely (), and the chance of executing the statement following else. In this way, the compiler, in the compilation process, will be more likely to follow the code to the surface of the code, thereby reducing the performance of the instruction jump drop.

======

After reading a lap of other people's writing, they also want to output point dry goods, listing GLib-2.35.4 Gmacros.h code as follows:
* * The g_likely and g_unlikely macros let the programmer give hints to * the compiler Expression.
 Some compilers * Can use this information for optimizations.  
 * * The _G_BOOLEAN_EXPR macro is intended to trigger a GCC warning when * putting assignments in g_return_if_fail ().                   * * #if defined (__gnuc__) && (__gnuc__ > 2) && defined (__optimize__) #define _G_BOOLEAN_EXPR (EXPR)                         \ g_gnuc_extension ({\ int _g_boolean_var_;                      \ if (expr) \ _g_boolean_var_ = 1;                      \ else \ _g_boolean_var_ = 0;                             \ _g_boolean_var_; })//provides the programmer's expected results for conditional judgment--for compiler optimizations #define G_LIKELY (expr) (__builtin_expect (_g_boolean_expr (expr), 1)) #define G_unlikely (expr) (__builtin_expect (_g_boolean_expr (EXPR), 0)) #else #define G_like-LY (expr) (expr) #define g_unlikely (expr) (expr) #endif 
It can be seen from the above,   GLIB using     _g_boolean_expr (EXPR) instead!! (expr)  . But functionally it is the same.  

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.