最近在看kernel5.4.26的调度器代码,看到下面的:
static int
select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_flags)
{
struct sched_domain *tmp, *sd = NULL;
int cpu = smp_processor_id();
int new_cpu = prev_cpu;
int want_affine = 0;
int sync = (wake_flags & WF_SYNC) && !(current->flags & PF_EXITING);
if (sd_flag & SD_BALANCE_WAKE) {
record_wakee(p);
if (sched_energy_enabled()) { //这个数值在哪里设置的呢?
new_cpu = find_energy_efficient_cpu(p, prev_cpu, sync);
if (new_cpu >= 0)
return new_cpu;
new_cpu = prev_cpu;
}
want_affine = !wake_wide(p) && cpumask_test_cpu(cpu, p->cpus_ptr);
}
如下所示:
#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL)
#define perf_domain_span(pd) (to_cpumask(((pd)->em_pd->cpus)))
DECLARE_STATIC_KEY_FALSE(sched_energy_present);
static inline bool sched_energy_enabled(void)
{
return static_branch_unlikely(&sched_energy_present);
}
#else /* ! (CONFIG_ENERGY_MODEL && CONFIG_CPU_FREQ_GOV_SCHEDUTIL) */
#define perf_domain_span(pd) NULL
static inline bool sched_energy_enabled(void) { return false; }
#endif /* CONFIG_ENERGY_MODEL && CONFIG_CPU_FREQ_GOV_SCHEDUTIL */
- 如果调度器是使用EAS并且cpufreq governor使用的是scheduitl,则返回sched_energy_present数值
- 否则直接返回false.
那么sched_energy_present数值怎么被设置的呢?
#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL)
DEFINE_STATIC_KEY_FALSE(sched_energy_present);
也需要满足两个定义才会声明此变量
#define DEFINE_STATIC_KEY_FALSE(name) \
struct static_key_false name = STATIC_KEY_FALSE_INIT
#define STATIC_KEY_FALSE_INIT (struct static_key_false){ .key = STATIC_KEY_INIT_FALSE, }
#define STATIC_KEY_INIT_FALSE \
{ .enabled = { 0 }, \
┊ { .entries = (void *)JUMP_TYPE_FALSE } }
#define JUMP_TYPE_FALSE 0UL
可以看到DEFINE_STATIC_KEY_FALSE是设置sched_energy_present为false的,即enable=0.
那么这个数值在哪里设置为enable为非0数值的呢?
/*
1. sched domain构建,即topology的构建,在系统初始化的时候.
2. 有cpu插拔动作的时候都会调用这个函数,重构sched domain.
*/
void partition_sched_domains_locked(int ndoms_new, cpumask_var_t doms_new[],
┊ struct sched_domain_attr *dattr_new)
{
.................
#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL)
/* Build perf. domains: */
for (i = 0; i < ndoms_new; i++) {
for (j = 0; j < n && !sched_energy_update; j++) {
if (cpumask_equal(doms_new[i], doms_cur[j]) &&
┊ cpu_rq(cpumask_first(doms_cur[j]))->rd->pd) {
has_eas = true;
goto match3;
}
}
/* No match - add perf. domains for a new rd */
has_eas |= build_perf_domains(doms_new[i]); //has_eas = true,否则energy mode没有建立,EAS不能使用
match3:
;
}
sched_energy_set(has_eas);
#endif
................
}
static void sched_energy_set(bool has_eas)
{
if (!has_eas && static_branch_unlikely(&sched_energy_present)) {
if (sched_debug())
pr_info("%s: stopping EAS\n", __func__);
static_branch_disable_cpuslocked(&sched_energy_present);
} else if (has_eas && !static_branch_unlikely(&sched_energy_present)) {
if (sched_debug())
pr_info("%s: starting EAS\n", __func__);
static_branch_enable_cpuslocked(&sched_energy_present);
}
}
我们看下static_branch_enable_cpuslocked(&sched_energy_present)这么定义的?
#define static_branch_enable_cpuslocked(x) static_key_enable_cpuslocked(&(x)->key)
void static_key_enable_cpuslocked(struct static_key *key)
{
STATIC_KEY_CHECK_USE(key);
lockdep_assert_cpus_held();
if (atomic_read(&key->enabled) > 0) {
WARN_ON_ONCE(atomic_read(&key->enabled) != 1);
return;
}
jump_label_lock();
if (atomic_read(&key->enabled) == 0) {
atomic_set(&key->enabled, -1);
jump_label_update(key);
/*
┊* See static_key_slow_inc().
┊*/
atomic_set_release(&key->enabled, 1);
}
jump_label_unlock();
}
EXPORT_SYMBOL_GPL(static_key_enable_cpuslocked);
可以看到sched_energy_present被设置成非0数值了. 这样sched_energy_enabled()也就返回true了,可以走EAS流程选择target_cpu.
为何使用static key呢?
查看文档说明如下:
Static keys allows the inclusion of seldom used features in
performance-sensitive fast-path kernel code, via a GCC feature and a code
patching technique. A quick example::
DEFINE_STATIC_KEY_FALSE(key);
...
if (static_branch_unlikely(&key))
do unlikely code
else
do likely code
...
static_branch_enable(&key);
...
static_branch_disable(&key);
...
The static_branch_unlikely() branch will be generated into the code with as little
impact to the likely code path as possible.
其实就是对经常使用的代码进行优化,并且这个数值很少被改变.
参考文献:
static-key简介