blob: edb710b646b90d1833cf42138c04d381dc8c705f [file] [log] [blame]
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