Linux 内核源码中likely()和unlikely()【转】

本文转载自:http://blog.csdn.net/tigerjibo/article/details/8279183

ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢?

首先明确:

if (likely(value))等价于if (value)
if (likely(a>b)) {
fun1();

if (unlikely(value))等价于if (value)

也就是说likely()和unlikely()从阅读和理解的角度是一样的。

这两个宏在内核中定义如下:

  1. <linux/compiler>
  2. #define likely(x) __builtin_expect(!!(x), 1)
  3. #define unlikely(x) __builtin_expect(!!(x), 0)

复制代码

这里的__built_expect()函数是gcc(version >= 2.96)的内建函数,提供给程序员使用的,目的是将"分支转移"的信

息提供给编译器,这样编译器对代码进行优化,以减少指令跳转带来的性能下降。

__buildin_expect((x), 1)表示x的值为真的可能性更大。

__buildin_expect((x), 0)表示x的值为假的可能性更大。

也就是说,使用likely(),执行if后面的语句的机会更大,使用unlikely(),执行else后面的语句机会更大一些。通过这种

方式,编译器在编译过程中,会将可能性更大的代码紧跟着后面的代码,从而减少指令跳转带来的性能上的下降。

比如 :

  1. if (likely(a>b)) {
  2. fun1();
  3. }

复制代码

这里就是程序员可以确定 a>b 在程序执行流程中出现的可能相比较大,因此运用了likely()告诉编译器将fun1()函数

的二进制代码紧跟在前面程序的后面,这样就cache在预取数据时就可以将fun1()函数的二进制代码拿到cache中。

这样,也就添加了cache的命中率。

同样的,unlikely()的作用就是告诉编译器,a<b 的可能性很小所以这里在编译时,将fun2()的二进制代码尽量

不要和前边的编译在一块。咱们不用对likely和unlikely感到迷惑,须要知晓的就是 if(likely(a>b)) 和 if(a>b)在功能

上是等价的,同样 if(unlikely(a<b)) 和 if(a<b) 的功能也是一样的。不一样的只是他们声称的二进制代码有所不一

样,这一点咱们也可以从他们的汇编代码中看到。总之,likely和unlikely的功能就是添加 cache的命中率,提高系统

执行速度。

时间: 2024-11-02 13:30:09

Linux 内核源码中likely()和unlikely()【转】的相关文章

Linux 内核源码中likely()和unlikely()

ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢? 首先明确: if (likely(value))等价于if (value)if (likely(a>b)) {fun1(); if (unlikely(value))等价于if (value) 也就是说likely()和unlikely()从阅读和理解的角度是一样的. 这两个宏在内核中定义如下: <linux/compiler> #define likely(x) __builtin_

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线

Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938396.html 在基本分析完内核启动流程的之后,还有一个比较重要的初始化函数没有分析,那就是do_basic_setup.在内核init线程中调用了do_basic_setup,这个函数也做了很多内核和驱动的初始化工作,详解

Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 【转】

原文地址:Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938390.html 在构架相关的汇编代码运行完之后,程序跳入了构架无关的内核C语言代码:init/main.c中的start_kernel函数,在这个函数中Linux内核开始真正进入初始化阶段, 下面我就顺这代码逐个函数的解释,但是这里并不会过于深入

Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938393.html 在分析start_kernel函数的时候,其中有构架相关的初始化函数setup_arch. 此函数根据构架而异,对于ARM构架的详细分析如下: void __init setup_arch(char **cmdlin

Linux内核源码分析方法

  一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都知道,想成为优秀的程序员,需要大量的实践和代码的编写.编程固然重要,但是往往只编程的人很容易把自己局限在自己的知识领域内.如果要扩展自己知识的广度,我们需要多接触其他人编写的代码,尤其是水平比我们更高的人编写的代码.通过这种途径,我们可以跳出自己知识圈的束缚,进入他人的知识圈,了解更多甚至我们一

Linux内核源码学习之 数据结构

本篇记录在学习Linux内核源码过程中对一些知道但不熟悉不会用的数据结构进行记录. union 是在学习进程复制函数do_fork中遇到的: <sched.h> union thread_union { struct thread_info thread_info; unsigned long stack[THREAD_SIZE/sizeof(long)]; }; struct  thread_info和stack被声明为union 共享空间 "联合"是一种特殊的类,也是一

ARMv8 Linux内核源码分析:__flush_dcache_all()

1.1 /* *  __flush_dcache_all() *  Flush the wholeD-cache. * Corrupted registers: x0-x7, x9-x11 */ ENTRY(__flush_dcache_all) //保证之前的访存指令的顺序 dsb sy //读cache level id register mrs x0, clidr_el1           // read clidr //取bits[26:24](Level of Coherency f

linux内核源码注解

轻松学习Linux操作系统内核源码的方法 针对好多Linux 爱好者对内核很有兴趣却无从下口,本文旨在介绍一种解读linux内核源码的入门方法,而不是解说linux复杂的内核机制:一.核心源程序的文件组织:1.Linux核心源程序通常都安装在/usr/src/linux下,而且它有一个非常简单的编号约定:任何偶数的核心(例如2.0.30)都是一个稳定地发行的核心,而任何奇数的核心(例如2.1.42)都是一个开发中的核心. 本文基于稳定的2.2.5源代码,第二部分的实现平台为 RedHat Lin