sched: notify cpufreq on over/underprovisioned CPUs

After a migration occurs the source and destination CPUs may
not be running at frequencies which match the new task load on
those CPUs.

Previously, the scheduler was notifying cpufreq anytime a task
greater than a certain size migrates. This is suboptimal however
since this does not take into account the CPU's current
frequency and other task activity that may be present.

Change-Id: I5092bda3a517e1343f97e5a455957c25ee19b549
Signed-off-by: Steve Muckle <smuckle@codeaurora.org>
This commit is contained in:
Steve Muckle 2014-06-12 12:14:15 -07:00
parent dbd2db2471
commit 80753c7e5e
3 changed files with 72 additions and 30 deletions

View File

@ -43,7 +43,10 @@ extern unsigned int sysctl_sched_window_stats_policy;
extern unsigned int sysctl_sched_init_task_load_pct;
#endif
extern unsigned int sysctl_sched_task_migrate_notify_pct;
#ifdef CONFIG_SCHED_FREQ_INPUT
extern int sysctl_sched_freq_inc_notify_slack_pct;
extern int sysctl_sched_freq_dec_notify_slack_pct;
#endif
#ifdef CONFIG_SCHED_HMP
extern unsigned int sysctl_sched_enable_hmp_task_placement;

View File

@ -1019,27 +1019,29 @@ unsigned int __read_mostly sched_use_pelt;
unsigned int max_possible_efficiency = 1024;
unsigned int min_possible_efficiency = 1024;
__read_mostly unsigned int sysctl_sched_task_migrate_notify_pct = 25;
unsigned int sched_task_migrate_notify;
__read_mostly int sysctl_sched_freq_inc_notify_slack_pct;
__read_mostly int sysctl_sched_freq_dec_notify_slack_pct = 25;
int sched_migrate_notify_proc_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
/* Returns how undercommitted a CPU is given its current frequency and
* task load (as measured in the previous window). Returns this value
* as a percentage of the CPU's maximum frequency. A negative value
* means the CPU is overcommitted at its current frequency.
*/
int rq_freq_margin(struct rq *rq)
{
int ret;
unsigned int *data = (unsigned int *)table->data;
unsigned int freq_required;
int margin;
ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
if (ret || !write)
return ret;
freq_required = scale_task_load(rq->prev_runnable_sum, rq->cpu);
freq_required *= 128;
freq_required /= max_task_load();
freq_required *= rq->max_possible_freq;
freq_required /= 128;
if (*data > 100)
return -EINVAL;
sched_task_migrate_notify = div64_u64((u64)*data *
(u64)max_task_load(), 100);
return 0;
margin = rq->cur_freq - freq_required;
margin *= 100;
margin /= (int)rq->max_possible_freq;
return margin;
}
/*
@ -1366,6 +1368,11 @@ update_task_ravg(struct task_struct *p, struct rq *rq,
{
}
static inline int rq_freq_margin(struct rq *rq)
{
return INT_MAX;
}
static inline void init_cpu_efficiency(void) {}
static inline void mark_task_starting(struct task_struct *p) {}
@ -1448,23 +1455,33 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
if (p->state == TASK_WAKING)
double_rq_unlock(src_rq, dest_rq);
/* Is p->ravg.prev_window significant? Trigger a load
alert notifier if so. */
if (p->ravg.prev_window > sched_task_migrate_notify &&
!cpumask_test_cpu(new_cpu,
&src_rq->freq_domain_cpumask)) {
atomic_notifier_call_chain(
&load_alert_notifier_head, 0,
(void *)task_cpu(p));
if (cpumask_test_cpu(new_cpu,
&src_rq->freq_domain_cpumask))
goto done;
/* Evaluate possible frequency notifications for
* source and destination CPUs in different frequency
* domains. */
if (rq_freq_margin(dest_rq) <
sysctl_sched_freq_inc_notify_slack_pct)
atomic_notifier_call_chain(
&load_alert_notifier_head, 0,
(void *)new_cpu);
}
if (rq_freq_margin(src_rq) >
sysctl_sched_freq_dec_notify_slack_pct)
atomic_notifier_call_chain(
&load_alert_notifier_head, 0,
(void *)task_cpu(p));
}
#endif
}
#if defined(CONFIG_SCHED_FREQ_INPUT) || defined(CONFIG_SCHED_HMP)
done:
#endif
__set_task_cpu(p, new_cpu);
}
@ -1978,6 +1995,14 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
if (src_cpu != cpu) {
wake_flags |= WF_MIGRATED;
set_task_cpu(p, cpu);
} else {
#ifdef CONFIG_SCHED_FREQ_INPUT
if (rq_freq_margin(cpu_rq(cpu)) <
sysctl_sched_freq_inc_notify_slack_pct)
atomic_notifier_call_chain(
&load_alert_notifier_head, 0,
(void *)cpu);
#endif
}
#endif /* CONFIG_SMP */
@ -2245,6 +2270,13 @@ void wake_up_new_task(struct task_struct *p)
rq = __task_rq_lock(p);
mark_task_starting(p);
#ifdef CONFIG_SCHED_FREQ_INPUT
if (rq_freq_margin(task_rq(p)) <
sysctl_sched_freq_inc_notify_slack_pct)
atomic_notifier_call_chain(
&load_alert_notifier_head, 0,
(void *)task_cpu(p));
#endif
activate_task(rq, p, 0);
p->on_rq = 1;
trace_sched_wakeup_new(p, true);

View File

@ -296,11 +296,18 @@ static struct ctl_table kern_table[] = {
},
#ifdef CONFIG_SCHED_FREQ_INPUT
{
.procname = "sched_task_migrate_notify",
.data = &sysctl_sched_task_migrate_notify_pct,
.procname = "sched_freq_inc_notify_slack_pct",
.data = &sysctl_sched_freq_inc_notify_slack_pct,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = sched_migrate_notify_proc_handler,
.proc_handler = proc_dointvec,
},
{
.procname = "sched_freq_dec_notify_slack_pct",
.data = &sysctl_sched_freq_dec_notify_slack_pct,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
#endif
#if defined(CONFIG_SCHED_FREQ_INPUT) || defined(CONFIG_SCHED_HMP)