Skip to content

Commit 63ba842

Browse files
author
Peter Zijlstra
committed
sched/deadline: Introduce deadline servers
Low priority tasks (e.g., SCHED_OTHER) can suffer starvation if tasks with higher priority (e.g., SCHED_FIFO) monopolize CPU(s). RT Throttling has been introduced a while ago as a (mostly debug) countermeasure one can utilize to reserve some CPU time for low priority tasks (usually background type of work, e.g. workqueues, timers, etc.). It however has its own problems (see documentation) and the undesired effect of unconditionally throttling FIFO tasks even when no lower priority activity needs to run (there are mechanisms to fix this issue as well, but, again, with their own problems). Introduce deadline servers to service low priority tasks needs under starvation conditions. Deadline servers are built extending SCHED_DEADLINE implementation to allow 2-level scheduling (a sched_deadline entity becomes a container for lower priority scheduling entities). Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Daniel Bristot de Oliveira <bristot@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lkml.kernel.org/r/4968601859d920335cf85822eb573a5f179f04b8.1699095159.git.bristot@kernel.org
1 parent 2f7a0f5 commit 63ba842

5 files changed

Lines changed: 292 additions & 108 deletions

File tree

include/linux/sched.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,13 @@ struct robust_list_head;
6363
struct root_domain;
6464
struct rq;
6565
struct sched_attr;
66+
struct sched_dl_entity;
6667
struct seq_file;
6768
struct sighand_struct;
6869
struct signal_struct;
6970
struct task_delay_info;
7071
struct task_group;
72+
struct task_struct;
7173
struct user_event_mm;
7274

7375
/*
@@ -607,6 +609,9 @@ struct sched_rt_entity {
607609
#endif
608610
} __randomize_layout;
609611

612+
typedef bool (*dl_server_has_tasks_f)(struct sched_dl_entity *);
613+
typedef struct task_struct *(*dl_server_pick_f)(struct sched_dl_entity *);
614+
610615
struct sched_dl_entity {
611616
struct rb_node rb_node;
612617

@@ -654,6 +659,7 @@ struct sched_dl_entity {
654659
unsigned int dl_yielded : 1;
655660
unsigned int dl_non_contending : 1;
656661
unsigned int dl_overrun : 1;
662+
unsigned int dl_server : 1;
657663

658664
/*
659665
* Bandwidth enforcement timer. Each -deadline task has its
@@ -668,7 +674,20 @@ struct sched_dl_entity {
668674
* timer is needed to decrease the active utilization at the correct
669675
* time.
670676
*/
671-
struct hrtimer inactive_timer;
677+
struct hrtimer inactive_timer;
678+
679+
/*
680+
* Bits for DL-server functionality. Also see the comment near
681+
* dl_server_update().
682+
*
683+
* @rq the runqueue this server is for
684+
*
685+
* @server_has_tasks() returns true if @server_pick return a
686+
* runnable task.
687+
*/
688+
struct rq *rq;
689+
dl_server_has_tasks_f server_has_tasks;
690+
dl_server_pick_f server_pick;
672691

673692
#ifdef CONFIG_RT_MUTEXES
674693
/*
@@ -795,6 +814,7 @@ struct task_struct {
795814
struct sched_entity se;
796815
struct sched_rt_entity rt;
797816
struct sched_dl_entity dl;
817+
struct sched_dl_entity *dl_server;
798818
const struct sched_class *sched_class;
799819

800820
#ifdef CONFIG_SCHED_CORE

kernel/sched/core.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3797,6 +3797,8 @@ ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags,
37973797
rq->idle_stamp = 0;
37983798
}
37993799
#endif
3800+
3801+
p->dl_server = NULL;
38003802
}
38013803

38023804
/*
@@ -6003,12 +6005,27 @@ __pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
60036005
p = pick_next_task_idle(rq);
60046006
}
60056007

6008+
/*
6009+
* This is the fast path; it cannot be a DL server pick;
6010+
* therefore even if @p == @prev, ->dl_server must be NULL.
6011+
*/
6012+
if (p->dl_server)
6013+
p->dl_server = NULL;
6014+
60066015
return p;
60076016
}
60086017

60096018
restart:
60106019
put_prev_task_balance(rq, prev, rf);
60116020

6021+
/*
6022+
* We've updated @prev and no longer need the server link, clear it.
6023+
* Must be done before ->pick_next_task() because that can (re)set
6024+
* ->dl_server.
6025+
*/
6026+
if (prev->dl_server)
6027+
prev->dl_server = NULL;
6028+
60126029
for_each_class(class) {
60136030
p = class->pick_next_task(rq);
60146031
if (p)

0 commit comments

Comments
 (0)