performance/powersave策略
这两个都是设置静态的频率,performance设置最高频,powersave设置最低频。切换governor的时候配置好频率:
store_scaling_governor->cpufreq_set_policy->cpufreq_governor_limits
userspace策略
用户写文件节点/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed时,调用store_scaling_setspeed函数修改频率。
ondemand、conservative策略
这两个governor计算负载的方法以及调频的流程相同,不同的是利用负载计算预期频率的策略,因此4.14及更新的kernel把这两个governor相同的部分做了一些提炼。
Interactive策略
重要概念
hispeed_freq:当CPU频率为最低频且负载突然超过go_hispeed_load时,CPU跳到此频率
go_hispeed_load:hispeed_freq对应的负载
min_sample_time:在降频前需要在当前频率运行保持的时间
sampling_rate:interative管理器的采样间隔
target_loads:为每个频率设置不同的负载门限,以负载+频率的数组形式存储:如75:800:80:900:85:1300:90:1500:95,详细见如下分析。
above_hispeed_delay:频率升高时需要保持的时间,以频率+时间的数组形式存储
调频基本流程
设置sched的回调函数,每次发生任务调度时设置一个irq_work任务,在irq_work中重新计算目标频率
gov_set_update_util->cpufreq_add_update_util_hook->cpufreq_update_util->update_util_handler->irq_work_queue
->eval_target_freq
-> update_load /* 计算CPU移动平均负载频率loadadjfreq = cur_load * cur_freq,代表CPU实际需要的频率 */
-> choose_freq /* 根据target_load和loadadjfreq,计算target_freq */
choose_freq函数根据target_load数组使用如下公式来计算目标频率,通过多次迭代把负载控制在合理的范围内。
target_freq= loadadjfreq / tl = cur_freq * cur_load / tl;
static unsigned int choose_freq(struct interactive_cpu *icpu, unsigned int loadadjfreq)
{
struct cpufreq_policy *policy = icpu->ipolicy->policy;
struct cpufreq_frequency_table *freq_table = policy->freq_table;
unsigned int prevfreq, freqmin = 0, freqmax = UINT_MAX, tl;
unsigned int freq = policy->cur;
int index;do {
prevfreq = freq;
tl = freq_to_targetload(icpu->ipolicy->tunables, freq); /* 根据目标freq返回目标负载 */
/*
* Find the lowest frequency where the computed load is less
* than or equal to the target load.
* target_freq= loadadjfreq / tl = cur_freq * cur_load / tl; /* 根据这个公式逐渐收缩,多次调整找到最佳tl和目标freq */
*/
index = cpufreq_frequency_table_target(policy, loadadjfreq / tl, CPUFREQ_RELATION_L);
freq = freq_table[index].frequency;
if (freq > prevfreq) {
/* The previous frequency is too low */
...
} else if (freq < prevfreq) {
/* The previous frequency is high enough. */
...
}
/* If same frequency chosen as previous then done. */
} while (freq != prevfreq);return freq;
}
下面通过一个例子来描述上面函数的计算过程
假设CPU支持的频率为[200:800]内每隔50MHz的频率。
1)target_loads = 75,那么所有频率的的门限均为75。
升频情况:如果当前频率为350MHz,负载为85超过了75,那么根据公式
target_freq= 350 * 85 / 75 = 396,则在频率表中匹配的档位为400。
降频情况:如果当前频率为350MHz,负载为65低于了75,那么根据公式
target_freq= 350 * 65 / 75 = 303,则在频率表中匹配的档位为350。2)target_loads = 70:400:80:600:90,为不同频率分别设置不同的门限,好处是较低频率可以有较快的反应。(0:400)内的频率负载门限为70,[400:600)内的频率负载门限为80;[600:)内的频率负载门限为90。
升频情况:如果当前频率为350MHz,负载为85超过了70,那么根据公式
target_freq= 350 * 85 / 70 = 425,则在频率表中匹配的档位为450。450的门限为80,再次计算
target_freq= 350 * 85 / 80 = 371,则在频率表中匹配的档位为400。 400的门限为80,所以最终计算的频率为400。降频情况:
如果当前频率为450MHz,负载为50低于了80,那么根据公式
target_freq= 450 * 50 / 80 = 281,则在频率表中匹配的档位为300,300的门限为70,再次计算
target_freq= 450 * 50 / 70 = 321,则在频率表中匹配的档位为350,350的门限为70,所以最终计算的频率为350。
Schedutil策略
基本思想
初始化时调用cpufreq_add_update_util_hook注册调频回调函数。
sugov_start
->cpufreq_add_update_util_hook
cpufreq_update_util会由kernel调度器调用,每当任务调度时执行回调函数计算负载和预期频率。
标签:load,负载,target,governor,cpufreq,频率,linux,freq From: https://www.cnblogs.com/lvzh/p/13938802.htmlcpufreq_update_util