mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
sched_ext: Introduce cgroup sub-sched support
A system often runs multiple workloads especially in multi-tenant server environments where a system is split into partitions servicing separate more-or-less independent workloads each requiring an application-specific scheduler. To support such and other use cases, sched_ext is in the process of growing multiple scheduler support. When partitioning a system in terms of CPUs for such use cases, an oft-taken approach is hard partitioning the system using cpuset. While it would be possible to tie sched_ext multiple scheduler support to cpuset partitions, such an approach would have fundamental limitations stemming from the lack of dynamism and flexibility. Users often don't care which specific CPUs are assigned to which workload and want to take advantage of optimizations which are enabled by running workloads on a larger machine - e.g. opportunistic over-commit, improving latency critical workload characteristics while maintaining bandwidth fairness, employing control mechanisms based on different criteria than on-CPU time for e.g. flexible memory bandwidth isolation, packing similar parts from different workloads on same L3s to improve cache efficiency, and so on. As this sort of dynamic behaviors are impossible or difficult to implement with hard partitioning, sched_ext is implementing cgroup sub-sched support where schedulers can be attached to the cgroup hierarchy and a parent scheduler is responsible for controlling the CPUs that each child can use at any given moment. This makes CPU distribution dynamically controlled by BPF allowing high flexibility. This patch adds the skeletal sched_ext cgroup sub-sched support: - sched_ext_ops.sub_cgroup_id and .sub_attach/detach() are added. Non-zero sub_cgroup_id indicates that the scheduler is to be attached to the identified cgroup. A sub-sched is attached to the cgroup iff the nearest ancestor scheduler implements .sub_attach() and grants the attachment. Max nesting depth is limited by SCX_SUB_MAX_DEPTH. - When a scheduler exits, all its descendant schedulers are exited together. Also, cgroup.scx_sched added which points to the effective scheduler instance for the cgroup. This is updated on scheduler init/exit and inherited on cgroup online. When a cgroup is offlined, the attached scheduler is automatically exited. - Sub-sched support is gated on CONFIG_EXT_SUB_SCHED which is automatically enabled if both SCX and cgroups are enabled. Sub-sched support is not tied to the CPU controller but rather the cgroup hierarchy itself. This is intentional as the support for cpu.weight and cpu.max based resource control is orthogonal to sub-sched support. Note that CONFIG_CGROUPS around cgroup subtree iteration support for scx_task_iter is replaced with CONFIG_EXT_SUB_SCHED for consistency. - This allows loading sub-scheds and most framework operations such as propagating disable down the hierarchy work. However, sub-scheds are not operational yet and all tasks stay with the root sched. This will serve as the basis for building up full sub-sched support. - DSQs point to the scx_sched they belong to. - scx_qmap is updated to allow attachment of sub-scheds and also serving as sub-scheds. - scx_is_descendant() is added but not yet used in this patch. It is used by later changes in the series and placed here as this is where the function belongs. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/percpu-refcount.h>
|
||||
#include <linux/percpu-rwsem.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/u64_stats_sync.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/bpf-cgroup-defs.h>
|
||||
@@ -624,6 +625,9 @@ struct cgroup {
|
||||
#ifdef CONFIG_BPF_SYSCALL
|
||||
struct bpf_local_storage __rcu *bpf_cgrp_storage;
|
||||
#endif
|
||||
#ifdef CONFIG_EXT_SUB_SCHED
|
||||
struct scx_sched __rcu *scx_sched;
|
||||
#endif
|
||||
|
||||
/* All ancestors including self */
|
||||
union {
|
||||
|
||||
@@ -78,6 +78,7 @@ struct scx_dispatch_q {
|
||||
u64 id;
|
||||
struct rhash_head hash_node;
|
||||
struct llist_node free_node;
|
||||
struct scx_sched *sched;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
@@ -157,6 +158,8 @@ struct scx_dsq_list_node {
|
||||
.priv = (__priv), \
|
||||
}
|
||||
|
||||
struct scx_sched;
|
||||
|
||||
/*
|
||||
* The following is embedded in task_struct and contains all fields necessary
|
||||
* for a task to be scheduled by SCX.
|
||||
|
||||
@@ -1176,6 +1176,10 @@ config EXT_GROUP_SCHED
|
||||
|
||||
endif #CGROUP_SCHED
|
||||
|
||||
config EXT_SUB_SCHED
|
||||
def_bool y
|
||||
depends on SCHED_CLASS_EXT
|
||||
|
||||
config SCHED_MM_CID
|
||||
def_bool y
|
||||
depends on SMP && RSEQ
|
||||
|
||||
+504
-28
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,8 @@ enum scx_consts {
|
||||
SCX_BYPASS_LB_DONOR_PCT = 125,
|
||||
SCX_BYPASS_LB_MIN_DELTA_DIV = 4,
|
||||
SCX_BYPASS_LB_BATCH = 256,
|
||||
|
||||
SCX_SUB_MAX_DEPTH = 4,
|
||||
};
|
||||
|
||||
enum scx_exit_kind {
|
||||
@@ -38,6 +40,7 @@ enum scx_exit_kind {
|
||||
SCX_EXIT_UNREG_BPF, /* BPF-initiated unregistration */
|
||||
SCX_EXIT_UNREG_KERN, /* kernel-initiated unregistration */
|
||||
SCX_EXIT_SYSRQ, /* requested by 'S' sysrq */
|
||||
SCX_EXIT_PARENT, /* parent exiting */
|
||||
|
||||
SCX_EXIT_ERROR = 1024, /* runtime error, error msg contains details */
|
||||
SCX_EXIT_ERROR_BPF, /* ERROR but triggered through scx_bpf_error() */
|
||||
@@ -62,6 +65,7 @@ enum scx_exit_kind {
|
||||
enum scx_exit_code {
|
||||
/* Reasons */
|
||||
SCX_ECODE_RSN_HOTPLUG = 1LLU << 32,
|
||||
SCX_ECODE_RSN_CGROUP_OFFLINE = 2LLU << 32,
|
||||
|
||||
/* Actions */
|
||||
SCX_ECODE_ACT_RESTART = 1LLU << 48,
|
||||
@@ -213,7 +217,7 @@ struct scx_exit_task_args {
|
||||
bool cancelled;
|
||||
};
|
||||
|
||||
/* argument container for ops->cgroup_init() */
|
||||
/* argument container for ops.cgroup_init() */
|
||||
struct scx_cgroup_init_args {
|
||||
/* the weight of the cgroup [1..10000] */
|
||||
u32 weight;
|
||||
@@ -236,12 +240,12 @@ enum scx_cpu_preempt_reason {
|
||||
};
|
||||
|
||||
/*
|
||||
* Argument container for ops->cpu_acquire(). Currently empty, but may be
|
||||
* Argument container for ops.cpu_acquire(). Currently empty, but may be
|
||||
* expanded in the future.
|
||||
*/
|
||||
struct scx_cpu_acquire_args {};
|
||||
|
||||
/* argument container for ops->cpu_release() */
|
||||
/* argument container for ops.cpu_release() */
|
||||
struct scx_cpu_release_args {
|
||||
/* the reason the CPU was preempted */
|
||||
enum scx_cpu_preempt_reason reason;
|
||||
@@ -250,9 +254,7 @@ struct scx_cpu_release_args {
|
||||
struct task_struct *task;
|
||||
};
|
||||
|
||||
/*
|
||||
* Informational context provided to dump operations.
|
||||
*/
|
||||
/* informational context provided to dump operations */
|
||||
struct scx_dump_ctx {
|
||||
enum scx_exit_kind kind;
|
||||
s64 exit_code;
|
||||
@@ -261,6 +263,18 @@ struct scx_dump_ctx {
|
||||
u64 at_jiffies;
|
||||
};
|
||||
|
||||
/* argument container for ops.sub_attach() */
|
||||
struct scx_sub_attach_args {
|
||||
struct sched_ext_ops *ops;
|
||||
char *cgroup_path;
|
||||
};
|
||||
|
||||
/* argument container for ops.sub_detach() */
|
||||
struct scx_sub_detach_args {
|
||||
struct sched_ext_ops *ops;
|
||||
char *cgroup_path;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sched_ext_ops - Operation table for BPF scheduler implementation
|
||||
*
|
||||
@@ -721,6 +735,20 @@ struct sched_ext_ops {
|
||||
|
||||
#endif /* CONFIG_EXT_GROUP_SCHED */
|
||||
|
||||
/**
|
||||
* @sub_attach: Attach a sub-scheduler
|
||||
* @args: argument container, see the struct definition
|
||||
*
|
||||
* Return 0 to accept the sub-scheduler. -errno to reject.
|
||||
*/
|
||||
s32 (*sub_attach)(struct scx_sub_attach_args *args);
|
||||
|
||||
/**
|
||||
* @sub_detach: Detach a sub-scheduler
|
||||
* @args: argument container, see the struct definition
|
||||
*/
|
||||
void (*sub_detach)(struct scx_sub_detach_args *args);
|
||||
|
||||
/*
|
||||
* All online ops must come before ops.cpu_online().
|
||||
*/
|
||||
@@ -762,6 +790,10 @@ struct sched_ext_ops {
|
||||
*/
|
||||
void (*exit)(struct scx_exit_info *info);
|
||||
|
||||
/*
|
||||
* Data fields must comes after all ops fields.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @dispatch_max_batch: Max nr of tasks that dispatch() can dispatch
|
||||
*/
|
||||
@@ -796,6 +828,12 @@ struct sched_ext_ops {
|
||||
*/
|
||||
u64 hotplug_seq;
|
||||
|
||||
/**
|
||||
* @cgroup_id: When >1, attach the scheduler as a sub-scheduler on the
|
||||
* specified cgroup.
|
||||
*/
|
||||
u64 sub_cgroup_id;
|
||||
|
||||
/**
|
||||
* @name: BPF scheduler's name
|
||||
*
|
||||
@@ -900,6 +938,8 @@ struct scx_sched {
|
||||
struct scx_dispatch_q **global_dsqs;
|
||||
struct scx_sched_pcpu __percpu *pcpu;
|
||||
|
||||
s32 level;
|
||||
|
||||
/*
|
||||
* Updates to the following warned bitfields can race causing RMW issues
|
||||
* but it doesn't really matter.
|
||||
@@ -907,6 +947,18 @@ struct scx_sched {
|
||||
bool warned_zero_slice:1;
|
||||
bool warned_deprecated_rq:1;
|
||||
|
||||
struct list_head all;
|
||||
|
||||
#ifdef CONFIG_EXT_SUB_SCHED
|
||||
struct list_head children;
|
||||
struct list_head sibling;
|
||||
struct cgroup *cgrp;
|
||||
char *cgrp_path;
|
||||
struct kset *sub_kset;
|
||||
|
||||
bool sub_attached;
|
||||
#endif /* CONFIG_EXT_SUB_SCHED */
|
||||
|
||||
atomic_t exit_kind;
|
||||
struct scx_exit_info *exit_info;
|
||||
|
||||
@@ -916,6 +968,9 @@ struct scx_sched {
|
||||
struct irq_work error_irq_work;
|
||||
struct kthread_work disable_work;
|
||||
struct rcu_work rcu_work;
|
||||
|
||||
/* all ancestors including self */
|
||||
struct scx_sched *ancestors[];
|
||||
};
|
||||
|
||||
enum scx_wake_flags {
|
||||
|
||||
@@ -41,6 +41,7 @@ const volatile u32 dsp_batch;
|
||||
const volatile bool highpri_boosting;
|
||||
const volatile bool print_dsqs_and_events;
|
||||
const volatile bool print_msgs;
|
||||
const volatile u64 sub_cgroup_id;
|
||||
const volatile s32 disallow_tgid;
|
||||
const volatile bool suppress_dump;
|
||||
|
||||
@@ -862,7 +863,7 @@ s32 BPF_STRUCT_OPS_SLEEPABLE(qmap_init)
|
||||
struct bpf_timer *timer;
|
||||
s32 ret;
|
||||
|
||||
if (print_msgs)
|
||||
if (print_msgs && !sub_cgroup_id)
|
||||
print_cpus();
|
||||
|
||||
ret = scx_bpf_create_dsq(SHARED_DSQ, -1);
|
||||
@@ -892,6 +893,11 @@ void BPF_STRUCT_OPS(qmap_exit, struct scx_exit_info *ei)
|
||||
UEI_RECORD(uei, ei);
|
||||
}
|
||||
|
||||
s32 BPF_STRUCT_OPS(qmap_sub_attach, struct scx_sub_attach_args *args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SCX_OPS_DEFINE(qmap_ops,
|
||||
.select_cpu = (void *)qmap_select_cpu,
|
||||
.enqueue = (void *)qmap_enqueue,
|
||||
@@ -907,6 +913,7 @@ SCX_OPS_DEFINE(qmap_ops,
|
||||
.cgroup_init = (void *)qmap_cgroup_init,
|
||||
.cgroup_set_weight = (void *)qmap_cgroup_set_weight,
|
||||
.cgroup_set_bandwidth = (void *)qmap_cgroup_set_bandwidth,
|
||||
.sub_attach = (void *)qmap_sub_attach,
|
||||
.cpu_online = (void *)qmap_cpu_online,
|
||||
.cpu_offline = (void *)qmap_cpu_offline,
|
||||
.init = (void *)qmap_init,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/stat.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include <scx/common.h>
|
||||
#include "scx_qmap.bpf.skel.h"
|
||||
@@ -67,7 +68,7 @@ int main(int argc, char **argv)
|
||||
|
||||
skel->rodata->slice_ns = __COMPAT_ENUM_OR_ZERO("scx_public_consts", "SCX_SLICE_DFL");
|
||||
|
||||
while ((opt = getopt(argc, argv, "s:e:t:T:l:b:PMHd:D:Spvh")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "s:e:t:T:l:b:PMHc:d:D:Spvh")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
skel->rodata->slice_ns = strtoull(optarg, NULL, 0) * 1000;
|
||||
@@ -96,6 +97,16 @@ int main(int argc, char **argv)
|
||||
case 'H':
|
||||
skel->rodata->highpri_boosting = true;
|
||||
break;
|
||||
case 'c': {
|
||||
struct stat st;
|
||||
if (stat(optarg, &st) < 0) {
|
||||
perror("stat");
|
||||
return 1;
|
||||
}
|
||||
skel->struct_ops.qmap_ops->sub_cgroup_id = st.st_ino;
|
||||
skel->rodata->sub_cgroup_id = st.st_ino;
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
skel->rodata->disallow_tgid = strtol(optarg, NULL, 0);
|
||||
if (skel->rodata->disallow_tgid < 0)
|
||||
|
||||
Reference in New Issue
Block a user