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超过阈值,就切换到最大频率运行.


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部