Loading Documentation/cpu-freq/governors.txt +13 −3 Original line number Diff line number Diff line Loading @@ -312,9 +312,9 @@ information such as migration. If non-zero, this also implies governor sampling windows are aligned across CPUs, with same timer_rate, regardless what align_windows is set to. Default is zero. use_migration_notif: If non-zero, reevaluate CPU's frequency immediately after receiving notification from scheduler. If zero, ignore scheduler notification. Default is zero. use_migration_notif: If non-zero, schedule hrtimer to fire in 1ms to reevaluate frequency of notified CPU, unless the hrtimer is already pending. If zero, ignore scheduler notification. Default is zero. max_freq_hysteresis: Each time freq evaluation chooses policy->max, next max_freq_hysteresis is considered as hysteresis period. During Loading @@ -337,6 +337,16 @@ evaluation triggered by timer, min_sample_time is still always enforced. fast_ramp_down has no effect if use_migration_notif is set to zero. Default is zero. enable_prediction: If non-zero, two frequencies will be calculated during each sampling period: one based on busy time in previous sampling period (f_prev), and the other based on prediction provided by scheduler (f_pred). Max of both will be selected as final frequency. Hispeed related logic, including both frequency selection and delay is ignored if enable_prediction is set. If only f_pred but not f_prev picked policy->max, max_freq_hysteresis period is not started/extended. use_sched_load must be turned on before enabling this feature. Default is zero. 3. The Governor Interface in the CPUfreq Core ============================================= Loading drivers/cpufreq/cpufreq_interactive.c +127 −64 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <linux/tick.h> #include <linux/time.h> #include <linux/timer.h> #include <linux/hrtimer.h> #include <linux/workqueue.h> #include <linux/kthread.h> #include <linux/slab.h> Loading @@ -37,6 +38,7 @@ struct cpufreq_interactive_policyinfo { struct timer_list policy_timer; struct timer_list policy_slack_timer; struct hrtimer notif_timer; spinlock_t load_lock; /* protects load tracking stat */ u64 last_evaluated_jiffy; struct cpufreq_policy *policy; Loading @@ -52,6 +54,7 @@ struct cpufreq_interactive_policyinfo { struct rw_semaphore enable_sem; bool reject_notification; bool notif_pending; unsigned long notif_cpu; int governor_enabled; struct cpufreq_interactive_tunables *cached_tunables; struct sched_load *sl; Loading Loading @@ -154,6 +157,9 @@ struct cpufreq_interactive_tunables { /* Ignore min_sample_time for notification */ bool fast_ramp_down; /* Whether to enable prediction or not */ bool enable_prediction; }; /* For cases where we have single governor instance for system */ Loading Loading @@ -433,28 +439,43 @@ static u64 update_load(int cpu) return now; } static unsigned int sl_busy_to_laf(struct cpufreq_interactive_policyinfo *ppol, unsigned long busy) { struct cpufreq_interactive_tunables *tunables = ppol->policy->governor_data; busy *= ppol->policy->cpuinfo.max_freq; return div64_s64(busy, tunables->timer_rate) * 100; } #define NEW_TASK_RATIO 75 #define PRED_TOLERANCE_PCT 10 static void cpufreq_interactive_timer(unsigned long data) { u64 now; s64 now; unsigned int delta_time; u64 cputime_speedadj; int cpu_load; int pol_load = 0; struct cpufreq_interactive_policyinfo *ppol = per_cpu(polinfo, data); struct cpufreq_interactive_tunables *tunables = ppol->policy->governor_data; struct sched_load *sl = ppol->sl; struct cpufreq_interactive_cpuinfo *pcpu; unsigned int new_freq; unsigned int loadadjfreq = 0, tmploadadjfreq; unsigned int prev_laf = 0, t_prevlaf; unsigned int pred_laf = 0, t_predlaf = 0; unsigned int prev_chfreq, pred_chfreq, chosen_freq; unsigned int index; unsigned long flags; unsigned long max_cpu; int i, fcpu; struct sched_load *sl; int cpu, i; int new_load_pct = 0; int prev_l, pred_l = 0; struct cpufreq_govinfo govinfo; bool skip_hispeed_logic, skip_min_sample_time; bool policy_max_fast_restore = false; bool jump_to_max_no_ts = false; bool jump_to_max = false; if (!down_read_trylock(&ppol->enable_sem)) Loading @@ -462,89 +483,106 @@ static void cpufreq_interactive_timer(unsigned long data) if (!ppol->governor_enabled) goto exit; fcpu = cpumask_first(ppol->policy->related_cpus); now = ktime_to_us(ktime_get()); spin_lock_irqsave(&ppol->target_freq_lock, flags); spin_lock(&ppol->load_lock); skip_hispeed_logic = tunables->ignore_hispeed_on_notif && ppol->notif_pending; skip_hispeed_logic = tunables->enable_prediction ? true : tunables->ignore_hispeed_on_notif && ppol->notif_pending; skip_min_sample_time = tunables->fast_ramp_down && ppol->notif_pending; ppol->notif_pending = false; now = ktime_to_us(ktime_get()); ppol->last_evaluated_jiffy = get_jiffies_64(); if (tunables->use_sched_load) sched_get_cpus_busy(ppol->sl, ppol->policy->related_cpus); sched_get_cpus_busy(sl, ppol->policy->cpus); max_cpu = cpumask_first(ppol->policy->cpus); for_each_cpu(i, ppol->policy->cpus) { pcpu = &per_cpu(cpuinfo, i); sl = &ppol->sl[i - fcpu]; i = 0; for_each_cpu(cpu, ppol->policy->cpus) { pcpu = &per_cpu(cpuinfo, cpu); if (tunables->use_sched_load) { cputime_speedadj = (u64)sl->prev_load * ppol->policy->cpuinfo.max_freq; do_div(cputime_speedadj, tunables->timer_rate); t_prevlaf = sl_busy_to_laf(ppol, sl[i].prev_load); prev_l = t_prevlaf / ppol->target_freq; if (tunables->enable_prediction) { t_predlaf = sl_busy_to_laf(ppol, sl[i].predicted_load); pred_l = t_predlaf / ppol->target_freq; } if (sl[i].prev_load) new_load_pct = sl[i].new_task_load * 100 / sl[i].prev_load; else new_load_pct = 0; if (sl->prev_load) new_load_pct = sl->new_task_load * 100 / sl->prev_load; } else { now = update_load(i); now = update_load(cpu); delta_time = (unsigned int) (now - pcpu->cputime_speedadj_timestamp); if (WARN_ON_ONCE(!delta_time)) continue; cputime_speedadj = pcpu->cputime_speedadj; do_div(cputime_speedadj, delta_time); t_prevlaf = (unsigned int)cputime_speedadj * 100; prev_l = t_prevlaf / ppol->target_freq; } tmploadadjfreq = (unsigned int)cputime_speedadj * 100; pcpu->loadadjfreq = tmploadadjfreq; if (tmploadadjfreq > loadadjfreq) { loadadjfreq = tmploadadjfreq; max_cpu = i; /* find max of loadadjfreq inside policy */ if (t_prevlaf > prev_laf) { prev_laf = t_prevlaf; max_cpu = cpu; } cpu_load = tmploadadjfreq / ppol->target_freq; trace_cpufreq_interactive_cpuload(i, cpu_load, new_load_pct); pred_laf = max(t_predlaf, pred_laf); cpu_load = max(prev_l, pred_l); pol_load = max(pol_load, cpu_load); trace_cpufreq_interactive_cpuload(cpu, cpu_load, new_load_pct, prev_l, pred_l); if (cpu_load >= tunables->go_hispeed_load && /* save loadadjfreq for notification */ pcpu->loadadjfreq = max(t_prevlaf, t_predlaf); /* detect heavy new task and jump to policy->max */ if (prev_l >= tunables->go_hispeed_load && new_load_pct >= NEW_TASK_RATIO) { skip_hispeed_logic = true; jump_to_max = true; } i++; } spin_unlock(&ppol->load_lock); cpu_load = loadadjfreq / ppol->target_freq; tunables->boosted = tunables->boost_val || now < tunables->boostpulse_endtime; prev_chfreq = choose_freq(ppol, prev_laf); pred_chfreq = choose_freq(ppol, pred_laf); chosen_freq = max(prev_chfreq, pred_chfreq); if (prev_chfreq < ppol->policy->max && pred_chfreq >= ppol->policy->max) if (!jump_to_max) jump_to_max_no_ts = true; if (now - ppol->max_freq_hyst_start_time < tunables->max_freq_hysteresis && cpu_load >= tunables->go_hispeed_load && pol_load >= tunables->go_hispeed_load && ppol->target_freq < ppol->policy->max) { skip_hispeed_logic = true; skip_min_sample_time = true; policy_max_fast_restore = true; if (!jump_to_max) jump_to_max_no_ts = true; } if (policy_max_fast_restore || jump_to_max) { new_freq = chosen_freq; if (jump_to_max_no_ts || jump_to_max) { new_freq = ppol->policy->cpuinfo.max_freq; } else if (skip_hispeed_logic) { new_freq = choose_freq(ppol, loadadjfreq); } else if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) { if (ppol->target_freq < tunables->hispeed_freq) { new_freq = tunables->hispeed_freq; } else { new_freq = choose_freq(ppol, loadadjfreq); if (new_freq < tunables->hispeed_freq) } else if (!skip_hispeed_logic) { if (pol_load >= tunables->go_hispeed_load || tunables->boosted) { if (ppol->target_freq < tunables->hispeed_freq) new_freq = tunables->hispeed_freq; else new_freq = max(new_freq, tunables->hispeed_freq); } } else { new_freq = choose_freq(ppol, loadadjfreq); if (new_freq > tunables->hispeed_freq && ppol->policy->cur < tunables->hispeed_freq) new_freq = tunables->hispeed_freq; } if (now - ppol->max_freq_hyst_start_time < Loading @@ -557,7 +595,7 @@ static void cpufreq_interactive_timer(unsigned long data) now - ppol->hispeed_validate_time < freq_to_above_hispeed_delay(tunables, ppol->target_freq)) { trace_cpufreq_interactive_notyet( max_cpu, cpu_load, ppol->target_freq, max_cpu, pol_load, ppol->target_freq, ppol->policy->cur, new_freq); spin_unlock_irqrestore(&ppol->target_freq_lock, flags); goto rearm; Loading @@ -582,7 +620,7 @@ static void cpufreq_interactive_timer(unsigned long data) if (now - ppol->floor_validate_time < tunables->min_sample_time) { trace_cpufreq_interactive_notyet( max_cpu, cpu_load, ppol->target_freq, max_cpu, pol_load, ppol->target_freq, ppol->policy->cur, new_freq); spin_unlock_irqrestore(&ppol->target_freq_lock, flags); goto rearm; Loading @@ -601,24 +639,24 @@ static void cpufreq_interactive_timer(unsigned long data) */ if ((!tunables->boosted || new_freq > tunables->hispeed_freq) && !policy_max_fast_restore) { && !jump_to_max_no_ts) { ppol->floor_freq = new_freq; ppol->floor_validate_time = now; } if (new_freq >= ppol->policy->max && !policy_max_fast_restore) if (new_freq >= ppol->policy->max && !jump_to_max_no_ts) ppol->max_freq_hyst_start_time = now; if (ppol->target_freq == new_freq && ppol->target_freq <= ppol->policy->cur) { trace_cpufreq_interactive_already( max_cpu, cpu_load, ppol->target_freq, max_cpu, pol_load, ppol->target_freq, ppol->policy->cur, new_freq); spin_unlock_irqrestore(&ppol->target_freq_lock, flags); goto rearm; } trace_cpufreq_interactive_target(max_cpu, cpu_load, ppol->target_freq, trace_cpufreq_interactive_target(max_cpu, pol_load, ppol->target_freq, ppol->policy->cur, new_freq); ppol->target_freq = new_freq; Loading Loading @@ -753,33 +791,51 @@ static int load_change_callback(struct notifier_block *nb, unsigned long val, struct cpufreq_interactive_tunables *tunables; unsigned long flags; if (speedchange_task == current) return 0; if (!ppol || ppol->reject_notification) return 0; if (!down_read_trylock(&ppol->enable_sem)) return 0; if (!ppol->governor_enabled) { if (!ppol->governor_enabled) goto exit; tunables = ppol->policy->governor_data; if (!tunables->use_sched_load || !tunables->use_migration_notif) goto exit; spin_lock_irqsave(&ppol->target_freq_lock, flags); ppol->notif_pending = true; ppol->notif_cpu = cpu; spin_unlock_irqrestore(&ppol->target_freq_lock, flags); if (!hrtimer_is_queued(&ppol->notif_timer)) hrtimer_start(&ppol->notif_timer, ms_to_ktime(1), HRTIMER_MODE_REL); exit: up_read(&ppol->enable_sem); return 0; } tunables = ppol->policy->governor_data; if (!tunables->use_sched_load || !tunables->use_migration_notif) { static enum hrtimer_restart cpufreq_interactive_hrtimer(struct hrtimer *timer) { struct cpufreq_interactive_policyinfo *ppol = container_of(timer, struct cpufreq_interactive_policyinfo, notif_timer); int cpu; if (!down_read_trylock(&ppol->enable_sem)) return 0; if (!ppol->governor_enabled) { up_read(&ppol->enable_sem); return 0; } cpu = ppol->notif_cpu; trace_cpufreq_interactive_load_change(cpu); spin_lock_irqsave(&ppol->target_freq_lock, flags); ppol->notif_pending = true; spin_unlock_irqrestore(&ppol->target_freq_lock, flags); del_timer(&ppol->policy_timer); del_timer(&ppol->policy_slack_timer); cpufreq_interactive_timer(cpu); up_read(&ppol->enable_sem); return 0; return HRTIMER_NORESTART; } static struct notifier_block load_notifier_block = { Loading Loading @@ -994,6 +1050,7 @@ show_store_one(max_freq_hysteresis); show_store_one(align_windows); show_store_one(ignore_hispeed_on_notif); show_store_one(fast_ramp_down); show_store_one(enable_prediction); static ssize_t show_go_hispeed_load(struct cpufreq_interactive_tunables *tunables, char *buf) Loading Loading @@ -1388,6 +1445,7 @@ show_store_gov_pol_sys(max_freq_hysteresis); show_store_gov_pol_sys(align_windows); show_store_gov_pol_sys(ignore_hispeed_on_notif); show_store_gov_pol_sys(fast_ramp_down); show_store_gov_pol_sys(enable_prediction); #define gov_sys_attr_rw(_name) \ static struct global_attr _name##_gov_sys = \ Loading Loading @@ -1417,6 +1475,7 @@ gov_sys_pol_attr_rw(max_freq_hysteresis); gov_sys_pol_attr_rw(align_windows); gov_sys_pol_attr_rw(ignore_hispeed_on_notif); gov_sys_pol_attr_rw(fast_ramp_down); gov_sys_pol_attr_rw(enable_prediction); static struct global_attr boostpulse_gov_sys = __ATTR(boostpulse, 0200, NULL, store_boostpulse_gov_sys); Loading @@ -1443,6 +1502,7 @@ static struct attribute *interactive_attributes_gov_sys[] = { &align_windows_gov_sys.attr, &ignore_hispeed_on_notif_gov_sys.attr, &fast_ramp_down_gov_sys.attr, &enable_prediction_gov_sys.attr, NULL, }; Loading Loading @@ -1470,6 +1530,7 @@ static struct attribute *interactive_attributes_gov_pol[] = { &align_windows_gov_pol.attr, &ignore_hispeed_on_notif_gov_pol.attr, &fast_ramp_down_gov_pol.attr, &enable_prediction_gov_pol.attr, NULL, }; Loading Loading @@ -1544,6 +1605,8 @@ static struct cpufreq_interactive_policyinfo *get_policyinfo( ppol->policy_timer.function = cpufreq_interactive_timer; init_timer(&ppol->policy_slack_timer); ppol->policy_slack_timer.function = cpufreq_interactive_nop_timer; hrtimer_init(&ppol->notif_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ppol->notif_timer.function = cpufreq_interactive_hrtimer; spin_lock_init(&ppol->load_lock); spin_lock_init(&ppol->target_freq_lock); init_rwsem(&ppol->enable_sem); Loading include/trace/events/cpufreq_interactive.h +13 −7 Original line number Diff line number Diff line Loading @@ -119,21 +119,27 @@ TRACE_EVENT(cpufreq_interactive_load_change, ); TRACE_EVENT(cpufreq_interactive_cpuload, TP_PROTO(unsigned long cpu_id, unsigned long load, unsigned int new_task_pct), TP_ARGS(cpu_id, load, new_task_pct), TP_PROTO(unsigned long cpu_id, unsigned int load, unsigned int new_task_pct, unsigned int prev, unsigned int predicted), TP_ARGS(cpu_id, load, new_task_pct, prev, predicted), TP_STRUCT__entry( __field(unsigned long, cpu_id) __field(unsigned long, load) __field(unsigned long, new_task_pct) __field(unsigned int, load) __field(unsigned int, new_task_pct) __field(unsigned int, prev) __field(unsigned int, predicted) ), TP_fast_assign( __entry->cpu_id = cpu_id; __entry->load = load; __entry->new_task_pct = new_task_pct; __entry->prev = prev; __entry->predicted = predicted; ), TP_printk("cpu=%lu load=%lu new_task_pct=%lu", __entry->cpu_id, __entry->load, __entry->new_task_pct) TP_printk("cpu=%lu load=%u new_task_pct=%u prev=%u predicted=%u", __entry->cpu_id, __entry->load, __entry->new_task_pct, __entry->prev, __entry->predicted) ); #endif /* _TRACE_CPUFREQ_INTERACTIVE_H */ Loading Loading
Documentation/cpu-freq/governors.txt +13 −3 Original line number Diff line number Diff line Loading @@ -312,9 +312,9 @@ information such as migration. If non-zero, this also implies governor sampling windows are aligned across CPUs, with same timer_rate, regardless what align_windows is set to. Default is zero. use_migration_notif: If non-zero, reevaluate CPU's frequency immediately after receiving notification from scheduler. If zero, ignore scheduler notification. Default is zero. use_migration_notif: If non-zero, schedule hrtimer to fire in 1ms to reevaluate frequency of notified CPU, unless the hrtimer is already pending. If zero, ignore scheduler notification. Default is zero. max_freq_hysteresis: Each time freq evaluation chooses policy->max, next max_freq_hysteresis is considered as hysteresis period. During Loading @@ -337,6 +337,16 @@ evaluation triggered by timer, min_sample_time is still always enforced. fast_ramp_down has no effect if use_migration_notif is set to zero. Default is zero. enable_prediction: If non-zero, two frequencies will be calculated during each sampling period: one based on busy time in previous sampling period (f_prev), and the other based on prediction provided by scheduler (f_pred). Max of both will be selected as final frequency. Hispeed related logic, including both frequency selection and delay is ignored if enable_prediction is set. If only f_pred but not f_prev picked policy->max, max_freq_hysteresis period is not started/extended. use_sched_load must be turned on before enabling this feature. Default is zero. 3. The Governor Interface in the CPUfreq Core ============================================= Loading
drivers/cpufreq/cpufreq_interactive.c +127 −64 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <linux/tick.h> #include <linux/time.h> #include <linux/timer.h> #include <linux/hrtimer.h> #include <linux/workqueue.h> #include <linux/kthread.h> #include <linux/slab.h> Loading @@ -37,6 +38,7 @@ struct cpufreq_interactive_policyinfo { struct timer_list policy_timer; struct timer_list policy_slack_timer; struct hrtimer notif_timer; spinlock_t load_lock; /* protects load tracking stat */ u64 last_evaluated_jiffy; struct cpufreq_policy *policy; Loading @@ -52,6 +54,7 @@ struct cpufreq_interactive_policyinfo { struct rw_semaphore enable_sem; bool reject_notification; bool notif_pending; unsigned long notif_cpu; int governor_enabled; struct cpufreq_interactive_tunables *cached_tunables; struct sched_load *sl; Loading Loading @@ -154,6 +157,9 @@ struct cpufreq_interactive_tunables { /* Ignore min_sample_time for notification */ bool fast_ramp_down; /* Whether to enable prediction or not */ bool enable_prediction; }; /* For cases where we have single governor instance for system */ Loading Loading @@ -433,28 +439,43 @@ static u64 update_load(int cpu) return now; } static unsigned int sl_busy_to_laf(struct cpufreq_interactive_policyinfo *ppol, unsigned long busy) { struct cpufreq_interactive_tunables *tunables = ppol->policy->governor_data; busy *= ppol->policy->cpuinfo.max_freq; return div64_s64(busy, tunables->timer_rate) * 100; } #define NEW_TASK_RATIO 75 #define PRED_TOLERANCE_PCT 10 static void cpufreq_interactive_timer(unsigned long data) { u64 now; s64 now; unsigned int delta_time; u64 cputime_speedadj; int cpu_load; int pol_load = 0; struct cpufreq_interactive_policyinfo *ppol = per_cpu(polinfo, data); struct cpufreq_interactive_tunables *tunables = ppol->policy->governor_data; struct sched_load *sl = ppol->sl; struct cpufreq_interactive_cpuinfo *pcpu; unsigned int new_freq; unsigned int loadadjfreq = 0, tmploadadjfreq; unsigned int prev_laf = 0, t_prevlaf; unsigned int pred_laf = 0, t_predlaf = 0; unsigned int prev_chfreq, pred_chfreq, chosen_freq; unsigned int index; unsigned long flags; unsigned long max_cpu; int i, fcpu; struct sched_load *sl; int cpu, i; int new_load_pct = 0; int prev_l, pred_l = 0; struct cpufreq_govinfo govinfo; bool skip_hispeed_logic, skip_min_sample_time; bool policy_max_fast_restore = false; bool jump_to_max_no_ts = false; bool jump_to_max = false; if (!down_read_trylock(&ppol->enable_sem)) Loading @@ -462,89 +483,106 @@ static void cpufreq_interactive_timer(unsigned long data) if (!ppol->governor_enabled) goto exit; fcpu = cpumask_first(ppol->policy->related_cpus); now = ktime_to_us(ktime_get()); spin_lock_irqsave(&ppol->target_freq_lock, flags); spin_lock(&ppol->load_lock); skip_hispeed_logic = tunables->ignore_hispeed_on_notif && ppol->notif_pending; skip_hispeed_logic = tunables->enable_prediction ? true : tunables->ignore_hispeed_on_notif && ppol->notif_pending; skip_min_sample_time = tunables->fast_ramp_down && ppol->notif_pending; ppol->notif_pending = false; now = ktime_to_us(ktime_get()); ppol->last_evaluated_jiffy = get_jiffies_64(); if (tunables->use_sched_load) sched_get_cpus_busy(ppol->sl, ppol->policy->related_cpus); sched_get_cpus_busy(sl, ppol->policy->cpus); max_cpu = cpumask_first(ppol->policy->cpus); for_each_cpu(i, ppol->policy->cpus) { pcpu = &per_cpu(cpuinfo, i); sl = &ppol->sl[i - fcpu]; i = 0; for_each_cpu(cpu, ppol->policy->cpus) { pcpu = &per_cpu(cpuinfo, cpu); if (tunables->use_sched_load) { cputime_speedadj = (u64)sl->prev_load * ppol->policy->cpuinfo.max_freq; do_div(cputime_speedadj, tunables->timer_rate); t_prevlaf = sl_busy_to_laf(ppol, sl[i].prev_load); prev_l = t_prevlaf / ppol->target_freq; if (tunables->enable_prediction) { t_predlaf = sl_busy_to_laf(ppol, sl[i].predicted_load); pred_l = t_predlaf / ppol->target_freq; } if (sl[i].prev_load) new_load_pct = sl[i].new_task_load * 100 / sl[i].prev_load; else new_load_pct = 0; if (sl->prev_load) new_load_pct = sl->new_task_load * 100 / sl->prev_load; } else { now = update_load(i); now = update_load(cpu); delta_time = (unsigned int) (now - pcpu->cputime_speedadj_timestamp); if (WARN_ON_ONCE(!delta_time)) continue; cputime_speedadj = pcpu->cputime_speedadj; do_div(cputime_speedadj, delta_time); t_prevlaf = (unsigned int)cputime_speedadj * 100; prev_l = t_prevlaf / ppol->target_freq; } tmploadadjfreq = (unsigned int)cputime_speedadj * 100; pcpu->loadadjfreq = tmploadadjfreq; if (tmploadadjfreq > loadadjfreq) { loadadjfreq = tmploadadjfreq; max_cpu = i; /* find max of loadadjfreq inside policy */ if (t_prevlaf > prev_laf) { prev_laf = t_prevlaf; max_cpu = cpu; } cpu_load = tmploadadjfreq / ppol->target_freq; trace_cpufreq_interactive_cpuload(i, cpu_load, new_load_pct); pred_laf = max(t_predlaf, pred_laf); cpu_load = max(prev_l, pred_l); pol_load = max(pol_load, cpu_load); trace_cpufreq_interactive_cpuload(cpu, cpu_load, new_load_pct, prev_l, pred_l); if (cpu_load >= tunables->go_hispeed_load && /* save loadadjfreq for notification */ pcpu->loadadjfreq = max(t_prevlaf, t_predlaf); /* detect heavy new task and jump to policy->max */ if (prev_l >= tunables->go_hispeed_load && new_load_pct >= NEW_TASK_RATIO) { skip_hispeed_logic = true; jump_to_max = true; } i++; } spin_unlock(&ppol->load_lock); cpu_load = loadadjfreq / ppol->target_freq; tunables->boosted = tunables->boost_val || now < tunables->boostpulse_endtime; prev_chfreq = choose_freq(ppol, prev_laf); pred_chfreq = choose_freq(ppol, pred_laf); chosen_freq = max(prev_chfreq, pred_chfreq); if (prev_chfreq < ppol->policy->max && pred_chfreq >= ppol->policy->max) if (!jump_to_max) jump_to_max_no_ts = true; if (now - ppol->max_freq_hyst_start_time < tunables->max_freq_hysteresis && cpu_load >= tunables->go_hispeed_load && pol_load >= tunables->go_hispeed_load && ppol->target_freq < ppol->policy->max) { skip_hispeed_logic = true; skip_min_sample_time = true; policy_max_fast_restore = true; if (!jump_to_max) jump_to_max_no_ts = true; } if (policy_max_fast_restore || jump_to_max) { new_freq = chosen_freq; if (jump_to_max_no_ts || jump_to_max) { new_freq = ppol->policy->cpuinfo.max_freq; } else if (skip_hispeed_logic) { new_freq = choose_freq(ppol, loadadjfreq); } else if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) { if (ppol->target_freq < tunables->hispeed_freq) { new_freq = tunables->hispeed_freq; } else { new_freq = choose_freq(ppol, loadadjfreq); if (new_freq < tunables->hispeed_freq) } else if (!skip_hispeed_logic) { if (pol_load >= tunables->go_hispeed_load || tunables->boosted) { if (ppol->target_freq < tunables->hispeed_freq) new_freq = tunables->hispeed_freq; else new_freq = max(new_freq, tunables->hispeed_freq); } } else { new_freq = choose_freq(ppol, loadadjfreq); if (new_freq > tunables->hispeed_freq && ppol->policy->cur < tunables->hispeed_freq) new_freq = tunables->hispeed_freq; } if (now - ppol->max_freq_hyst_start_time < Loading @@ -557,7 +595,7 @@ static void cpufreq_interactive_timer(unsigned long data) now - ppol->hispeed_validate_time < freq_to_above_hispeed_delay(tunables, ppol->target_freq)) { trace_cpufreq_interactive_notyet( max_cpu, cpu_load, ppol->target_freq, max_cpu, pol_load, ppol->target_freq, ppol->policy->cur, new_freq); spin_unlock_irqrestore(&ppol->target_freq_lock, flags); goto rearm; Loading @@ -582,7 +620,7 @@ static void cpufreq_interactive_timer(unsigned long data) if (now - ppol->floor_validate_time < tunables->min_sample_time) { trace_cpufreq_interactive_notyet( max_cpu, cpu_load, ppol->target_freq, max_cpu, pol_load, ppol->target_freq, ppol->policy->cur, new_freq); spin_unlock_irqrestore(&ppol->target_freq_lock, flags); goto rearm; Loading @@ -601,24 +639,24 @@ static void cpufreq_interactive_timer(unsigned long data) */ if ((!tunables->boosted || new_freq > tunables->hispeed_freq) && !policy_max_fast_restore) { && !jump_to_max_no_ts) { ppol->floor_freq = new_freq; ppol->floor_validate_time = now; } if (new_freq >= ppol->policy->max && !policy_max_fast_restore) if (new_freq >= ppol->policy->max && !jump_to_max_no_ts) ppol->max_freq_hyst_start_time = now; if (ppol->target_freq == new_freq && ppol->target_freq <= ppol->policy->cur) { trace_cpufreq_interactive_already( max_cpu, cpu_load, ppol->target_freq, max_cpu, pol_load, ppol->target_freq, ppol->policy->cur, new_freq); spin_unlock_irqrestore(&ppol->target_freq_lock, flags); goto rearm; } trace_cpufreq_interactive_target(max_cpu, cpu_load, ppol->target_freq, trace_cpufreq_interactive_target(max_cpu, pol_load, ppol->target_freq, ppol->policy->cur, new_freq); ppol->target_freq = new_freq; Loading Loading @@ -753,33 +791,51 @@ static int load_change_callback(struct notifier_block *nb, unsigned long val, struct cpufreq_interactive_tunables *tunables; unsigned long flags; if (speedchange_task == current) return 0; if (!ppol || ppol->reject_notification) return 0; if (!down_read_trylock(&ppol->enable_sem)) return 0; if (!ppol->governor_enabled) { if (!ppol->governor_enabled) goto exit; tunables = ppol->policy->governor_data; if (!tunables->use_sched_load || !tunables->use_migration_notif) goto exit; spin_lock_irqsave(&ppol->target_freq_lock, flags); ppol->notif_pending = true; ppol->notif_cpu = cpu; spin_unlock_irqrestore(&ppol->target_freq_lock, flags); if (!hrtimer_is_queued(&ppol->notif_timer)) hrtimer_start(&ppol->notif_timer, ms_to_ktime(1), HRTIMER_MODE_REL); exit: up_read(&ppol->enable_sem); return 0; } tunables = ppol->policy->governor_data; if (!tunables->use_sched_load || !tunables->use_migration_notif) { static enum hrtimer_restart cpufreq_interactive_hrtimer(struct hrtimer *timer) { struct cpufreq_interactive_policyinfo *ppol = container_of(timer, struct cpufreq_interactive_policyinfo, notif_timer); int cpu; if (!down_read_trylock(&ppol->enable_sem)) return 0; if (!ppol->governor_enabled) { up_read(&ppol->enable_sem); return 0; } cpu = ppol->notif_cpu; trace_cpufreq_interactive_load_change(cpu); spin_lock_irqsave(&ppol->target_freq_lock, flags); ppol->notif_pending = true; spin_unlock_irqrestore(&ppol->target_freq_lock, flags); del_timer(&ppol->policy_timer); del_timer(&ppol->policy_slack_timer); cpufreq_interactive_timer(cpu); up_read(&ppol->enable_sem); return 0; return HRTIMER_NORESTART; } static struct notifier_block load_notifier_block = { Loading Loading @@ -994,6 +1050,7 @@ show_store_one(max_freq_hysteresis); show_store_one(align_windows); show_store_one(ignore_hispeed_on_notif); show_store_one(fast_ramp_down); show_store_one(enable_prediction); static ssize_t show_go_hispeed_load(struct cpufreq_interactive_tunables *tunables, char *buf) Loading Loading @@ -1388,6 +1445,7 @@ show_store_gov_pol_sys(max_freq_hysteresis); show_store_gov_pol_sys(align_windows); show_store_gov_pol_sys(ignore_hispeed_on_notif); show_store_gov_pol_sys(fast_ramp_down); show_store_gov_pol_sys(enable_prediction); #define gov_sys_attr_rw(_name) \ static struct global_attr _name##_gov_sys = \ Loading Loading @@ -1417,6 +1475,7 @@ gov_sys_pol_attr_rw(max_freq_hysteresis); gov_sys_pol_attr_rw(align_windows); gov_sys_pol_attr_rw(ignore_hispeed_on_notif); gov_sys_pol_attr_rw(fast_ramp_down); gov_sys_pol_attr_rw(enable_prediction); static struct global_attr boostpulse_gov_sys = __ATTR(boostpulse, 0200, NULL, store_boostpulse_gov_sys); Loading @@ -1443,6 +1502,7 @@ static struct attribute *interactive_attributes_gov_sys[] = { &align_windows_gov_sys.attr, &ignore_hispeed_on_notif_gov_sys.attr, &fast_ramp_down_gov_sys.attr, &enable_prediction_gov_sys.attr, NULL, }; Loading Loading @@ -1470,6 +1530,7 @@ static struct attribute *interactive_attributes_gov_pol[] = { &align_windows_gov_pol.attr, &ignore_hispeed_on_notif_gov_pol.attr, &fast_ramp_down_gov_pol.attr, &enable_prediction_gov_pol.attr, NULL, }; Loading Loading @@ -1544,6 +1605,8 @@ static struct cpufreq_interactive_policyinfo *get_policyinfo( ppol->policy_timer.function = cpufreq_interactive_timer; init_timer(&ppol->policy_slack_timer); ppol->policy_slack_timer.function = cpufreq_interactive_nop_timer; hrtimer_init(&ppol->notif_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ppol->notif_timer.function = cpufreq_interactive_hrtimer; spin_lock_init(&ppol->load_lock); spin_lock_init(&ppol->target_freq_lock); init_rwsem(&ppol->enable_sem); Loading
include/trace/events/cpufreq_interactive.h +13 −7 Original line number Diff line number Diff line Loading @@ -119,21 +119,27 @@ TRACE_EVENT(cpufreq_interactive_load_change, ); TRACE_EVENT(cpufreq_interactive_cpuload, TP_PROTO(unsigned long cpu_id, unsigned long load, unsigned int new_task_pct), TP_ARGS(cpu_id, load, new_task_pct), TP_PROTO(unsigned long cpu_id, unsigned int load, unsigned int new_task_pct, unsigned int prev, unsigned int predicted), TP_ARGS(cpu_id, load, new_task_pct, prev, predicted), TP_STRUCT__entry( __field(unsigned long, cpu_id) __field(unsigned long, load) __field(unsigned long, new_task_pct) __field(unsigned int, load) __field(unsigned int, new_task_pct) __field(unsigned int, prev) __field(unsigned int, predicted) ), TP_fast_assign( __entry->cpu_id = cpu_id; __entry->load = load; __entry->new_task_pct = new_task_pct; __entry->prev = prev; __entry->predicted = predicted; ), TP_printk("cpu=%lu load=%lu new_task_pct=%lu", __entry->cpu_id, __entry->load, __entry->new_task_pct) TP_printk("cpu=%lu load=%u new_task_pct=%u prev=%u predicted=%u", __entry->cpu_id, __entry->load, __entry->new_task_pct, __entry->prev, __entry->predicted) ); #endif /* _TRACE_CPUFREQ_INTERACTIVE_H */ Loading