定义的地方
#ifdef CONFIG_CPU_FREQ
#define arch_scale_freq_capacity cpufreq_scale_freq_capacity
extern unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu);
extern unsigned long cpufreq_scale_max_freq_capacity(int cpu);
#endif
#ifndef CONFIG_64BIT_ONLY_CPU
#define arch_scale_cpu_capacity scale_cpu_capacity
extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu);
#endif
默认配置:CONFIG_CPU_FREQ=y,CONFIG_64BIT_ONLY_CPU=n
- scale_freq_capacity获取的地方:
static DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
static DEFINE_PER_CPU(unsigned long, max_freq_scale) = SCHED_CAPACITY_SCALE;
static void
scale_freq_capacity(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs)
{
unsigned long cur = freqs ? freqs->new : policy->cur;
unsigned long scale = (cur << SCHED_CAPACITY_SHIFT) / policy->max;
struct cpufreq_cpuinfo *cpuinfo = &policy->cpuinfo;
int cpu;
pr_debug("cpus %*pbl cur/cur max freq %lu/%u kHz freq scale %lu\n",
cpumask_pr_args(policy->cpus), cur, policy->max, scale);
for_each_cpu(cpu, policy->cpus)
per_cpu(freq_scale, cpu) = scale;
if (freqs)
return;
scale = (policy->max << SCHED_CAPACITY_SHIFT) / cpuinfo->max_freq;
pr_debug("cpus %*pbl cur max/max freq %u/%u kHz max freq scale %lu\n",
cpumask_pr_args(policy->cpus), policy->max, cpuinfo->max_freq,
scale);
for_each_cpu(cpu, policy->cpus)
per_cpu(max_freq_scale, cpu) = scale;
}
unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu)
{
return per_cpu(freq_scale, cpu);
}
unsigned long cpufreq_scale_max_freq_capacity(int cpu)
{
return per_cpu(max_freq_scale, cpu);
}
怎么知道scale_freq_capacity会被调用呢?可以看到存在两个地方存在调用:
cpufreq_set_policy
cpufreq_freq_transition_begin
这两个函数必定会被调用到,第二个函数会被频繁的调用,因为每次freq的变化都会调用它。
而且我也通过log验证了确实被调用了,scale_freq_capacity也符合curr_freq * 1024/max_freq计算结果
- scale_cpu_capacity获取的地方:
static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu)
{
#ifdef CONFIG_CPU_FREQ
unsigned long max_freq_scale = cpufreq_scale_max_freq_capacity(cpu);
return per_cpu(cpu_scale, cpu) * max_freq_scale >> SCHED_CAPACITY_SHIFT;
#else
return per_cpu(cpu_scale, cpu);
#endif
}
static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
{
per_cpu(cpu_scale, cpu) = capacity;
}
static void update_cpu_capacity(unsigned int cpu)
{
unsigned long capacity = SCHED_CAPACITY_SCALE;
if (cpu_core_energy(cpu)) {
int max_cap_idx = cpu_core_energy(cpu)->nr_cap_states - 1;
capacity = cpu_core_energy(cpu)->cap_states[max_cap_idx].cap;
}
set_capacity_scale(cpu, capacity);
pr_info("CPU%d: update cpu_capacity %lu\n",
cpu, arch_scale_cpu_capacity(NULL, cpu));
}
static inline
const struct sched_group_energy * const cpu_core_energy(int cpu)
{
struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0];
#ifndef CONFIG_DEFAULT_USE_ENERGY_AWARE
return NULL;
#endif
if (!sge) {
pr_warn("Invalid sched_group_energy for CPU%d\n", cpu);
return NULL;
}
return sge;
}
也能够看到,都是通过per_cpu来设定和获取的,以后得好好梳理下per_cpu的来龙去脉,实在是太有用了。
由于定义了CONFIG_CPU_FREQ,所以需要先获取max_freq_scale的数值,从第一章,能够知道cpufreq_scale_max_freq(cpu)的数值为1024,在scale_freq_capacity中并没有成功修改scale_max_freq数值。所以scale_cpu_capacity就是每个cpu自身的capacity数值,最后的数值就是cpu_scale,这个数值是从dts里面获取的。我们之前的文章讲解了kernel/sched/energy.c文件获取cpu power、capacity,cpu idle power了,里面的这些数据全部存储在sge_array全局二维数组中。