| From 35b63582233849233b5c6dcf3d4dea2d7fefd327 Mon Sep 17 00:00:00 2001 |
| From: Joel Fernandes <joelaf@google.com> |
| Date: Thu, 11 Jun 2020 10:37:12 -0400 |
| Subject: [PATCH] CHROMIUM: sched: Add /proc/pid/tasks/tid/latency_sensitive |
| attribute |
| |
| Upstream is moving to use uclamp which we would like. However, only 2 of |
| the 3 attributes are available in it (the clamp ones). The third |
| attribute - uclamp latency sensitive attribute is out-of-tree in Android |
| and available only for CPU controller CGroups. This patch tries to add |
| support for the third so that the 2 upstream ones can be used without |
| requiring CPU controller CGroups. |
| |
| In Chrome OS, typically the latency sensitive attribute has been set |
| using schedtune CGroup. However the upstream uclamp interface uses CPU |
| controller CGroups. Even if we carry the out-of-tree patch to add the |
| latency sensitive attribute to uclamp-cgroups, we still cannot use it |
| for our usecase. The reason is currently, several threads in the |
| 'foreground' CPU controller CGroup don't have the schedtune prefer-idle |
| (aka latency sensitive) attribute set. If we set this attribute for |
| 'foreground', then all foreground tasks will get the attribute set, |
| which we don't want. |
| |
| The solution is to add a temporary "latency sensitive" attribute to |
| procfs until upstream figures out what this interface should look like. |
| These patches aim to make the code selfcontained in their own |
| translation units so as to make the maintenance burden minimal. |
| For the other uclamp attributes (clamp min/max), those will be set via |
| the upstream sched_setattr(2). |
| |
| BUG=b:147773166,b:189814845,b:224657177 |
| TEST=boot |
| |
| Change-Id: I9b872b081ab6e876c1751603c947e7d9a7c210d9 |
| Signed-off-by: Joel Fernandes <joelaf@google.com> |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2241891 |
| Reviewed-by: Brian Geffon <bgeffon@chromium.org> |
| (cherry picked from commit 78d0e1deb87193434d53526eabcddba10075cb54) |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2981472 |
| Tested-by: Ikjoon Jang <ikjn@chromium.org> |
| (cherry picked from commit e2ea9fbe51a6f807b4d6ad73d3330eade2c811b2) |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3884575 |
| Reviewed-by: Douglas Anderson <dianders@chromium.org> |
| Tested-by: Douglas Anderson <dianders@chromium.org> |
| Commit-Queue: Douglas Anderson <dianders@chromium.org> |
| --- |
| fs/proc/Kconfig | 6 +++ |
| fs/proc/Makefile | 1 + |
| fs/proc/base.c | 3 ++ |
| fs/proc/internal.h | 1 + |
| fs/proc/latsense.c | 94 ++++++++++++++++++++++++++++++++++ |
| include/linux/sched.h | 4 ++ |
| include/linux/sched/latsense.h | 8 +++ |
| kernel/sched/build_utility.c | 4 ++ |
| kernel/sched/core.c | 4 ++ |
| kernel/sched/latsense.c | 17 ++++++ |
| kernel/sched/sched.h | 1 + |
| 11 files changed, 143 insertions(+) |
| create mode 100644 fs/proc/latsense.c |
| create mode 100644 include/linux/sched/latsense.h |
| create mode 100644 kernel/sched/latsense.c |
| |
| diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig |
| index 32b1116ae137c61bc0eb915498dab969b1f4c50c..61a5a323f60af5a058cc712e5a24053449b7c26a 100644 |
| --- a/fs/proc/Kconfig |
| +++ b/fs/proc/Kconfig |
| @@ -108,3 +108,9 @@ config PROC_PID_ARCH_STATUS |
| config PROC_CPU_RESCTRL |
| def_bool n |
| depends on PROC_FS |
| + |
| +config PROC_LATSENSE |
| + def_bool y |
| + depends on PROC_FS && UCLAMP_TASK |
| + help |
| + Enable /proc/pid/tasks/tid latency sensitive scheduler attribute |
| diff --git a/fs/proc/Makefile b/fs/proc/Makefile |
| index bd08616ed8bad7937173183eb08634c9526a4e90..f11ca7f70601bb8013490c89a966325e09dfb068 100644 |
| --- a/fs/proc/Makefile |
| +++ b/fs/proc/Makefile |
| @@ -27,6 +27,7 @@ proc-y += softirqs.o |
| proc-y += namespaces.o |
| proc-y += self.o |
| proc-y += thread_self.o |
| +proc-$(CONFIG_PROC_LATSENSE) += latsense.o |
| proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o |
| proc-$(CONFIG_NET) += proc_net.o |
| proc-$(CONFIG_PROC_KCORE) += kcore.o |
| diff --git a/fs/proc/base.c b/fs/proc/base.c |
| index 2e4cf0f52e486f910712508de0bae71f9d1121a4..0765fbec136433846f47198021d4c500bf564001 100644 |
| --- a/fs/proc/base.c |
| +++ b/fs/proc/base.c |
| @@ -3700,6 +3700,9 @@ static const struct pid_entry tid_base_stuff[] = { |
| ONE("ksm_merging_pages", S_IRUSR, proc_pid_ksm_merging_pages), |
| ONE("ksm_stat", S_IRUSR, proc_pid_ksm_stat), |
| #endif |
| +#ifdef CONFIG_PROC_LATSENSE |
| + REG("latency_sensitive", S_IRUGO|S_IWUSR, proc_tid_latsense_operations), |
| +#endif |
| }; |
| |
| static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx) |
| diff --git a/fs/proc/internal.h b/fs/proc/internal.h |
| index d16ec48623078f83efa59d941bf8acca7d5098c3..86e86c7a1445b4e48024757b88fcdddea20d2035 100644 |
| --- a/fs/proc/internal.h |
| +++ b/fs/proc/internal.h |
| @@ -149,6 +149,7 @@ unsigned name_to_int(const struct qstr *qstr); |
| * array.c |
| */ |
| extern const struct file_operations proc_tid_children_operations; |
| +extern const struct file_operations proc_tid_latsense_operations; |
| |
| extern void proc_task_name(struct seq_file *m, struct task_struct *p, |
| bool escape); |
| diff --git a/fs/proc/latsense.c b/fs/proc/latsense.c |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d8426446bac0e20feffd6d12d9125966a9b470c5 |
| --- /dev/null |
| +++ b/fs/proc/latsense.c |
| @@ -0,0 +1,94 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +/* |
| + * Copyright 2019 Google, Inc. |
| + * |
| + * Support for setting tasks as latency sensitive |
| + * using /proc/pid/tasks/tid/latency_sensitive interface. |
| + */ |
| + |
| +#include <linux/types.h> |
| +#include <linux/errno.h> |
| +#include <linux/kernel.h> |
| +#include <linux/sched/task.h> |
| +#include <linux/sched/latsense.h> |
| +#include <linux/proc_fs.h> |
| +#include <linux/seq_file.h> |
| +#include <linux/fs_struct.h> |
| + |
| +#include "internal.h" |
| + |
| +/* |
| + * Print out latsense related information: |
| + */ |
| +static int sched_latsense_show(struct seq_file *m, void *v) |
| +{ |
| + struct inode *inode = m->private; |
| + struct task_struct *p; |
| + |
| + p = get_proc_task(inode); |
| + if (!p) |
| + return -ESRCH; |
| + |
| + seq_printf(m, "%d\n", !!proc_sched_get_latency_sensitive(p)); |
| + |
| + put_task_struct(p); |
| + |
| + return 0; |
| +} |
| + |
| +static ssize_t |
| +sched_latsense_write(struct file *file, const char __user *buf, |
| + size_t count, loff_t *offset) |
| +{ |
| + struct inode *inode = file_inode(file); |
| + struct task_struct *p; |
| + char buffer[PROC_NUMBUF]; |
| + int val; |
| + int err; |
| + |
| + memset(buffer, 0, sizeof(buffer)); |
| + if (count > sizeof(buffer) - 1) |
| + count = sizeof(buffer) - 1; |
| + if (copy_from_user(buffer, buf, count)) |
| + return -EFAULT; |
| + |
| + err = kstrtoint(strstrip(buffer), 0, &val); |
| + if (err < 0) |
| + return err; |
| + |
| + if (val != 0 && val != 1) |
| + return -EINVAL; |
| + |
| + p = get_proc_task(inode); |
| + if (!p) |
| + return -ESRCH; |
| + |
| + err = proc_sched_set_latency_sensitive(p, val); |
| + if (err) |
| + count = err; |
| + |
| + put_task_struct(p); |
| + |
| + return count; |
| +} |
| + |
| +static int sched_latsense_open(struct inode *inode, struct file *filp) |
| +{ |
| + int ret; |
| + |
| + ret = single_open(filp, sched_latsense_show, NULL); |
| + if (!ret) { |
| + struct seq_file *m = filp->private_data; |
| + |
| + m->private = inode; |
| + } |
| + return ret; |
| +} |
| + |
| +const struct file_operations proc_tid_latsense_operations = { |
| + .open = sched_latsense_open, |
| + .read = seq_read, |
| + .write = sched_latsense_write, |
| + .llseek = seq_lseek, |
| + .release = single_release, |
| +}; |
| diff --git a/include/linux/sched.h b/include/linux/sched.h |
| index 292c316972485dae579a2518b4a2b847d35b961c..8fc90bd0426b91ed055f8c324c6de3cf9fd1361e 100644 |
| --- a/include/linux/sched.h |
| +++ b/include/linux/sched.h |
| @@ -822,6 +822,10 @@ struct task_struct { |
| |
| struct sched_statistics stats; |
| |
| +#ifdef CONFIG_PROC_LATSENSE |
| + int proc_latency_sensitive; |
| +#endif |
| + |
| #ifdef CONFIG_PREEMPT_NOTIFIERS |
| /* List of struct preempt_notifier: */ |
| struct hlist_head preempt_notifiers; |
| diff --git a/include/linux/sched/latsense.h b/include/linux/sched/latsense.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..9922cdbc924c5159e93c564c65c2b91edc7eb838 |
| --- /dev/null |
| +++ b/include/linux/sched/latsense.h |
| @@ -0,0 +1,8 @@ |
| +/* SPDX-License-Identifier: GPL-2.0 */ |
| +#ifndef _LINUX_SCHED_LATSENSE_H |
| +#define _LINUX_SCHED_LATSENSE_H |
| + |
| +extern int proc_sched_set_latency_sensitive(struct task_struct *p, int val); |
| +extern int proc_sched_get_latency_sensitive(struct task_struct *p); |
| + |
| +#endif /* _LINUX_SCHED_LATSENSE_H */ |
| diff --git a/kernel/sched/build_utility.c b/kernel/sched/build_utility.c |
| index 80a3df49ab478420a8827f62a0bdf3374479082e..da43355e8b90e336fe8e4251c1013a260af495a2 100644 |
| --- a/kernel/sched/build_utility.c |
| +++ b/kernel/sched/build_utility.c |
| @@ -107,3 +107,7 @@ |
| #ifdef CONFIG_SCHED_AUTOGROUP |
| # include "autogroup.c" |
| #endif |
| + |
| +#ifdef CONFIG_PROC_LATSENSE |
| +# include "latsense.c" |
| +#endif |
| diff --git a/kernel/sched/core.c b/kernel/sched/core.c |
| index a708d225c28e861922997ed27a25d1b21f072d2a..71710fb144e92a739cff22da27a10d3267c2108a 100644 |
| --- a/kernel/sched/core.c |
| +++ b/kernel/sched/core.c |
| @@ -4752,6 +4752,10 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) |
| p->prio = p->normal_prio = p->static_prio; |
| set_load_weight(p, false); |
| |
| +#ifdef CONFIG_PROC_LATSENSE |
| + p->proc_latency_sensitive = 0; |
| +#endif |
| + |
| /* |
| * We don't need the reset flag anymore after the fork. It has |
| * fulfilled its duty: |
| diff --git a/kernel/sched/latsense.c b/kernel/sched/latsense.c |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ebb0a12d7b215aed1c1f44116b4a400e65035327 |
| --- /dev/null |
| +++ b/kernel/sched/latsense.c |
| @@ -0,0 +1,17 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +#include "sched.h" |
| + |
| +int proc_sched_set_latency_sensitive(struct task_struct *p, int val) |
| +{ |
| + if (val != 0 && val != 1) |
| + return -EINVAL; |
| + |
| + p->proc_latency_sensitive = val; |
| + |
| + return 0; |
| +} |
| + |
| +int proc_sched_get_latency_sensitive(struct task_struct *p) |
| +{ |
| + return p->proc_latency_sensitive; |
| +} |
| diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h |
| index 2e5a95486a4222341216089921846c6cb25a5cd7..7f37b0392f30b4f28e1f184a5f96d75cb1e4a1a7 100644 |
| --- a/kernel/sched/sched.h |
| +++ b/kernel/sched/sched.h |
| @@ -10,6 +10,7 @@ |
| #include <linux/sched/cpufreq.h> |
| #include <linux/sched/deadline.h> |
| #include <linux/sched.h> |
| +#include <linux/sched/latsense.h> |
| #include <linux/sched/loadavg.h> |
| #include <linux/sched/mm.h> |
| #include <linux/sched/rseq_api.h> |
| -- |
| 2.43.0.472.g3155946c3a-goog |
| |