| From a90db8ff845312a69ec48d2f5668aa9644cbe0c4 Mon Sep 17 00:00:00 2001 |
| From: Syed Rameez Mustafa <rameezmustafa@codeaurora.org> |
| Date: Fri, 16 Dec 2016 11:59:05 -0800 |
| Subject: [PATCH] NOUPSTREAM: ANDROID: cpu-hotplug: Always use real time |
| scheduling when hotplugging a CPU |
| |
| CPU hotplug operations take place in preemptible context. This leaves |
| the hotplugging thread at the mercy of overall system load and CPU |
| availability. If the hotplugging thread does not get an opportunity |
| to execute after it has already begun a hotplug operation, CPUs can |
| end up being stuck in a quasi online state. In the worst case a CPU |
| can be stuck in a state where the migration thread is parked while |
| another task is executing and changing affinity in a loop. This |
| combination can result in unbounded execution time for the running |
| task until the hotplugging thread gets the chance to run to complete |
| the hotplug operation. |
| |
| Fix the said problem by ensuring that hotplug can only occur from |
| threads belonging to the RT sched class. This allows the hotplugging |
| thread priority on the CPU no matter what the system load or the |
| number of available CPUs are. If a SCHED_NORMAL task attempts to |
| hotplug a CPU, we temporarily elevate it's scheduling policy to RT. |
| Furthermore, we disallow hotplugging operations to begin if the |
| calling task belongs to the idle and deadline classes or those that |
| use the SCHED_BATCH policy. |
| |
| [CPNOTE: 30/06/21] Lee: Vendor workaround - asked if this is still required via the bug |
| [CPNOTE: 30/09/21] Lee: Still no answer - if no one replies we should try and revert his 5 year old patch |
| |
| Bug: 169238689 |
| Change-Id: Idbb1384626e6ddff46c0d2ce752eee68396c78af |
| Signed-off-by: Syed Rameez Mustafa <rameezmustafa@codeaurora.org> |
| [psodagud@codeaurora.org: Fixed compilation issues] |
| Signed-off-by: Prasad Sodagudi <psodagud@codeaurora.org> |
| --- |
| kernel/cpu.c | 43 ++++++++++++++++++++++++++++++++++++++++++- |
| kernel/sched/fair.c | 3 ++- |
| 2 files changed, 44 insertions(+), 2 deletions(-) |
| |
| diff --git a/kernel/cpu.c b/kernel/cpu.c |
| index ded343fa13a4..0fb2d33e62d3 100644 |
| --- a/kernel/cpu.c |
| +++ b/kernel/cpu.c |
| @@ -34,6 +34,7 @@ |
| #include <linux/scs.h> |
| #include <linux/percpu-rwsem.h> |
| #include <linux/cpuset.h> |
| +#include <uapi/linux/sched/types.h> |
| #include <linux/random.h> |
| |
| #include <trace/events/power.h> |
| @@ -1320,6 +1321,25 @@ void cpuhp_online_idle(enum cpuhp_state state) |
| complete_ap_thread(st, true); |
| } |
| |
| +static int switch_to_rt_policy(void) |
| +{ |
| + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; |
| + unsigned int policy = current->policy; |
| + |
| + if (policy == SCHED_NORMAL) |
| + /* Switch to SCHED_FIFO from SCHED_NORMAL. */ |
| + return sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m); |
| + else |
| + return 1; |
| +} |
| + |
| +static int switch_to_fair_policy(void) |
| +{ |
| + struct sched_param param = { .sched_priority = 0 }; |
| + |
| + return sched_setscheduler_nocheck(current, SCHED_NORMAL, ¶m); |
| +} |
| + |
| /* Requires cpu_add_remove_lock to be held */ |
| static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target) |
| { |
| @@ -1384,6 +1404,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target) |
| static int cpu_up(unsigned int cpu, enum cpuhp_state target) |
| { |
| int err = 0; |
| + int switch_err; |
| |
| if (!cpu_possible(cpu)) { |
| pr_err("can't online cpu %d because it is not configured as may-hotadd at boot time\n", |
| @@ -1394,9 +1415,21 @@ static int cpu_up(unsigned int cpu, enum cpuhp_state target) |
| return -EINVAL; |
| } |
| |
| + /* |
| + * CPU hotplug operations consists of many steps and each step |
| + * calls a callback of core kernel subsystem. CPU hotplug-in |
| + * operation may get preempted by other CFS tasks and whole |
| + * operation of cpu hotplug in CPU gets delayed. Switch the |
| + * current task to SCHED_FIFO from SCHED_NORMAL, so that |
| + * hotplug in operation may complete quickly in heavy loaded |
| + * conditions and new CPU will start handle the workload. |
| + */ |
| + |
| + switch_err = switch_to_rt_policy(); |
| + |
| err = try_online_node(cpu_to_node(cpu)); |
| if (err) |
| - return err; |
| + goto switch_out; |
| |
| cpu_maps_update_begin(); |
| |
| @@ -1412,6 +1445,14 @@ static int cpu_up(unsigned int cpu, enum cpuhp_state target) |
| err = _cpu_up(cpu, 0, target); |
| out: |
| cpu_maps_update_done(); |
| +switch_out: |
| + if (!switch_err) { |
| + switch_err = switch_to_fair_policy(); |
| + if (switch_err) |
| + pr_err("Hotplug policy switch err=%d Task %s pid=%d\n", |
| + switch_err, current->comm, current->pid); |
| + } |
| + |
| return err; |
| } |
| |
| diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c |
| index 9fa41b8fbde1..e433ba2723f0 100644 |
| --- a/kernel/sched/fair.c |
| +++ b/kernel/sched/fair.c |
| @@ -6803,7 +6803,8 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy |
| |
| cpu = smp_processor_id(); |
| if (sync && cpu_rq(cpu)->nr_running == 1 && |
| - cpumask_test_cpu(cpu, p->cpus_ptr)) { |
| + cpumask_test_cpu(cpu, p->cpus_ptr) && |
| + task_fits_capacity(p, capacity_of(cpu))) { |
| rcu_read_unlock(); |
| return cpu; |
| } |
| -- |
| 2.35.0 |
| |