From b30e1d54a557c7168184b61725567292c424bf0c Mon Sep 17 00:00:00 2001 From: Shaleen Agrawal Date: Wed, 20 Apr 2022 18:07:13 -0700 Subject: [PATCH 01/12] sched: walt: enable early migrate for topapp Create nodes to enable top-app tasks to upmigrate faster to gold cores. Change-Id: If06ddf23b13d6277e66cf5dffa537a75e7902089 Signed-off-by: Shaleen Agrawal --- kernel/sched/walt/sysctl.c | 81 ++++++++++++++++++++++++++++++++++++++ kernel/sched/walt/walt.h | 33 +++++++++++----- 2 files changed, 105 insertions(+), 9 deletions(-) diff --git a/kernel/sched/walt/sysctl.c b/kernel/sched/walt/sysctl.c index 0e8439d33799..56a5608bf11f 100644 --- a/kernel/sched/walt/sysctl.c +++ b/kernel/sched/walt/sysctl.c @@ -47,6 +47,8 @@ unsigned int sysctl_sched_wake_up_idle[2]; unsigned int sysctl_input_boost_ms; unsigned int sysctl_input_boost_freq[8]; unsigned int sysctl_sched_boost_on_input; +unsigned int sysctl_sched_early_up[MAX_MARGIN_LEVELS]; +unsigned int sysctl_sched_early_down[MAX_MARGIN_LEVELS]; /* sysctl nodes accesed by other files */ unsigned int __read_mostly sysctl_sched_coloc_downmigrate_ns; @@ -457,6 +459,69 @@ int sched_updown_migrate_handler(struct ctl_table *table, int write, /* update individual cpu thresholds */ sched_update_updown_migrate_values(data == &sysctl_sched_capacity_margin_up_pct[0]); +unlock_mutex: + mutex_unlock(&mutex); + + return ret; +} + +int sched_updown_early_migrate_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + int ret, i; + unsigned int *data = (unsigned int *)table->data; + static DEFINE_MUTEX(mutex); + int cap_margin_levels = num_sched_clusters ? num_sched_clusters - 1 : 0; + int val[MAX_MARGIN_LEVELS]; + struct ctl_table tmp = { + .data = &val, + .maxlen = sizeof(int) * cap_margin_levels, + .mode = table->mode, + }; + + if (cap_margin_levels <= 0) + return -EINVAL; + + mutex_lock(&mutex); + + if (!write) { + ret = proc_dointvec(table, write, buffer, lenp, ppos); + goto unlock_mutex; + } + + ret = proc_dointvec(&tmp, write, buffer, lenp, ppos); + if (ret) + goto unlock_mutex; + + for (i = 0; i < cap_margin_levels; i++) { + if (val[i] < 1024) { + ret = -EINVAL; + goto unlock_mutex; + } + } + + /* check up pct is greater than dn pct */ + if (data == &sysctl_sched_early_up[0]) { + for (i = 0; i < cap_margin_levels; i++) { + if (val[i] >= sysctl_sched_early_down[i]) { + ret = -EINVAL; + goto unlock_mutex; + } + } + } else { + for (i = 0; i < cap_margin_levels; i++) { + if (sysctl_sched_early_up[i] >= val[i]) { + ret = -EINVAL; + goto unlock_mutex; + } + } + } + + /* all things checkout update the value */ + for (i = 0; i < cap_margin_levels; i++) + data[i] = val[i]; + unlock_mutex: mutex_unlock(&mutex); @@ -721,6 +786,20 @@ struct ctl_table walt_table[] = { .mode = 0644, .proc_handler = sched_updown_migrate_handler, }, + { + .procname = "sched_early_upmigrate", + .data = &sysctl_sched_early_up, + .maxlen = sizeof(unsigned int) * MAX_MARGIN_LEVELS, + .mode = 0644, + .proc_handler = sched_updown_early_migrate_handler, + }, + { + .procname = "sched_early_downmigrate", + .data = &sysctl_sched_early_down, + .maxlen = sizeof(unsigned int) * MAX_MARGIN_LEVELS, + .mode = 0644, + .proc_handler = sched_updown_early_migrate_handler, + }, { .procname = "walt_rtg_cfs_boost_prio", .data = &sysctl_walt_rtg_cfs_boost_prio, @@ -951,6 +1030,8 @@ void walt_tunables(void) for (i = 0; i < MAX_MARGIN_LEVELS; i++) { sysctl_sched_capacity_margin_up_pct[i] = 95; /* ~5% margin */ sysctl_sched_capacity_margin_dn_pct[i] = 85; /* ~15% margin */ + sysctl_sched_early_up[i] = 1077; + sysctl_sched_early_down[i] = 1204; } sysctl_sched_group_upmigrate_pct = 100; diff --git a/kernel/sched/walt/walt.h b/kernel/sched/walt/walt.h index 42dd9a79ab99..df2bfb1d2737 100644 --- a/kernel/sched/walt/walt.h +++ b/kernel/sched/walt/walt.h @@ -740,6 +740,15 @@ static inline unsigned int walt_nr_rtg_high_prio(int cpu) return wrq->walt_stats.nr_rtg_high_prio_tasks; } +static inline bool task_in_related_thread_group(struct task_struct *p) +{ + struct walt_task_struct *wts = (struct walt_task_struct *) p->android_vendor_data1; + + return (rcu_access_pointer(wts->grp) != NULL); +} + +extern unsigned int sysctl_sched_early_up[MAX_MARGIN_LEVELS]; +extern unsigned int sysctl_sched_early_down[MAX_MARGIN_LEVELS]; static inline bool task_fits_capacity(struct task_struct *p, long capacity, int cpu) @@ -751,21 +760,27 @@ static inline bool task_fits_capacity(struct task_struct *p, /* * Derive upmigration/downmigrate margin wrt the src/dest CPU. */ - if (src_wrq->cluster->id > dst_wrq->cluster->id) + if (src_wrq->cluster->id > dst_wrq->cluster->id) { margin = sched_capacity_margin_down[cpu]; - else + if (task_in_related_thread_group(p)) { + if (is_min_cluster_cpu(cpu)) + margin = sysctl_sched_early_down[0]; + else if (!is_max_cluster_cpu(cpu)) + margin = sysctl_sched_early_down[1]; + } + } else { margin = sched_capacity_margin_up[task_cpu(p)]; + if (task_in_related_thread_group(p)) { + if (is_min_cluster_cpu(task_cpu(p))) + margin = sysctl_sched_early_up[0]; + else if (!is_max_cluster_cpu(task_cpu(p))) + margin = sysctl_sched_early_up[1]; + } + } return capacity * 1024 > uclamp_task_util(p) * margin; } -static inline bool task_in_related_thread_group(struct task_struct *p) -{ - struct walt_task_struct *wts = (struct walt_task_struct *) p->android_vendor_data1; - - return (rcu_access_pointer(wts->grp) != NULL); -} - static inline bool task_fits_max(struct task_struct *p, int cpu) { unsigned long capacity = capacity_orig_of(cpu); From e3e14e56fbae65fdb0a217695e5b7ef1f9e047ad Mon Sep 17 00:00:00 2001 From: Shaleen Agrawal Date: Fri, 26 Aug 2022 10:37:31 -0700 Subject: [PATCH 02/12] sched/walt: Ensure frequency bump to fmax under walt rotation Previously, frequencies would jump to fmax when walt rotation was enabled. This was done through the early detection path. But, as a consequence of early detection boost optimizations, frequencies regressed under walt rotation. Change-Id: I40f91ba873a9cc179fcfb23291dc4839e857428a Signed-off-by: Shaleen Agrawal --- kernel/sched/walt/cpufreq_walt.c | 10 +++++++--- kernel/sched/walt/walt.c | 3 ++- kernel/sched/walt/walt.h | 2 ++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/kernel/sched/walt/cpufreq_walt.c b/kernel/sched/walt/cpufreq_walt.c index f36038918132..a278459d50f4 100644 --- a/kernel/sched/walt/cpufreq_walt.c +++ b/kernel/sched/walt/cpufreq_walt.c @@ -296,10 +296,11 @@ static void waltgov_walt_adjust(struct waltgov_cpu *wg_cpu, unsigned long cpu_ut bool is_migration = wg_cpu->flags & WALT_CPUFREQ_IC_MIGRATION; bool is_rtg_boost = wg_cpu->walt_load.rtgb_active; bool is_hiload; - bool is_ed_boost = wg_cpu->walt_load.ed_active; + bool big_task_rotation = wg_cpu->walt_load.big_task_rotation; + bool employ_ed_boost = wg_cpu->walt_load.ed_active && sysctl_ed_boost_pct; unsigned long pl = wg_cpu->walt_load.pl; - if (is_ed_boost) { + if (employ_ed_boost) { cpu_util = mult_frac(cpu_util, 100 + sysctl_ed_boost_pct, 100); max_and_reason(util, cpu_util, wg_cpu, CPUFREQ_REASON_EARLY_DET); } @@ -323,8 +324,11 @@ static void waltgov_walt_adjust(struct waltgov_cpu *wg_cpu, unsigned long cpu_ut max_and_reason(util, pl, wg_cpu, CPUFREQ_REASON_PL); } - if (is_ed_boost) + if (employ_ed_boost) wg_cpu->reasons |= CPUFREQ_REASON_EARLY_DET; + + if (big_task_rotation) + max_and_reason(util, *max, wg_cpu, CPUFREQ_REASON_BTR); } static inline unsigned long target_util(struct waltgov_policy *wg_policy, diff --git a/kernel/sched/walt/walt.c b/kernel/sched/walt/walt.c index 3defd6833e3c..2bba5fa165f3 100644 --- a/kernel/sched/walt/walt.c +++ b/kernel/sched/walt/walt.c @@ -464,7 +464,7 @@ static void update_task_cpu_cycles(struct task_struct *p, int cpu, static inline bool is_ed_enabled(void) { - return (walt_rotation_enabled || (boost_policy != SCHED_BOOST_NONE)); + return (boost_policy != SCHED_BOOST_NONE); } static inline bool is_ed_task(struct task_struct *p, u64 wallclock) @@ -652,6 +652,7 @@ __cpu_util_freq_walt(int cpu, struct walt_cpu_load *walt_load, unsigned int *rea walt_load->pl = pl; walt_load->ws = walt_load_reported_window; walt_load->rtgb_active = rtgb_active; + walt_load->big_task_rotation = walt_rotation_enabled; if (wrq->ed_task) walt_load->ed_active = true; else diff --git a/kernel/sched/walt/walt.h b/kernel/sched/walt/walt.h index df2bfb1d2737..6b3fd25b2112 100644 --- a/kernel/sched/walt/walt.h +++ b/kernel/sched/walt/walt.h @@ -60,6 +60,7 @@ struct walt_cpu_load { bool rtgb_active; u64 ws; bool ed_active; + bool big_task_rotation; }; #define DECLARE_BITMAP_ARRAY(name, nr, bits) \ @@ -307,6 +308,7 @@ extern unsigned int sched_lib_mask_force; #define WALT_CPUFREQ_BOOST_UPDATE 0x20 #define CPUFREQ_REASON_LOAD 0 +#define CPUFREQ_REASON_BTR 0x1 #define CPUFREQ_REASON_PL 0x2 #define CPUFREQ_REASON_EARLY_DET 0x4 #define CPUFREQ_REASON_RTG_BOOST 0x8 From 3abcd9269ff169f6e75f082a958c364860cf910d Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Fri, 26 Aug 2022 16:31:59 -0700 Subject: [PATCH 03/12] sched/walt: disable cpu packing when current freq is high This in addition to other criteria already present in the code. Change-Id: Ief3a21eb159bed8eb724427c0acca327a3cbb272 Signed-off-by: Abhijeet Dharmapurikar --- kernel/sched/walt/walt.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/sched/walt/walt.h b/kernel/sched/walt/walt.h index 6b3fd25b2112..94404dc16078 100644 --- a/kernel/sched/walt/walt.h +++ b/kernel/sched/walt/walt.h @@ -1048,6 +1048,10 @@ static inline int walt_find_and_choose_cluster_packing_cpu(int start_cpu, struct if (task_util(p) >= sysctl_sched_idle_enough) return -1; + /* don't pack if running at a freq higher than 43.9pct of its fmax */ + if (arch_scale_freq_capacity(packing_cpu) > 450) + return -1; + /* the packing cpu can be used, so pack! */ return packing_cpu; } From 3de224c44457f59a898153740beab5fd4a62ef69 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Thu, 25 Aug 2022 12:34:45 -0700 Subject: [PATCH 04/12] sched/walt: fix packing worthy gold tasks running on silvers The current code identifies the first 32bit cpu as the packing cpu when the load conditions are met. However, it skips checking if that 32bit cpu is actually halted. In case it were halted, the select_task_rq()->is_cpu_allowed() fails, causing the task to run on a fallback cpu which invariably ends up being a silver cpu. Fix this by finding the first unhalted cpu for packing. If its a 32bit task further find a 32bit supporting cpu. Either case always ensure that an unhalted cpu is used for packing. Change-Id: I459c70fe3793a26c4b06bb80f8660003b1875c85 Signed-off-by: Abhijeet Dharmapurikar --- kernel/sched/walt/walt.h | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/kernel/sched/walt/walt.h b/kernel/sched/walt/walt.h index 94404dc16078..c78354ec4ec2 100644 --- a/kernel/sched/walt/walt.h +++ b/kernel/sched/walt/walt.h @@ -1002,7 +1002,6 @@ static inline int walt_find_and_choose_cluster_packing_cpu(int start_cpu, struct struct walt_rq *wrq = (struct walt_rq *)rq->android_vendor_data1; struct walt_sched_cluster *cluster = wrq->cluster; cpumask_t unhalted_cpus; - cpumask_t cluster_32bit_cpus; int packing_cpu; /* if idle_enough feature is not enabled */ @@ -1011,22 +1010,19 @@ static inline int walt_find_and_choose_cluster_packing_cpu(int start_cpu, struct if (!sysctl_sched_cluster_util_thres_pct) return -1; - /* find all 32 bit capable cpus in this cluster */ - cpumask_and(&cluster_32bit_cpus, &cluster->cpus, system_32bit_el0_cpumask()); - /* pack 32 bit and 64 bit tasks on the same cpu, if possible */ - if (cpumask_weight(&cluster_32bit_cpus) > 0) { - packing_cpu = cpumask_first(&cluster_32bit_cpus); - } else { - /* find all unhalted active cpus */ - cpumask_andnot(&unhalted_cpus, cpu_active_mask, cpu_halt_mask); + /* find all unhalted active cpus */ + cpumask_andnot(&unhalted_cpus, cpu_active_mask, cpu_halt_mask); - /* find all unhalted active cpus in this cluster */ - cpumask_and(&unhalted_cpus, &unhalted_cpus, &cluster->cpus); + /* find all unhalted active cpus in this cluster */ + cpumask_and(&unhalted_cpus, &unhalted_cpus, &cluster->cpus); - /* return the first found unhalted, active cpu, in this cluster */ - packing_cpu = cpumask_first(&unhalted_cpus); - } + if (is_compat_thread(task_thread_info(p))) + /* try to find a packing cpu within 32 bit subset */ + cpumask_and(&unhalted_cpus, &unhalted_cpus, system_32bit_el0_cpumask()); + + /* return the first found unhalted, active cpu, in this cluster */ + packing_cpu = cpumask_first(&unhalted_cpus); /* packing cpu must be a valid cpu for runqueue lookup */ if (packing_cpu >= nr_cpu_ids) From d3e9a484aca7c0ce43e444a1254e0bb757b9daef Mon Sep 17 00:00:00 2001 From: Stephen Dickey Date: Mon, 29 Aug 2022 11:14:05 -0700 Subject: [PATCH 05/12] kernel/sched/walt: kernel space adaptive_low/high_freq values Add kernel-space adaptive_low_freq and adaptive_high_freq to the waltgov cpufreq policies, such that kernel space code or vendor kernel space code can manipulate these values directly. Set the actual in-use adaptive freq values to the max of the user space value and the kernel space value. Change-Id: I59deca1cd60bcd8bd63170e6e1bced63456b41d6 Signed-off-by: Stephen Dickey --- kernel/sched/walt/cpufreq_walt.c | 111 +++++++++++++++++++++++++++++-- kernel/sched/walt/walt.h | 6 ++ 2 files changed, 113 insertions(+), 4 deletions(-) diff --git a/kernel/sched/walt/cpufreq_walt.c b/kernel/sched/walt/cpufreq_walt.c index a278459d50f4..83f802199f64 100644 --- a/kernel/sched/walt/cpufreq_walt.c +++ b/kernel/sched/walt/cpufreq_walt.c @@ -25,6 +25,8 @@ struct waltgov_tunables { unsigned int rtg_boost_freq; unsigned int adaptive_low_freq; unsigned int adaptive_high_freq; + unsigned int adaptive_low_freq_kernel; + unsigned int adaptive_high_freq_kernel; unsigned int target_load_thresh; unsigned int target_load_shift; bool pl; @@ -220,6 +222,18 @@ static inline unsigned long walt_map_util_freq(unsigned long util, return (fmax + (fmax >> 2)) * util / cap; } +static inline unsigned int get_adaptive_low_freq(struct waltgov_policy *wg_policy) +{ + return(max(wg_policy->tunables->adaptive_low_freq, + wg_policy->tunables->adaptive_low_freq_kernel)); +} + +static inline unsigned int get_adaptive_high_freq(struct waltgov_policy *wg_policy) +{ + return(max(wg_policy->tunables->adaptive_high_freq, + wg_policy->tunables->adaptive_high_freq_kernel)); +} + static unsigned int get_next_freq(struct waltgov_policy *wg_policy, unsigned long util, unsigned long max, struct waltgov_cpu *wg_cpu, u64 time) @@ -232,11 +246,11 @@ static unsigned int get_next_freq(struct waltgov_policy *wg_policy, freq = raw_freq; if (wg_policy->tunables->adaptive_high_freq) { - if (raw_freq < wg_policy->tunables->adaptive_low_freq) { - freq = wg_policy->tunables->adaptive_low_freq; + if (raw_freq < get_adaptive_low_freq(wg_policy)) { + freq = get_adaptive_low_freq(wg_policy); wg_driv_cpu->reasons = CPUFREQ_REASON_ADAPTIVE_LOW; - } else if (raw_freq <= wg_policy->tunables->adaptive_high_freq) { - freq = wg_policy->tunables->adaptive_high_freq; + } else if (raw_freq <= get_adaptive_high_freq(wg_policy)) { + freq = get_adaptive_high_freq(wg_policy); wg_driv_cpu->reasons = CPUFREQ_REASON_ADAPTIVE_HIGH; } } @@ -669,6 +683,91 @@ static ssize_t boost_store(struct gov_attr_set *attr_set, const char *buf, return count; } +/** + * cpufreq_walt_set_adaptive_freq() - set the waltgov adaptive freq for cpu + * @cpu: the cpu for which the values should be set + * @adaptive_low_freq: low freq + * @adaptive_high_freq:high_freq + * + * Configure the adaptive_low/high_freq for the cpu specified. This will impact all + * cpus governed by the policy (e.g. all cpus in a cluster). The actual value used + * for adaptive frequencies will be governed by the user space setting for the + * policy, and this value. + * + * Return: 0 if successful, error otherwise + */ +int cpufreq_walt_set_adaptive_freq(unsigned int cpu, unsigned int adaptive_low_freq, + unsigned int adaptive_high_freq) +{ + struct waltgov_cpu *wg_cpu = &per_cpu(waltgov_cpu, cpu); + struct waltgov_policy *wg_policy = wg_cpu->wg_policy; + struct cpufreq_policy *policy = wg_policy->policy; + + if (!cpu_possible(cpu)) + return -EFAULT; + + if (policy->min <= adaptive_low_freq && policy->max >= adaptive_high_freq) { + wg_policy->tunables->adaptive_low_freq_kernel = adaptive_low_freq; + wg_policy->tunables->adaptive_high_freq_kernel = adaptive_high_freq; + return 0; + } + + return -EINVAL; +} +EXPORT_SYMBOL(cpufreq_walt_set_adaptive_freq); + +/** + * cpufreq_walt_get_adaptive_freq() - get the waltgov adaptive freq for cpu + * @cpu: the cpu for which the values should be returned + * @adaptive_low_freq: pointer to write the current kernel adaptive_low_freq value + * @adaptive_high_freq:pointer to write the current kernel adaptive_high_freq value + * + * Get the currently active adaptive_low/high_freq for the cpu specified. + * + * Return: 0 if successful, error otherwise + */ +int cpufreq_walt_get_adaptive_freq(unsigned int cpu, unsigned int *adaptive_low_freq, + unsigned int *adaptive_high_freq) +{ + struct waltgov_cpu *wg_cpu = &per_cpu(waltgov_cpu, cpu); + struct waltgov_policy *wg_policy = wg_cpu->wg_policy; + + if (!cpu_possible(cpu)) + return -EFAULT; + + if (adaptive_low_freq && adaptive_high_freq) { + *adaptive_low_freq = get_adaptive_low_freq(wg_policy); + *adaptive_high_freq = get_adaptive_high_freq(wg_policy); + return 0; + } + + return -EINVAL; +} +EXPORT_SYMBOL(cpufreq_walt_get_adaptive_freq); + +/** + * cpufreq_walt_reset_adaptive_freq() - reset the waltgov adaptive freq for cpu + * @cpu: the cpu for which the values should be set + * + * Reset the kernel adaptive_low/high_freq to zero. + * + * Return: 0 if successful, error otherwise + */ +int cpufreq_walt_reset_adaptive_freq(unsigned int cpu) +{ + struct waltgov_cpu *wg_cpu = &per_cpu(waltgov_cpu, cpu); + struct waltgov_policy *wg_policy = wg_cpu->wg_policy; + + if (!cpu_possible(cpu)) + return -EFAULT; + + wg_policy->tunables->adaptive_low_freq_kernel = 0; + wg_policy->tunables->adaptive_high_freq_kernel = 0; + + return 0; +} +EXPORT_SYMBOL(cpufreq_walt_reset_adaptive_freq); + #define WALTGOV_ATTR_RW(_name) \ static struct governor_attr _name = \ __ATTR(_name, 0644, show_##_name, store_##_name) \ @@ -826,6 +925,8 @@ static void waltgov_tunables_save(struct cpufreq_policy *policy, cached->boost = tunables->boost; cached->adaptive_low_freq = tunables->adaptive_low_freq; cached->adaptive_high_freq = tunables->adaptive_high_freq; + cached->adaptive_low_freq_kernel = tunables->adaptive_low_freq_kernel; + cached->adaptive_high_freq_kernel = tunables->adaptive_high_freq_kernel; cached->target_load_thresh = tunables->target_load_thresh; cached->target_load_shift = tunables->target_load_shift; } @@ -848,6 +949,8 @@ static void waltgov_tunables_restore(struct cpufreq_policy *policy) tunables->boost = cached->boost; tunables->adaptive_low_freq = cached->adaptive_low_freq; tunables->adaptive_high_freq = cached->adaptive_high_freq; + tunables->adaptive_low_freq_kernel = cached->adaptive_low_freq_kernel; + tunables->adaptive_high_freq_kernel = cached->adaptive_high_freq_kernel; tunables->target_load_thresh = cached->target_load_thresh; tunables->target_load_shift = cached->target_load_shift; } diff --git a/kernel/sched/walt/walt.h b/kernel/sched/walt/walt.h index c78354ec4ec2..dbc334ab649e 100644 --- a/kernel/sched/walt/walt.h +++ b/kernel/sched/walt/walt.h @@ -221,6 +221,12 @@ extern unsigned int sysctl_sched_hyst_min_coloc_ns; extern unsigned int sysctl_sched_long_running_rt_task_ms; extern unsigned int sysctl_ed_boost_pct; +extern int cpufreq_walt_set_adaptive_freq(unsigned int cpu, unsigned int adaptive_low_freq, + unsigned int adaptive_high_freq); +extern int cpufreq_walt_get_adaptive_freq(unsigned int cpu, unsigned int *adaptive_low_freq, + unsigned int *adaptive_high_freq); +extern int cpufreq_walt_reset_adaptive_freq(unsigned int cpu); + #define WALT_MANY_WAKEUP_DEFAULT 1000 extern unsigned int sysctl_sched_many_wakeup_threshold; extern unsigned int sysctl_walt_rtg_cfs_boost_prio; From 774bb80375ef2a1c073e46f1ff1a4f62c8b9e67c Mon Sep 17 00:00:00 2001 From: Stephen Dickey Date: Wed, 31 Aug 2022 10:47:39 -0700 Subject: [PATCH 06/12] sched/walt: add lowlatency support for key binder transactions The current change protects only binder transactions targeted towards an RT process. This change attempts to consider all binder transaction interacting with an RT task. Change-Id: I35cbb695f6709170afa075b1b50d009b17b1b508 Signed-off-by: Kishore Sri venkata Ganesh Bolisetty Signed-off-by: Stephen Dickey --- kernel/sched/walt/walt_cfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/sched/walt/walt_cfs.c b/kernel/sched/walt/walt_cfs.c index 6a44c6c9400c..bde882b1aab9 100644 --- a/kernel/sched/walt/walt_cfs.c +++ b/kernel/sched/walt/walt_cfs.c @@ -987,10 +987,10 @@ static void walt_binder_low_latency_set(void *unused, struct task_struct *task, if (unlikely(walt_disabled)) return; - if (task && current->signal && - (current->signal->oom_score_adj == 0) && - ((current->prio < DEFAULT_PRIO) || - (task->group_leader->prio < MAX_RT_PRIO))) + if (task && ((task_in_related_thread_group(current) && + task->group_leader->prio < MAX_RT_PRIO) || + (current->group_leader->prio < MAX_RT_PRIO && + task_in_related_thread_group(task)))) wts->low_latency |= WALT_LOW_LATENCY_BINDER; } From 97bfb7d38f00b3c8636b32feab011e9da773a86e Mon Sep 17 00:00:00 2001 From: Stephen Dickey Date: Wed, 31 Aug 2022 16:07:05 -0700 Subject: [PATCH 07/12] kernel/sched/walt: change formatting for not_preferred output Core control takes a numeric input for the not_preferred field to identify which cpus can be paused. 1 means can pause, 0 means the cpu cannot pause. The output is in order of the number of the cpu. For example # cat /sys/devices/system/cpu/cpu3/core_ctl/not_preferred 1 0 1 0 This means that cpu 3 and cpu 5 are not_preferred and can be paused. Change-Id: Ia4b982352bba7e463d59579ece13ccfcb09b0baf Signed-off-by: Stephen Dickey --- kernel/sched/walt/core_ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/walt/core_ctl.c b/kernel/sched/walt/core_ctl.c index cdb123d90b8f..ebd0b01da5f7 100644 --- a/kernel/sched/walt/core_ctl.c +++ b/kernel/sched/walt/core_ctl.c @@ -392,7 +392,7 @@ static ssize_t show_not_preferred(const struct cluster_data *state, char *buf) for (i = 0; i < state->num_cpus; i++) { c = &per_cpu(cpu_state, i + state->first_cpu); count += scnprintf(buf + count, PAGE_SIZE - count, - "CPU#%d: %u\n", c->cpu, c->not_preferred); + "%u ", c->not_preferred); } spin_unlock_irqrestore(&state_lock, flags); From c9410f348b6ec7b8240fe63bee5fe2b11bed1668 Mon Sep 17 00:00:00 2001 From: Shaleen Agrawal Date: Tue, 30 Aug 2022 16:07:06 -0700 Subject: [PATCH 08/12] sched/walt: Add tracepoint to display select_task_rt fastpath Add tracepoint to help debug rt task placement decisions. Change-Id: I95170b2b45adf3a614ba49d237c8ed6ca6e145aa Signed-off-by: Shaleen Agrawal Signed-off-by: Stephen Dickey --- kernel/sched/walt/trace.h | 22 ++++++++++++++++++++++ kernel/sched/walt/walt_rt.c | 21 ++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/kernel/sched/walt/trace.h b/kernel/sched/walt/trace.h index d260c63a9609..bed2f38942e0 100644 --- a/kernel/sched/walt/trace.h +++ b/kernel/sched/walt/trace.h @@ -1055,6 +1055,28 @@ TRACE_EVENT(sched_compute_energy, __entry->cluster_first_cpu2, __entry->s2, __entry->m2, __entry->c2) ) +TRACE_EVENT(sched_select_task_rt, + + TP_PROTO(struct task_struct *p, int fastpath), + + TP_ARGS(p, fastpath), + + TP_STRUCT__entry( + __field(int, pid) + __array(char, comm, TASK_COMM_LEN) + __field(int, fastpath) + ), + + TP_fast_assign( + __entry->pid = p->pid; + memcpy(__entry->comm, p->comm, TASK_COMM_LEN); + __entry->fastpath = fastpath; + ), + + TP_printk("pid=%d comm=%s fastpath=%u", + __entry->pid, __entry->comm, __entry->fastpath) +); + TRACE_EVENT(sched_task_util, TP_PROTO(struct task_struct *p, unsigned long candidates, diff --git a/kernel/sched/walt/walt_rt.c b/kernel/sched/walt/walt_rt.c index 3265be5ba664..18d531791ff2 100644 --- a/kernel/sched/walt/walt_rt.c +++ b/kernel/sched/walt/walt_rt.c @@ -225,6 +225,14 @@ static inline bool walt_should_honor_rt_sync(struct rq *rq, struct task_struct * rq->rt.rt_nr_running <= 2; } +enum rt_fastpaths { + NONE = 0, + NON_WAKEUP, + SYNC_WAKEUP, + CLUSTER_PACKING_FASTPATH, +}; + + static void walt_select_task_rq_rt(void *unused, struct task_struct *task, int cpu, int sd_flag, int wake_flags, int *new_cpu) { @@ -235,13 +243,16 @@ static void walt_select_task_rq_rt(void *unused, struct task_struct *task, int c int ret, target = -1, this_cpu; struct cpumask *lowest_mask; int packing_cpu; + int fastpath = NONE; if (unlikely(walt_disabled)) return; /* For anything but wake ups, just return the task_cpu */ - if (sd_flag != SD_BALANCE_WAKE && sd_flag != SD_BALANCE_FORK) - return; + if (sd_flag != SD_BALANCE_WAKE && sd_flag != SD_BALANCE_FORK) { + fastpath = NON_WAKEUP; + goto out; + } this_cpu = raw_smp_processor_id(); this_cpu_rq = cpu_rq(this_cpu); @@ -252,8 +263,9 @@ static void walt_select_task_rq_rt(void *unused, struct task_struct *task, int c if (sysctl_sched_sync_hint_enable && cpu_active(this_cpu) && !cpu_halted(this_cpu) && cpumask_test_cpu(this_cpu, task->cpus_ptr) && walt_should_honor_rt_sync(this_cpu_rq, task, sync)) { + fastpath = SYNC_WAKEUP; *new_cpu = this_cpu; - return; + goto out; } *new_cpu = cpu; /* previous CPU as back up */ @@ -292,6 +304,7 @@ static void walt_select_task_rq_rt(void *unused, struct task_struct *task, int c /* create a fastpath for finding a packing cpu */ packing_cpu = walt_find_and_choose_cluster_packing_cpu(task_cpu(task), task); if (packing_cpu >= 0) { + fastpath = CLUSTER_PACKING_FASTPATH; *new_cpu = packing_cpu; goto unlock; } @@ -320,6 +333,8 @@ static void walt_select_task_rq_rt(void *unused, struct task_struct *task, int c } unlock: rcu_read_unlock(); +out: + trace_sched_select_task_rt(task, fastpath); } From 92c1eb4e2f0b00d93db46a9c2bc112c6a4c83c67 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Fri, 19 Aug 2022 23:36:50 +0530 Subject: [PATCH 09/12] sched: walt: remove vendor hook "trace_binder_transaction_received" "trace_binder_transaction_received" vendor hook is used to clear binder low latency MVP priority, but for some usecase it is observed that usespace application is initiating read ioctl quickly and as part of ioctl handling binder driver initiates transaction received vendor hook and binder low latency MVP priority is cleared for the binder thread. Handle above condition by allowing binder thread to maintain and run with MVP priority for it's allocated MVP timeslice. The Low latency flag of the task is reset only when the binder transactions is initiated again on the same thread and task initiating the transaction doesn't comply with the low latency criterion. Change-Id: Ie068adc64796432b7d41b0256a25a04caac518b1 Signed-off-by: Ashay Jaiswal --- kernel/sched/walt/walt_cfs.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/kernel/sched/walt/walt_cfs.c b/kernel/sched/walt/walt_cfs.c index bde882b1aab9..9e6639eaceb9 100644 --- a/kernel/sched/walt/walt_cfs.c +++ b/kernel/sched/walt/walt_cfs.c @@ -992,16 +992,18 @@ static void walt_binder_low_latency_set(void *unused, struct task_struct *task, (current->group_leader->prio < MAX_RT_PRIO && task_in_related_thread_group(task)))) wts->low_latency |= WALT_LOW_LATENCY_BINDER; -} - -static void walt_binder_low_latency_clear(void *unused, struct binder_transaction *t) -{ - struct walt_task_struct *wts = (struct walt_task_struct *) current->android_vendor_data1; - - if (unlikely(walt_disabled)) - return; - if (wts->low_latency & WALT_LOW_LATENCY_BINDER) + else + /* + * Clear low_latency flag if criterion above is not met, this + * will handle usecase where for a binder thread WALT_LOW_LATENCY_BINDER + * is set by one task and before WALT clears this flag after timer expiry + * some other task tries to use same binder thread. + * + * The only gets cleared when binder transaction is initiated + * and the above condition to set flasg is nto satisfied. + */ wts->low_latency &= ~WALT_LOW_LATENCY_BINDER; + } static void binder_set_priority_hook(void *data, @@ -1364,7 +1366,6 @@ void walt_cfs_init(void) register_trace_android_rvh_select_task_rq_fair(walt_select_task_rq_fair, NULL); register_trace_android_vh_binder_wakeup_ilocked(walt_binder_low_latency_set, NULL); - register_trace_binder_transaction_received(walt_binder_low_latency_clear, NULL); register_trace_android_vh_binder_set_priority(binder_set_priority_hook, NULL); register_trace_android_vh_binder_restore_priority(binder_restore_priority_hook, NULL); From 4349ffdf244bc028fe96a645d7e00ccfe8618252 Mon Sep 17 00:00:00 2001 From: Shaleen Agrawal Date: Tue, 30 Aug 2022 14:45:09 -0700 Subject: [PATCH 10/12] kernel/sched/walt/energy-model: inflate cost for 1.6Ghz by 3x Certain frequencies in min-cap cpus draw excessive power and are more costly to the device's performance than indicated by the energy model. For silver frequencies above a threshold, inflate the cost by a percentage to create a steep power curve, favoring golds at lower frequencies. For example, to raise the cost for frequencies above 1.6GHz by 3x: echo 300 > /proc/sys/walt/sched_em_inflate_pct echo 220 > /proc/sys/walt/sched_em_inflate_thres Change-Id: Ia10a818ab2f217ffa3039667f52566d9894e5047 Signed-off-by: Shaleen Agrawal Signed-off-by: Stephen Dickey --- kernel/sched/walt/sysctl.c | 21 +++++++++++++++++++++ kernel/sched/walt/walt.h | 2 ++ kernel/sched/walt/walt_cfs.c | 19 ++++++++++++++----- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/kernel/sched/walt/sysctl.c b/kernel/sched/walt/sysctl.c index 56a5608bf11f..38b0c731eae4 100644 --- a/kernel/sched/walt/sysctl.c +++ b/kernel/sched/walt/sysctl.c @@ -19,6 +19,7 @@ static int __maybe_unused two = 2; static int __maybe_unused four = 4; static int one_hundred = 100; static int one_thousand = 1000; +static int one_thousand_twenty_four = 1024; static int two_thousand = 2000; /* @@ -77,6 +78,8 @@ unsigned int sysctl_sched_long_running_rt_task_ms; unsigned int sysctl_sched_idle_enough; unsigned int sysctl_sched_cluster_util_thres_pct; unsigned int sysctl_ed_boost_pct; +unsigned int sysctl_em_inflate_pct = 100; +unsigned int sysctl_em_inflate_thres = 1024; /* range is [1 .. INT_MAX] */ static int sysctl_task_read_pid = 1; @@ -1011,6 +1014,24 @@ struct ctl_table walt_table[] = { .extra1 = SYSCTL_ZERO, .extra2 = &one_hundred, }, + { + .procname = "sched_em_inflate_pct", + .data = &sysctl_em_inflate_pct, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = &one_hundred, + .extra2 = &one_thousand, + }, + { + .procname = "sched_em_inflate_thres", + .data = &sysctl_em_inflate_thres, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = &one_thousand_twenty_four, + }, { } }; diff --git a/kernel/sched/walt/walt.h b/kernel/sched/walt/walt.h index dbc334ab649e..9e074bcc5a14 100644 --- a/kernel/sched/walt/walt.h +++ b/kernel/sched/walt/walt.h @@ -220,6 +220,8 @@ extern unsigned int sysctl_sched_conservative_pl; extern unsigned int sysctl_sched_hyst_min_coloc_ns; extern unsigned int sysctl_sched_long_running_rt_task_ms; extern unsigned int sysctl_ed_boost_pct; +extern unsigned int sysctl_em_inflate_pct; +extern unsigned int sysctl_em_inflate_thres; extern int cpufreq_walt_set_adaptive_freq(unsigned int cpu, unsigned int adaptive_low_freq, unsigned int adaptive_high_freq); diff --git a/kernel/sched/walt/walt_cfs.c b/kernel/sched/walt/walt_cfs.c index 9e6639eaceb9..d2c2b339ecbd 100644 --- a/kernel/sched/walt/walt_cfs.c +++ b/kernel/sched/walt/walt_cfs.c @@ -568,6 +568,16 @@ cpu_util_next_walt_prs(int cpu, struct task_struct *p, int dst_cpu, bool prev_ds return util; } +static inline unsigned long get_util_to_cost(int cpu, unsigned long util) +{ + struct walt_rq *wrq = (struct walt_rq *) cpu_rq(cpu)->android_vendor_data1; + + if (cpu == 0 && util > sysctl_em_inflate_thres) + return mult_frac(wrq->cluster->util_to_cost[util], sysctl_em_inflate_pct, 100); + else + return wrq->cluster->util_to_cost[util]; +} + /** * walt_em_cpu_energy() - Estimates the energy consumed by the CPUs of a performance domain @@ -586,9 +596,8 @@ static inline unsigned long walt_em_cpu_energy(struct em_perf_domain *pd, unsigned long max_util, unsigned long sum_util, struct compute_energy_output *output, unsigned int x) { - unsigned long scale_cpu; + unsigned long scale_cpu, cost; int cpu; - struct walt_rq *wrq; if (!sum_util) return 0; @@ -651,14 +660,14 @@ static inline unsigned long walt_em_cpu_energy(struct em_perf_domain *pd, if (max_util >= 1024) max_util = 1023; - wrq = (struct walt_rq *) cpu_rq(cpu)->android_vendor_data1; + cost = get_util_to_cost(cpu, max_util); if (output) { - output->cost[x] = wrq->cluster->util_to_cost[max_util]; + output->cost[x] = cost; output->max_util[x] = max_util; output->sum_util[x] = sum_util; } - return wrq->cluster->util_to_cost[max_util] * sum_util / scale_cpu; + return cost * sum_util / scale_cpu; } /* From 30c5ecaa7f27d2886572659e8cda832dee23d344 Mon Sep 17 00:00:00 2001 From: Tengfei Fan Date: Wed, 7 Sep 2022 08:59:38 +0800 Subject: [PATCH 11/12] sched/walt: make TASK_BOOST_STRICT_MAX task have high chance for running on prime core TASK_BOOST_STRICT_MAX task can cause performance influence if it haven't running on prime core, so do this for these tasks have high chance for running on prime core. Change-Id: I249dbe1c201934ea3c4610e93b1b71b24fb20d80 Signed-off-by: Tengfei Fan --- kernel/sched/walt/walt_cfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/walt/walt_cfs.c b/kernel/sched/walt/walt_cfs.c index d2c2b339ecbd..f53e96478325 100644 --- a/kernel/sched/walt/walt_cfs.c +++ b/kernel/sched/walt/walt_cfs.c @@ -343,7 +343,8 @@ static void walt_find_best_target(struct sched_domain *sd, if (fbt_env->skip_cpu == i) continue; - if (wrq->num_mvp_tasks > 0) + if (wrq->num_mvp_tasks > 0 && + per_task_boost(p) != TASK_BOOST_STRICT_MAX) continue; /* From a602accc3cd998cd060ad6aefc1d17abc9ce0109 Mon Sep 17 00:00:00 2001 From: Stephen Dickey Date: Tue, 30 Aug 2022 16:12:29 -0700 Subject: [PATCH 12/12] kernel/sched/walt: check migration disabled in allowed_ptr_locked migrate_disable is called to prevent moving a task to a different cpu. In the process it will update the task's cpus_ptr to a temporary mask to restrict the task to run only on the current cpu. It has only one cpu set in this new mask. migrate_disable must always be paired with a migrate_enable call. When migrate_enable is called it will attempt to manipulate the allowed ptrs mask just prior to actually enabling migration on a task. This means __set_cpus_allowed_ptr is called. This calls a tracehook: migrate_enable __set_cpus_allowed_ptr __set_cpus_allowed_ptr_locked trace_android_rvh_set_cpus_allowed_ptr_locked android_rvh_set_cpus_allowed_ptr_locked The purpose of handling this hook in walt, is to prevent the assignment of a task to a halted cpu. When migrate_enable restores the affinity to p->cpus_mask and p->cpus_mask consists of a single cpu and that single cpu is halted, WALT will cause __set_cpus_allowed_ptr to reject and return early. IOW p->cpus_ptr is not set to p->cpus_mask. If the p->cpus_ptr is not restored to point to the p->cpus_mask, a subsequent migrate_disable/migrate_enable can happen, and is allowed to happen with the runque lock taken. Since the p->cpus_ptr is not pointing to the p->cpus_mask, migrate_enable will incorrectly call __set_cpus_allowed_ptr. This in turn will take the runque lock again resulting in a spinlock recursion. Address this by updating the hook code, checking the migrate_disabled flag for the task, and allowing the existing cpu to be used even if that cpu is halted. To achieve this utilize a different hook that is present in the code already: trace_android_rvh_set_cpus_allowed_by_task(). Change-Id: I42204332d708c6bc96f5de52eb9739d17cfdc0a3 Signed-off-by: Stephen Dickey --- kernel/sched/walt/walt_halt.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/kernel/sched/walt/walt_halt.c b/kernel/sched/walt/walt_halt.c index 663efed493c2..48a82da53cf5 100644 --- a/kernel/sched/walt/walt_halt.c +++ b/kernel/sched/walt/walt_halt.c @@ -500,17 +500,18 @@ static void android_rvh_get_nohz_timer_target(void *unused, int *cpu, bool *done rcu_read_unlock(); } -static void android_rvh_set_cpus_allowed_ptr_locked(void *unused, - const struct cpumask *cpu_valid_mask, - const struct cpumask *new_mask, - unsigned int *dest_cpu) +static void android_rvh_set_cpus_allowed_by_task(void *unused, + const struct cpumask *cpu_valid_mask, + const struct cpumask *new_mask, + struct task_struct *p, + unsigned int *dest_cpu) { cpumask_t allowed_cpus; if (unlikely(walt_disabled)) return; - if (cpu_halted(*dest_cpu)) { + if (cpu_halted(*dest_cpu) && !p->migration_disabled) { /* remove halted cpus from the valid mask, and store locally */ cpumask_andnot(&allowed_cpus, cpu_valid_mask, cpu_halt_mask); *dest_cpu = cpumask_any_and_distribute(&allowed_cpus, new_mask); @@ -573,8 +574,8 @@ void walt_halt_init(void) sched_setscheduler_nocheck(walt_drain_thread, SCHED_FIFO, ¶m); register_trace_android_rvh_get_nohz_timer_target(android_rvh_get_nohz_timer_target, NULL); - register_trace_android_rvh_set_cpus_allowed_ptr_locked( - android_rvh_set_cpus_allowed_ptr_locked, NULL); + register_trace_android_rvh_set_cpus_allowed_by_task( + android_rvh_set_cpus_allowed_by_task, NULL); register_trace_android_rvh_rto_next_cpu(android_rvh_rto_next_cpu, NULL); register_trace_android_rvh_is_cpu_allowed(android_rvh_is_cpu_allowed, NULL);