static-key机制

内核的static-key用来优化if-else频繁判断的问题.
如何使用:
#define DEFINE_STATIC_KEY_FALSE(name)    \
    struct static_key_false name = STATIC_KEY_FALSE_INIT
一般使用DEFINE_STATIC_KEY_FALSE 定义条件不成立的case,用DECLARE_STATIC_KEY_TRUE定义条件成立的case
#define DEFINE_STATIC_KEY_TRUE(name)    \
    struct static_key_true name = STATIC_KEY_TRUE_INIT


例如kernel/sched/core.c中的定义
DEFINE_STATIC_KEY_FALSE(sched_numa_balancing);
实际判读的时候,可以用static_branch_likely和static_branch_unlikely 来判断定义的这个变量表达的条件是否成立.
if (static_branch_likely(&sched_numa_balancing))
    return;
原理分析:
首先看定义struct static_key_false name = STATIC_KEY_FALSE_INIT
static_key_false 结构体的定义如下:
#ifdef HAVE_JUMP_LABEL

struct static_key {
    atomic_t enabled;
/* Set lsb bit to 1 if branch is default true, 0 ot */
    struct jump_entry *entries;
#ifdef CONFIG_MODULES
    struct static_key_mod *next;
#endif
};

#else
struct static_key {
    atomic_t enabled;
};
#endif    /* HAVE_JUMP_LABEL */
可见如果没有定义HAVE_JUMP_LABEL,则static_key 退化成atomic变量
#define STATIC_KEY_TRUE_INIT  (struct static_key_true) { .key = STATIC_KEY_INIT_TRUE,  }
#define STATIC_KEY_FALSE_INIT (struct static_key_false){ .key = STATIC_KEY_INIT_FALSE, }
#define STATIC_KEY_INIT_TRUE                    \
    { .enabled = { 1 },                    \
      .entries = (void *)JUMP_TYPE_TRUE }
#define STATIC_KEY_INIT_FALSE                    \
    { .enabled = { 0 },                    \
      .entries = (void *)JUMP_TYPE_FALSE }
false和true的主要区别就是enabled 是否为1.

#ifdef HAVE_JUMP_LABEL

#define static_branch_likely(x)                            \
({                                        \
    bool branch;                                \
    if (__builtin_types_compatible_p(typeof(*x), struct static_key_true))    \
        branch = !arch_static_branch(&(x)->key, true);            \
    else if (__builtin_types_compatible_p(typeof(*x), struct static_key_false)) \
        branch = !arch_static_branch_jump(&(x)->key, true);        \
    else                                    \
        branch = ____wrong_branch_error();                \
    branch;                                    \
})

#define static_branch_unlikely(x)                        \
({                                        \
    bool branch;                                \
    if (__builtin_types_compatible_p(typeof(*x), struct static_key_true))    \
        branch = arch_static_branch_jump(&(x)->key, false);        \
    else if (__builtin_types_compatible_p(typeof(*x), struct static_key_false)) \
        branch = arch_static_branch(&(x)->key, false);            \
    else                                    \
        branch = ____wrong_branch_error();                \
    branch;                                    \
})

#else /* !HAVE_JUMP_LABEL */

#define static_branch_likely(x)        likely(static_key_enabled(&(x)->key))
#define static_branch_unlikely(x)    unlikely(static_key_enabled(&(x)->key))

#endif /* HAVE_JUMP_LABEL */
可见同样依赖HAVE_JUMP_LABEL。如果没有定义的话,直接退化成likely和unlikely
static_branch_likely 和 static_branch_unlikely 主要是调用arch_static_branch和arch_static_branch_jump 来判断。arch_static_branch表示条件成立,继续执行
例如if (static_branch_likely(&sched_numa_balancing))
    return;
就直接return了
而arch_static_branch_jump 表示条件不成立,执行跳转。
使用这种机制比likely和unlikely的另外一个好处就是可以动态改变执行的条件
#define static_branch_enable(x)        static_key_enable(&(x)->key)
#define static_branch_disable(x)    static_key_disable(&(x)->key)
调用static_key_slow_dec 来使key加1
static inline void static_key_enable(struct static_key *key)
{
    int count = static_key_count(key);

    WARN_ON_ONCE(count < 0 || count > 1);

    if (!count)
        static_key_slow_inc(key);
}
调用static_key_slow_inc 来使key减1
static inline void static_key_disable(struct static_key *key)
{
    int count = static_key_count(key);

    WARN_ON_ONCE(count < 0 || count > 1);

    if (count)
        static_key_slow_dec(key);
}
除了通过static_branch_enable和 static_branch_disable 外,还可以通过static_branch_inc 是判断条件加1,从而是条件成立.反之依然.
#define static_branch_inc(x)        static_key_slow_inc(&(x)->key)
#define static_branch_dec(x)        static_key_slow_dec(&(x)->key)
总的来说static-key 机制比like/unlikely 灵活,推荐使用。



<think>好的,我需要解释这个宏定义#define static_branch_unlikely(x) unlikely(static_key_enabled(&(x)->key))的作用。首先,这个宏属于Linux内核中的静态分支优化技术。 静态分支允许内核在运行时根据条件动态改变代码路径,而不需要频繁检查条件,提升性能。static_key_enabled函数用于检查静态键是否启用。如果启用,执行较快路径;否则,执行较慢路径。 unlikely宏是告诉编译器该条件大概率不成立,帮助优化指令缓存,减少分支预测的开销。所以,static_branch_unlikely宏的作用是:判断静态键x是否启用,并暗示该情况不太可能发生,编译器据此优化代码。 总结来说,这个宏结合了静态分支和分支预测优化,用于高效处理那些预期不常触发的代码分支。</think>这个宏定义 `#define static_branch_unlikely(x) unlikely(static_key_enabled(&(x)->key))` 是 Linux 内核中用于 **静态分支优化(Static Branch)** 的关键机制。它的作用可以分步解释如下: --- ### 1. **核心目的** 用于 **运行时动态选择代码路径**,同时结合 **分支预测优化**。 当某个条件(例如某个功能是否启用)在运行时极少改变时,可以通过静态分支避免频繁的条件判断,提升性能。 --- ### 2. **分解宏定义** - **`static_key_enabled(&(x)->key)`** 检查静态键(Static Key)`x->key` 是否被启用。 - 若启用(`true`),代码会跳转到“快速路径”(fast path); - 若未启用(`false`),则走“慢速路径”(slow path)。 - **`unlikely()`** 提示编译器:括号内的条件大概率不成立(概率 < 50%)。 编译器会优化指令流水线,将“更可能执行的代码”放在靠近主流程的位置,减少分支预测失败的开销。 --- ### 3. **实际应用场景** 假设内核需要处理一个很少触发的功能(例如调试选项): ```c if (static_branch_unlikely(&debug_key)) { // 慢速路径:极少执行 do_debug(); } else { // 快速路径:常态执行 normal_operation(); } ``` - 当 `debug_key` 未启用时,`static_branch_unlikely` 返回 `false`,且 `unlikely(false)` 告诉编译器应优先优化 `else` 分支。 - 最终生成的汇编代码会尽量减少分支跳转的开销。 --- ### 4. **底层原理** - **静态键(Static Key)** 本质是一个全局变量,初始状态为 `false`(未启用)。 可通过 `static_key_enable()`/`static_key_disable()` 在运行时动态修改其状态。 - **代码替换** 内核会在运行时将条件跳转指令(如 `if`)替换为 `NOP`(无操作)或直接跳转指令,从而避免实际的条件判断。 --- ### 5. **与普通 `if` 的区别** | 特性 | 普通 `if` | 静态分支 (`static_branch_*`) | |--------------------|-----------------------------|----------------------------------| | 运行时开销 | 每次执行都检查条件 | 条件检查被优化为直接跳转或无操作 | | 适用场景 | 条件频繁变化 | 条件极少变化(如功能开关、调试选项)| | 性能影响 | 分支预测影响较大 | 近乎零开销 | --- ### 总结 这个宏通过结合 **静态分支** 和 **分支预测提示**,实现了对罕见代码路径的高效处理,是 Linux 内核中性能优化的关键手段之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值