summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sched/core.c100
-rw-r--r--kernel/sched/sched.h1
-rw-r--r--kernel/sysctl.c7
3 files changed, 103 insertions, 5 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index ae6e90e167b2..5bab9845df71 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -812,6 +812,22 @@ void sched_set_cluster_dstate(const cpumask_t *cluster_cpus, int dstate,
#endif /* CONFIG_SMP */
+#ifdef CONFIG_SCHED_HMP
+static inline void clear_ed_task(struct task_struct *p, struct rq *rq)
+{
+ if (p == rq->ed_task)
+ rq->ed_task = NULL;
+}
+
+static inline void set_task_last_wake(struct task_struct *p, u64 wallclock)
+{
+ p->last_wake_ts = wallclock;
+}
+#else
+static inline void clear_ed_task(struct task_struct *p, struct rq *rq) {}
+static inline void set_task_last_wake(struct task_struct *p, u64 wallclock) {}
+#endif
+
#if defined(CONFIG_RT_GROUP_SCHED) || (defined(CONFIG_FAIR_GROUP_SCHED) && \
(defined(CONFIG_SMP) || defined(CONFIG_CFS_BANDWIDTH)))
/*
@@ -906,6 +922,9 @@ void deactivate_task(struct rq *rq, struct task_struct *p, int flags)
if (task_contributes_to_load(p))
rq->nr_uninterruptible++;
+ if (flags & DEQUEUE_SLEEP)
+ clear_ed_task(p, rq);
+
dequeue_task(rq, p, flags);
}
@@ -1218,6 +1237,13 @@ static inline void clear_hmp_request(int cpu) { }
* IMPORTANT: Initialize both copies to same value!!
*/
+/*
+ * Tasks that are runnable continuously for a period greather than
+ * sysctl_early_detection_duration can be flagged early as potential
+ * high load tasks.
+ */
+__read_mostly unsigned int sysctl_early_detection_duration = 9500000;
+
static __read_mostly unsigned int sched_ravg_hist_size = 5;
__read_mostly unsigned int sysctl_sched_ravg_hist_size = 5;
@@ -2123,7 +2149,7 @@ static inline void mark_task_starting(struct task_struct *p)
return;
}
- p->ravg.mark_start = wallclock;
+ p->ravg.mark_start = p->last_wake_ts = wallclock;
}
static inline void set_window_start(struct rq *rq)
@@ -2196,6 +2222,7 @@ void sched_exit(struct task_struct *p)
p->ravg.mark_start = wallclock;
p->ravg.sum_history[0] = EXITING_TASK_MARKER;
enqueue_task(rq, p, 0);
+ clear_ed_task(p, rq);
raw_spin_unlock_irqrestore(&rq->lock, flags);
put_cpu();
@@ -2341,6 +2368,7 @@ void sched_get_cpus_busy(struct sched_load *busy,
u64 load[cpus], nload[cpus];
unsigned int cur_freq[cpus], max_freq[cpus];
int notifier_sent[cpus];
+ int early_detection[cpus];
int cpu, i = 0;
unsigned int window_size;
@@ -2374,6 +2402,7 @@ void sched_get_cpus_busy(struct sched_load *busy,
nload[i] = scale_load_to_cpu(nload[i], cpu);
notifier_sent[i] = rq->notifier_sent;
+ early_detection[i] = (rq->ed_task != NULL);
rq->notifier_sent = 0;
cur_freq[i] = rq->cur_freq;
max_freq[i] = rq->max_freq;
@@ -2388,6 +2417,13 @@ void sched_get_cpus_busy(struct sched_load *busy,
for_each_cpu(cpu, query_cpus) {
rq = cpu_rq(cpu);
+ if (early_detection[i]) {
+ busy[i].prev_load = div64_u64(sched_ravg_window,
+ NSEC_PER_USEC);
+ busy[i].new_task_load = 0;
+ goto exit_early;
+ }
+
if (!notifier_sent[i]) {
load[i] = scale_load_to_freq(load[i], max_freq[i],
cur_freq[i]);
@@ -2412,8 +2448,9 @@ void sched_get_cpus_busy(struct sched_load *busy,
busy[i].prev_load = div64_u64(load[i], NSEC_PER_USEC);
busy[i].new_task_load = div64_u64(nload[i], NSEC_PER_USEC);
+exit_early:
trace_sched_get_busy(cpu, busy[i].prev_load,
- busy[i].new_task_load);
+ busy[i].new_task_load, early_detection[i]);
i++;
}
}
@@ -2481,9 +2518,14 @@ static void fixup_busy_time(struct task_struct *p, int new_cpu)
bool new_task;
if (!sched_enable_hmp || !sched_migration_fixup ||
- exiting_task(p) || (!p->on_rq && p->state != TASK_WAKING))
+ (!p->on_rq && p->state != TASK_WAKING))
return;
+ if (exiting_task(p)) {
+ clear_ed_task(p, src_rq);
+ return;
+ }
+
if (p->state == TASK_WAKING)
double_rq_lock(src_rq, dest_rq);
@@ -2521,6 +2563,12 @@ static void fixup_busy_time(struct task_struct *p, int new_cpu)
}
}
+ if (p == src_rq->ed_task) {
+ src_rq->ed_task = NULL;
+ if (!dest_rq->ed_task)
+ dest_rq->ed_task = p;
+ }
+
BUG_ON((s64)src_rq->prev_runnable_sum < 0);
BUG_ON((s64)src_rq->curr_runnable_sum < 0);
BUG_ON((s64)src_rq->nt_prev_runnable_sum < 0);
@@ -3927,8 +3975,9 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
wake_flags |= WF_MIGRATED;
set_task_cpu(p, cpu);
}
-#endif /* CONFIG_SMP */
+ set_task_last_wake(p, wallclock);
+#endif /* CONFIG_SMP */
ttwu_queue(p, cpu);
stat:
ttwu_stat(p, cpu, wake_flags);
@@ -4013,6 +4062,7 @@ static void try_to_wake_up_local(struct task_struct *p)
update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0);
update_task_ravg(p, rq, TASK_WAKE, wallclock, 0);
ttwu_activate(rq, p, ENQUEUE_WAKEUP);
+ set_task_last_wake(p, wallclock);
}
ttwu_do_wakeup(rq, p, 0);
@@ -4832,6 +4882,38 @@ unsigned long long task_sched_runtime(struct task_struct *p)
return ns;
}
+#ifdef CONFIG_SCHED_HMP
+static bool early_detection_notify(struct rq *rq, u64 wallclock)
+{
+ struct task_struct *p;
+ int loop_max = 10;
+
+ if (!sched_boost() || !rq->cfs.h_nr_running)
+ return 0;
+
+ rq->ed_task = NULL;
+ list_for_each_entry(p, &rq->cfs_tasks, se.group_node) {
+ if (!loop_max)
+ break;
+
+ if (wallclock - p->last_wake_ts >=
+ sysctl_early_detection_duration) {
+ rq->ed_task = p;
+ return 1;
+ }
+
+ loop_max--;
+ }
+
+ return 0;
+}
+#else /* CONFIG_SCHED_HMP */
+static bool early_detection_notify(struct rq *rq, u64 wallclock)
+{
+ return 0;
+}
+#endif /* CONFIG_SCHED_HMP */
+
/*
* This function gets called by the timer code, with HZ frequency.
* We call it with interrupts disabled.
@@ -4841,6 +4923,8 @@ void scheduler_tick(void)
int cpu = smp_processor_id();
struct rq *rq = cpu_rq(cpu);
struct task_struct *curr = rq->curr;
+ u64 wallclock;
+ bool early_notif;
sched_clock_tick();
@@ -4850,9 +4934,15 @@ void scheduler_tick(void)
curr->sched_class->task_tick(rq, curr, 0);
update_cpu_load_active(rq);
calc_global_load_tick(rq);
- update_task_ravg(rq->curr, rq, TASK_UPDATE, sched_clock(), 0);
+ wallclock = sched_clock();
+ update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0);
+ early_notif = early_detection_notify(rq, wallclock);
raw_spin_unlock(&rq->lock);
+ if (early_notif)
+ atomic_notifier_call_chain(&load_alert_notifier_head,
+ 0, (void *)(long)cpu);
+
perf_event_task_tick();
#ifdef CONFIG_SMP
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 183dca8f05d8..2045dec5e80c 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -698,6 +698,7 @@ struct rq {
u64 irqload_ts;
unsigned int static_cpu_pwr_cost;
unsigned int static_cluster_pwr_cost;
+ struct task_struct *ed_task;
#ifdef CONFIG_SCHED_FREQ_INPUT
unsigned int old_busy_time;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 369120e75efe..509d59837983 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -439,6 +439,13 @@ static struct ctl_table kern_table[] = {
.proc_handler = sched_window_update_handler,
},
{
+ .procname = "sched_early_detection_duration",
+ .data = &sysctl_early_detection_duration,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
.procname = "sched_boost",
.data = &sysctl_sched_boost,
.maxlen = sizeof(unsigned int),