linux内核静态static,Linux内核中的static-key机制

# Linux内核中的static-key机制

背景

在移植某个TP时,发现频繁操作屏幕会导致i2c总线死掉。在跟踪代码的时候,我发现了这个static-key。

因此,学习一下这块的知识。

reference:

介绍

内核的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 灵活,推荐使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值