Linux - likely/unlikely

CPU特征

缓存

  程序的执行过程中程序指令及数据会按照以下方向流动:

  外部存储 -> 内存 -> L3缓存 -> L2缓存 -> L1缓存 -> 寄存器

   在计算机体系结构中这些存储部件有以下特征:

  • 每一类型的存储空间从左到右逐级变小
  • 每一类型的读写速度从左到右逐级变快
  • CPU运行的时候优先从右边的存储空间中获取,若没有则逐级向左查询

    所以如果希望程序运行的更快的话,就需要每次读取指令/数据的命中越靠右越好

指令流

一条指令的执行过程至少包括读取指令,解释指令和执行指令,当前计算的设计将这三个阶段设计为可并发执行,例如如下场景:

time1: 读取指令1

time2:    解释指令1     读取指令2

time3:  执行指令1     解释指令2     读取指令3

............................................................................

从以上设计可以看出将指令分成更细的步骤比起串行有更高的效率,前提是提前执行的下一条指令是有效的。

条件分支

 在编码中经常会写类似如下的逻辑:

按照理解这段程序汇编伪代码应该时如下形式:

  ...............

  cmpl     

  jle   L1

   .................  //执行条件为真时逻辑

  jmp  L2  //跳转至后续逻辑继续执行

 L1: 

  ..............   //执行条件为假时逻辑

 L2:

 ......................  //执行后续逻辑 

而在打开优化的情况下对应到汇编的指令如下:

实际汇编代码逻辑如下:

.........................

cmpl   

jle   L1

............

L2: 

...........

retq

L1:

.................

jmp L2

可以发现当编译器打开优化功能时程序的执行逻辑对于条件为真的情况相当友好,有以下优势

  • 增加了指令jle 后续指令执行的命中率
  • 省去了最后的一句jmp语句

当希望编译器对条件为假的情况友好时,可以有以下两种方法

  • 将条件语句的控制条件反转
  • 不改变控制条件在if语句中使用unlikely提示编译器

最后编译器生成汇编如下:

likely/unlikely 宏

#define __branch_check__(x, expect, is_constant) ({            \
            long ______r;                    \
            static struct ftrace_likely_data        \
                __aligned(4)                \
                __section("_ftrace_annotated_branch")    \
                ______f = {                \
                .data.func = __func__,            \
                .data.file = __FILE__,            \
                .data.line = __LINE__,            \
            };                        \
            ______r = __builtin_expect(!!(x), expect);    \
            ftrace_likely_update(&______f, ______r,        \
                         expect, is_constant);    \
            ______r;                    \
        })

/*
 * Using __builtin_constant_p(x) to ignore cases where the return
 * value is always the same.  This idea is taken from a similar patch
 * written by Daniel Walker.
 */
# ifndef likely
#  define likely(x)    (__branch_check__(x, 1, __builtin_constant_p(x)))
# endif
# ifndef unlikely
#  define unlikely(x)    (__branch_check__(x, 0, __builtin_constant_p(x)))
# endif

从likely/unlikely宏的定义中可以看出除了第二个参数代表期望值不一样外,宏定义的其他参数都是一样的。最终宏在区块_ftrace_annotated_branch 中定义了一个ftrace_likely_data对象 描述了插入宏的代码信息,比如:

  • 代码的位置信息
  • 条件的信息

void ftrace_likely_update(struct ftrace_likely_data *f, int val,
              int expect, int is_constant)
{
    unsigned long flags = user_access_save();

    /* A constant is always correct */
    if (is_constant) {
        f->constant++;
        val = expect;
    }
    /*
     * I would love to have a trace point here instead, but the
     * trace point code is so inundated with unlikely and likely
     * conditions that the recursive nightmare that exists is too
     * much to try to get working. At least for now.
     */
    trace_likely_condition(f, val, expect);

    /* FIXME: Make this atomic! */
    if (val == expect)
        f->data.correct++;
    else
        f->data.incorrect++;

    user_access_restore(flags);
}

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
error: Command "x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/lib/python3/dist-packages/numpy/core/include -I/usr/lib/python3/dist-packages/numpy/core/include -Ibuild/src.linux-x86_64-3.9/numpy/distutils/include -I/usr/include/python3.9 -c skimage/_shared/transform.c -o build/temp.linux-x86_64-3.9/skimage/_shared/transform.o -MMD -MF build/temp.linux-x86_64-3.9/skimage/_shared/transform.o.d -msse -msse2 -msse3" failed with exit status 1 ########### EXT COMPILER OPTIMIZATION ########### Platform : Architecture: x64 Compiler : gcc CPU baseline : Requested : 'min' Enabled : SSE SSE2 SSE3 Flags : -msse -msse2 -msse3 Extra checks: none CPU dispatch : Requested : 'max -xop -fma4' Enabled : SSSE3 SSE41 POPCNT SSE42 AVX F16C FMA3 AVX2 AVX512F AVX512CD AVX512_KNL AVX512_KNM AVX512_SKX AVX512_CLX AVX512_CNL AVX512_ICL Generated : none CCompilerOpt.cache_flush[809] : write cache to path -> /tmp/pip-install-vds_g0pc/scikit-image_ce84e6b3faf149029da8bbdd92daa66d/build/temp.linux-x86_64-3.9/ccompiler_opt_cache_ext.py [end of output] note: This error originates from a subprocess, and is likely not a problem with pip. error: legacy-install-failure × Encountered error while trying to install package. ╰─> scikit-image note: This is an issue with the package mentioned above, not pip. hint: See above for output from the failure.、
06-02

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值