详解likely和unlikely函数

    内核源码:linux-2.6.38.8.tar.bz2

    参考文档:http://gcc.gnu.org/onlinedocs/gcc-4.6.2/gcc/Other-Builtins.html#Other-Builtins

 

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

    1、对__builtin_expect的封装

    它们的源代码如下: 

/* linux-2.6.38.8/include/linux/compiler.h */
# define likely(x)	__builtin_expect(!!(x), 1)
# define unlikely(x)	__builtin_expect(!!(x), 0)

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

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

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

#include <stdio.h>

int main(void)
{
    int a;

    scanf("%d", &a);

    if(__builtin_expect(a, 4))
	printf("if: a = %d\n", a);
    else
	printf("else: a = %d\n", a);

    return 0;
}

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

else: a = 0

if: a = 1

if: a = 2

if: a = 3

if: a = 4

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

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

    2、使用__branch_check__函数

    它们的源代码如下: 

/* 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

    (1)、先使用内置函数__builtin_constant_p忽略表达式x为常量的情况

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

#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\n", num);
    free(ptr);

    count = __builtin_constant_p(VALUE) ? 20 + VALUE : 10;
    printf("count = %d\n", count);

    return 0;
}

    例子的输出结果: 

num = 30
count = 25

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

    (2)、函数__branch_check__的实现 

/* 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;					\
		})

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

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

  • 8
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在C语言中,UNLIKELY是一个宏定义,用于提示编译器某个条件的发生概率较低。它一般用于if语句中,让编译器优化代码以提高性能。UNLIKELY可以与条件表达式结合使用,以告诉编译器这个条件很少会满足,从而优化代码的执行路径。通常,UNLIKELY用于if语句中的条件表达式,使得编译器更倾向于执行if语句中的else分支,以提高代码的执行效率。!!运算符是C语言中处理逻辑表达式的一个技巧,用于将非零值转换为1。当变量x为非零值时,!!(x)返回1,当x为零时,!!(x)返回0。这个技巧常用于将条件表达式的结果映射为布尔值。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C语言技巧:有if时使用likelyunlikely让代码运行更快](https://blog.csdn.net/freestep96/article/details/128771498)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [C语言进阶——likelyunlikely](https://blog.csdn.net/weixin_44873133/article/details/107302688)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tanglinux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值