Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sched_ext: Add boilerplate for extensible scheduler class

This adds dummy implementations of sched_ext interfaces which interact with
the scheduler core and hook them in the correct places. As they're all
dummies, this doesn't cause any behavior changes. This is split out to help
reviewing.

v2: balance_scx_on_up() dropped. This will be handled in sched_ext proper.

Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: David Vernet <dvernet@meta.com>
Acked-by: Josh Don <joshdon@google.com>
Acked-by: Hao Luo <haoluo@google.com>
Acked-by: Barret Rhoden <brho@google.com>

+66 -8
+12
include/linux/sched/ext.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _LINUX_SCHED_EXT_H 3 + #define _LINUX_SCHED_EXT_H 4 + 5 + #ifdef CONFIG_SCHED_CLASS_EXT 6 + #error "NOT IMPLEMENTED YET" 7 + #else /* !CONFIG_SCHED_CLASS_EXT */ 8 + 9 + static inline void sched_ext_free(struct task_struct *p) {} 10 + 11 + #endif /* CONFIG_SCHED_CLASS_EXT */ 12 + #endif /* _LINUX_SCHED_EXT_H */
+2
kernel/fork.c
··· 23 23 #include <linux/sched/task.h> 24 24 #include <linux/sched/task_stack.h> 25 25 #include <linux/sched/cputime.h> 26 + #include <linux/sched/ext.h> 26 27 #include <linux/seq_file.h> 27 28 #include <linux/rtmutex.h> 28 29 #include <linux/init.h> ··· 972 971 WARN_ON(refcount_read(&tsk->usage)); 973 972 WARN_ON(tsk == current); 974 973 974 + sched_ext_free(tsk); 975 975 io_uring_free(tsk); 976 976 cgroup_free(tsk); 977 977 task_numa_free(tsk, true);
+24 -8
kernel/sched/core.c
··· 4559 4559 */ 4560 4560 int sched_fork(unsigned long clone_flags, struct task_struct *p) 4561 4561 { 4562 + int ret; 4563 + 4562 4564 __sched_fork(clone_flags, p); 4563 4565 /* 4564 4566 * We mark the process as NEW here. This guarantees that ··· 4597 4595 p->sched_reset_on_fork = 0; 4598 4596 } 4599 4597 4600 - if (dl_prio(p->prio)) 4601 - return -EAGAIN; 4602 - else if (rt_prio(p->prio)) 4598 + scx_pre_fork(p); 4599 + 4600 + if (dl_prio(p->prio)) { 4601 + ret = -EAGAIN; 4602 + goto out_cancel; 4603 + } else if (rt_prio(p->prio)) { 4603 4604 p->sched_class = &rt_sched_class; 4604 - else 4605 + } else { 4605 4606 p->sched_class = &fair_sched_class; 4607 + } 4606 4608 4607 4609 init_entity_runnable_average(&p->se); 4608 4610 ··· 4624 4618 RB_CLEAR_NODE(&p->pushable_dl_tasks); 4625 4619 #endif 4626 4620 return 0; 4621 + 4622 + out_cancel: 4623 + scx_cancel_fork(p); 4624 + return ret; 4627 4625 } 4628 4626 4629 4627 int sched_cgroup_fork(struct task_struct *p, struct kernel_clone_args *kargs) ··· 4658 4648 p->sched_class->task_fork(p); 4659 4649 raw_spin_unlock_irqrestore(&p->pi_lock, flags); 4660 4650 4661 - return 0; 4651 + return scx_fork(p); 4662 4652 } 4663 4653 4664 4654 void sched_cancel_fork(struct task_struct *p) 4665 4655 { 4656 + scx_cancel_fork(p); 4666 4657 } 4667 4658 4668 4659 void sched_post_fork(struct task_struct *p) 4669 4660 { 4670 4661 uclamp_post_fork(p); 4662 + scx_post_fork(p); 4671 4663 } 4672 4664 4673 4665 unsigned long to_ratio(u64 period, u64 runtime) ··· 5812 5800 * We can terminate the balance pass as soon as we know there is 5813 5801 * a runnable task of @class priority or higher. 5814 5802 */ 5815 - for_class_range(class, prev->sched_class, &idle_sched_class) { 5803 + for_balance_class_range(class, prev->sched_class, &idle_sched_class) { 5816 5804 if (class->balance(rq, prev, rf)) 5817 5805 break; 5818 5806 } ··· 5829 5817 { 5830 5818 const struct sched_class *class; 5831 5819 struct task_struct *p; 5820 + 5821 + if (scx_enabled()) 5822 + goto restart; 5832 5823 5833 5824 /* 5834 5825 * Optimization: we know that if all tasks are in the fair class we can ··· 5873 5858 if (prev->dl_server) 5874 5859 prev->dl_server = NULL; 5875 5860 5876 - for_each_class(class) { 5861 + for_each_active_class(class) { 5877 5862 p = class->pick_next_task(rq); 5878 5863 if (p) 5879 5864 return p; ··· 5906 5891 const struct sched_class *class; 5907 5892 struct task_struct *p; 5908 5893 5909 - for_each_class(class) { 5894 + for_each_active_class(class) { 5910 5895 p = class->pick_task(rq); 5911 5896 if (p) 5912 5897 return p; ··· 8370 8355 balance_push_set(smp_processor_id(), false); 8371 8356 #endif 8372 8357 init_sched_fair_class(); 8358 + init_sched_ext_class(); 8373 8359 8374 8360 psi_init(); 8375 8361
+24
kernel/sched/ext.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifdef CONFIG_SCHED_CLASS_EXT 4 + #error "NOT IMPLEMENTED YET" 5 + #else /* CONFIG_SCHED_CLASS_EXT */ 6 + 7 + #define scx_enabled() false 8 + 9 + static inline void scx_pre_fork(struct task_struct *p) {} 10 + static inline int scx_fork(struct task_struct *p) { return 0; } 11 + static inline void scx_post_fork(struct task_struct *p) {} 12 + static inline void scx_cancel_fork(struct task_struct *p) {} 13 + static inline void init_sched_ext_class(void) {} 14 + 15 + #define for_each_active_class for_each_class 16 + #define for_balance_class_range for_class_range 17 + 18 + #endif /* CONFIG_SCHED_CLASS_EXT */ 19 + 20 + #if defined(CONFIG_SCHED_CLASS_EXT) && defined(CONFIG_SMP) 21 + #error "NOT IMPLEMENTED YET" 22 + #else 23 + static inline void scx_update_idle(struct rq *rq, bool idle) {} 24 + #endif
+2
kernel/sched/idle.c
··· 452 452 453 453 static void put_prev_task_idle(struct rq *rq, struct task_struct *prev) 454 454 { 455 + scx_update_idle(rq, false); 455 456 } 456 457 457 458 static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool first) 458 459 { 459 460 update_idle_core(rq); 461 + scx_update_idle(rq, true); 460 462 schedstat_inc(rq->sched_goidle); 461 463 } 462 464
+2
kernel/sched/sched.h
··· 3658 3658 3659 3659 #endif 3660 3660 3661 + #include "ext.h" 3662 + 3661 3663 #endif /* _KERNEL_SCHED_SCHED_H */