zoukankan      html  css  js  c++  java
  • (linux)likely和unlikely函数

     


         在Linux内核中likely和unlikely函数有两种(只能两者选一)实现方式,它们的实现原理稍有不同,但作用是相同的,下面将结合linux-2.6.38.8版本的内核代码来进行讲解。

        1、对__builtin_expect的封装

        它们的源代码如下: 

    1. /* linux-2.6.38.8/include/linux/compiler.h */  
    2. # define likely(x)  __builtin_expect(!!(x), 1)  
    3. # define unlikely(x)    __builtin_expect(!!(x), 0)  
    <span style="font-family:SimHei;font-size:18px;">/* linux-2.6.38.8/include/linux/compiler.h */
    # define likely(x)	__builtin_expect(!!(x), 1)
    # define unlikely(x)	__builtin_expect(!!(x), 0)</span>

        __builtin_expect 是GCC的内置函数,用来对选择语句的判断条件进行优化,常用于一个判断条件经常成立(如likely)或经常不成立(如unlikely)的情况。

        __builtin_expect的函数原型为long  __builtin_expect (long exp, long c),返回值为完整表达式exp的值,它的作用是期望表达式exp的值等于c(注意,如果exp == c条件成立的机会占绝大多数,那么性能将会得到提升,否则性能反而会下降)。

        在普通的应用程序中也可以使用__builtin_expect,如下面的例子: 

    1. #include <stdio.h>  
    2.   
    3. int main(void)  
    4. {  
    5.     int a;  
    6.   
    7.     scanf("%d", &a);  
    8.   
    9.     if(__builtin_expect(a, 4))  
    10.     printf("if: a = %d ", a);  
    11.     else  
    12.     printf("else: a = %d ", a);  
    13.   
    14.     return 0;  
    15. }  
    <span style="font-family:SimHei;font-size:18px;">#include <stdio.h>
    
    int main(void)
    {
        int a;
    
        scanf("%d", &a);
    
        if(__builtin_expect(a, 4))
    	printf("if: a = %d
    ", a);
        else
    	printf("else: a = %d
    ", a);
    
        return 0;
    }
    </span>

        分别输入整数0到4来进行5次测试,它们的输出分别为: 

    1. else: a = 0  
    2.   
    3. if: a = 1  
    4.   
    5. if: a = 2  
    6.   
    7. if: a = 3  
    8.   
    9. if: a = 4  
    <span style="font-family:SimHei;font-size:18px;">else: a = 0
    
    if: a = 1
    
    if: a = 2
    
    if: a = 3
    
    if: a = 4
    </span>

        注意,在上例中只有输入整数0的时候才执行else后的打印语句,也就是说__builtin_expect(a, 4)函数的值就是表达式a的值。

        记住,它们只是用来提升性能的优化手段,并不会改变原来表达式的值。

        2、使用__branch_check__函数

        它们的源代码如下: 

    1. /* linux-2.6.38.8/include/linux/compiler.h */  
    2. # ifndef likely  
    3. #  define likely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1))  
    4. # endif  
    5. # ifndef unlikely  
    6. #  define unlikely(x)   (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))  
    7. # endif  
    <span style="font-family:SimHei;font-size:18px;">/* linux-2.6.38.8/include/linux/compiler.h */
    # ifndef likely
    #  define likely(x)	(__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1))
    # endif
    # ifndef unlikely
    #  define unlikely(x)	(__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
    # endif</span>

        (1)、先使用内置函数__builtin_constant_p忽略表达式x为常量的情况 (这而的!!(x)为什么不写成x呢?)

        __builtin_constant_p也是GCC的内置函数,函数原型为int  __builtin_constant_p(exp),用于判断表达式exp在编译时是否是一个常量,如果是则函数的值为整数1,否则为0,如下面的例子:

    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3.   
    4. #define VALUE 5  
    5.   
    6. int main(void)  
    7. {  
    8.     char *ptr = NULL;  
    9.     int num, count;  
    10.   
    11.     ptr = malloc(20);  
    12.     num = __builtin_constant_p(ptr) ? 20 : 20 + 10;  
    13.     printf("num = %d ", num);  
    14.     free(ptr);  
    15.   
    16.     count = __builtin_constant_p(VALUE) ? 20 + VALUE : 10;  
    17.     printf("count = %d ", count);  
    18.   
    19.     return 0;  
    20. }  
    <span style="font-family:SimHei;font-size:18px;">#include <stdio.h>
    #include <stdlib.h>
    
    #define VALUE 5
    
    int main(void)
    {
        char *ptr = NULL;
        int num, count;
    
        ptr = malloc(20);
        num = __builtin_constant_p(ptr) ? 20 : 20 + 10;
        printf("num = %d
    ", num);
        free(ptr);
    
        count = __builtin_constant_p(VALUE) ? 20 + VALUE : 10;
        printf("count = %d
    ", count);
    
        return 0;
    }
    </span>

        例子的输出结果: 

    1. num = 30  
    2. count = 25  
    <span style="font-family:SimHei;font-size:18px;">num = 30
    count = 25
    </span>

        例子中的ptr为指针变量,所以__builtin_constant_p(ptr)的值为0,num的值为30。

        (2)、函数__branch_check__的实现 

    1. /* linux-2.6.38.8/include/linux/compiler.h */  
    2. #define __branch_check__(x, expect) ({                    
    3.             int ______r;                      
    4.             static struct ftrace_branch_data          
    5.                 __attribute__((__aligned__(4)))       
    6.                 __attribute__((section("_ftrace_annotated_branch")))   
    7.                 ______f = {               
    8.                 .func = __func__,             
    9.                 .file = __FILE__,             
    10.                 .line = __LINE__,             
    11.             };                        
    12.             ______r = likely_notrace(x);              
    13.             ftrace_likely_update(&______f, ______r, expect);   
    14.             ______r;                      
    15.         })  
    <span style="font-family:SimHei;font-size:18px;">/* linux-2.6.38.8/include/linux/compiler.h */
    #define __branch_check__(x, expect) ({					
    			int ______r;					
    			static struct ftrace_branch_data		
    				__attribute__((__aligned__(4)))		
    				__attribute__((section("_ftrace_annotated_branch"))) 
    				______f = {				
    				.func = __func__,			
    				.file = __FILE__,			
    				.line = __LINE__,			
    			};						
    			______r = likely_notrace(x);			
    			ftrace_likely_update(&______f, ______r, expect); 
    			______r;					
    		})</span>

        使用它来检查判断条件并记录likely判断的预测信息,之后根据预测信息进行相应的优化以提升性能。

        函数__branch_check__的返回值为______r的值,也就是参数x的值。

  • 相关阅读:
    Computer Science Theory for the Information Age-4: 一些机器学习算法的简介
    Computer Science Theory for the Information Age-3: 高维空间中的高斯分布和随机投影
    Computer Science Theory for the Information Age-2: 高维空间中的正方体和Chernoff Bounds
    PrestaShop 1.7 如何添加网站的跟踪代码
    PrestaShop 1.7 创建税单的时候中文显示方框
    PrestaShop 1.7 首页菜单如何进行调整
    PrestaShop 1.7 如何启用 debug 模式
    PrestaShop 1.7.6 在访问分类的时候提示错误
    PrestaShop 1.7 安装完成后后台能进去,前台不行
    Maven 服务器如何设置用户名和密码
  • 原文地址:https://www.cnblogs.com/yanghong-hnu/p/4671340.html
Copyright © 2011-2022 走看看