cpufreq之ondemand governer的实现
governer具体是如何调整cpufreq的呢?我们以最复杂的ondemand为例,这个governor 如果发现现在cpu的loading过高的话,直接接却换到最高频率运行.
我们先看看init函数
source/drivers/cpufreq/cpufreq_ondemand.c
491 static int __init cpufreq_gov_dbs_init(void)
492 {
493 return cpufreq_register_governor(cpufreq_gov_ondemand );
494 }
调用cpufreq_register_governor 来注册governer,
603 struct cpufreq_governor cpufreq_gov_ondemand = {
604 .name = "ondemand",
605 .governor = od_cpufreq_governor_dbs,
606 .max_transition_latency = TRANSITION_LATENCY_LIMIT,
607 .owner = THIS_MODULE,
608 };
可见最后注册的是od_dbs_gov.gov.名字是 "ondemand"
要使用一个governer的话,要调用cpufreq_set_policy() 设定的event,分别是CPUFREQ_GOV_POLICY_INIT 和CPUFREQ_GOV_START
其中CPUFREQ_GOV_POLICY_INIT 就是一些简单的赋值,我们重点看CPUFREQ_GOV_START。如下code所示392 行会提供一个workqueue
242 int cpufreq_governor_dbs(struct cpufreq_policy *policy,
243 struct common_dbs_data *cdata, unsigned int event)
365 switch (event) {
366 case CPUFREQ_GOV_START:
367 if (!policy->cur)
368 return -EINVAL;
369
370 mutex_lock(&dbs_data->mutex);
371
372 for_each_cpu(j, policy->cpus) {
373 struct cpu_dbs_common_info *j_cdbs =
374 dbs_data->cdata->get_cpu_cdbs(j);
375 unsigned int prev_load;
376
377 j_cdbs->cpu = j;
378 j_cdbs->cur_policy = policy;
379 j_cdbs->prev_cpu_idle = get_cpu_idle_time(j,
380 &j_cdbs->prev_cpu_wall, io_busy);
381
382 prev_load = (unsigned int)
383 (j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle);
384 j_cdbs->prev_load = 100 * prev_load /
385 (unsigned int) j_cdbs->prev_cpu_wall;
386
387 if (ignore_nice)
388 j_cdbs->prev_cpu_nice =
389 kcpustat_cpu(j).cpustat[CPUTIME_NICE];
390
391 mutex_init(&j_cdbs->timer_mutex);
392 INIT_DEFERRABLE_WORK(&j_cdbs->work,
393 dbs_data->cdata->gov_dbs_timer);
394 }
395
396 if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
397 cs_dbs_info->down_skip = 0;
398 cs_dbs_info->enable = 1;
399 cs_dbs_info->requested_freq = policy->cur;
400 } else {
401 od_dbs_info->rate_mult = 1;
402 od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
403 od_ops->powersave_bias_init_cpu(cpu);
404 }
405
406 mutex_unlock(&dbs_data->mutex);
407
408 /* Initiate timer time stamp */
409 cpu_cdbs->time_stamp = ktime_get();
410
411 gov_queue_work(dbs_data, policy,
412 delay_for_sampling_rate(sampling_rate), true);
413 break;
}
针对ondemand ,392行的实现dbs_data->cdata->gov_dbs_timer。为od_dbs_timer。411行开始设定delay后运行这个workqueue。即调用od_dbs_timer函数,delay的时间为delay_for_sampling_rate(sampling_rate)
533 static struct common_dbs_data od_dbs_cdata = {
534 .governor = GOV_ONDEMAND,
535 .attr_group_gov_sys = &od_attr_group_gov_sys,
536 .attr_group_gov_pol = &od_attr_group_gov_pol,
537 .get_cpu_cdbs = get_cpu_cdbs,
538 .get_cpu_dbs_info_s = get_cpu_dbs_info_s,
539 .gov_dbs_timer = od_dbs_timer,
540 .gov_check_cpu = od_check_cpu,
541 .gov_ops = &od_ops,
542 .init = od_init,
543 .exit = od_exit,
544 };
194 static void od_dbs_timer(struct work_struct *work)
195 {
196 struct od_cpu_dbs_info_s *dbs_info =
197 container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work);
198 unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
199 struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info,
200 cpu);
201 struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data;
202 struct od_dbs_tuners *od_tuners = dbs_data->tuners;
203 int delay = 0, sample_type = core_dbs_info->sample_type;
204 bool modify_all = true;
205
206 mutex_lock(&core_dbs_info->cdbs.timer_mutex);
207 if (!need_load_eval(&core_dbs_info->cdbs, od_tuners->sampling_rate)) {
208 modify_all = false;
209 goto max_delay;
210 }
211
212 /* Common NORMAL_SAMPLE setup */
213 core_dbs_info->sample_type = OD_NORMAL_SAMPLE;
214 if (sample_type == OD_SUB_SAMPLE) {
215 delay = core_dbs_info->freq_lo_jiffies;
216 __cpufreq_driver_target(core_dbs_info->cdbs.cur_policy,
217 core_dbs_info->freq_lo, CPUFREQ_RELATION_H);
218 } else {
219 dbs_check_cpu(dbs_data, cpu);
220 if (core_dbs_info->freq_lo) {
221 /* Setup timer for SUB_SAMPLE */
222 core_dbs_info->sample_type = OD_SUB_SAMPLE;
223 delay = core_dbs_info->freq_hi_jiffies;
224 }
225 }
226
227 max_delay:
228 if (!delay)
229 delay = delay_for_sampling_rate(od_tuners->sampling_rate
230 * core_dbs_info->rate_mult);
231
232 gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all);
233 mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
234 }
从od_dbs_timer 的219行check cou的loadding,针对ondemand dbs_data->cdata->gov_check_cpu =
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
34 {
158
159 dbs_data->cdata->gov_check_cpu(cpu, max_load);
160 }
从od_check_cpu的165行可以看到如果当前的loader大于od_tuners->up_threshold。直接调用dbs_freq_increase 来设成成最大频率运行
155 static void od_check_cpu(int cpu, unsigned int load)
156 {
157 struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
158 struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
159 struct dbs_data *dbs_data = policy->governor_data;
160 struct od_dbs_tuners *od_tuners = dbs_data->tuners;
161
162 dbs_info->freq_lo = 0;
163
164 /* Check for frequency increase */
165 if (load > od_tuners->up_threshold) {
166 /* If switching to max speed, apply sampling_down_factor */
167 if (policy->cur < policy->max)
168 dbs_info->rate_mult =
169 od_tuners->sampling_down_factor;
170 dbs_freq_increase(policy, policy->max);
171 } else {
172 /* Calculate the next frequency proportional to load */
173 unsigned int freq_next, min_f, max_f;
174
175 min_f = policy->cpuinfo.min_freq;
176 max_f = policy->cpuinfo.max_freq;
177 freq_next = min_f + load * (max_f - min_f) / 100;
178
179 /* No longer fully busy, reset rate_mult */
180 dbs_info->rate_mult = 1;
181
182 if (!od_tuners->powersave_bias) {
183 __cpufreq_driver_target(policy, freq_next,
184 CPUFREQ_RELATION_C);
185 return;
186 }
187
188 freq_next = od_ops.powersave_bias_target(policy, freq_next,
189 CPUFREQ_RELATION_L);
190 __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_C);
191 }
192 }
dbs_freq_increase的实现如下:
141行得到最大频率,然后146行指定设定到hw寄存器中.
135 static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq)
136 {
137 struct dbs_data *dbs_data = policy->governor_data;
138 struct od_dbs_tuners *od_tuners = dbs_data->tuners;
139
140 if (od_tuners->powersave_bias)
141 freq = od_ops.powersave_bias_target(policy, freq,
142 CPUFREQ_RELATION_H);
143 else if (policy->cur == policy->max)
144 return;
145
146 __cpufreq_driver_target(policy, freq, od_tuners->powersave_bias ?
147 CPUFREQ_RELATION_L : CPUFREQ_RELATION_H);
148 }
workqueue 会定期运行,也就是定期检测cpu的loadding,一旦loading超过阈值,就切换到最大频率运行.
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!