Skip to content

Commit 557a6bf

Browse files
author
Peter Zijlstra
committed
sched/fair: Add trivial fair server
Use deadline servers to service fair tasks. This patch adds a fair_server deadline entity which acts as a container for fair entities and can be used to fix starvation when higher priority (wrt fair) tasks are monopolizing CPU(s). Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Daniel Bristot de Oliveira <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Tested-by: Juri Lelli <[email protected]> Link: https://lore.kernel.org/r/b6b0bcefaf25391bcf5b6ecdb9f1218de402d42e.1716811044.git.bristot@kernel.org
1 parent a741b82 commit 557a6bf

File tree

4 files changed

+62
-0
lines changed

4 files changed

+62
-0
lines changed

kernel/sched/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8336,6 +8336,7 @@ void __init sched_init(void)
83368336
#endif /* CONFIG_SMP */
83378337
hrtick_rq_init(rq);
83388338
atomic_set(&rq->nr_iowait, 0);
8339+
fair_server_init(rq);
83398340

83408341
#ifdef CONFIG_SCHED_CORE
83418342
rq->core = rq;

kernel/sched/deadline.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,13 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64
13811381
resched_curr(rq);
13821382
}
13831383

1384+
/*
1385+
* The fair server (sole dl_server) does not account for real-time
1386+
* workload because it is running fair work.
1387+
*/
1388+
if (dl_se == &rq->fair_server)
1389+
return;
1390+
13841391
/*
13851392
* Because -- for now -- we share the rt bandwidth, we need to
13861393
* account our runtime there too, otherwise actual rt tasks
@@ -1414,15 +1421,31 @@ void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec)
14141421

14151422
void dl_server_start(struct sched_dl_entity *dl_se)
14161423
{
1424+
struct rq *rq = dl_se->rq;
1425+
14171426
if (!dl_server(dl_se)) {
1427+
/* Disabled */
1428+
dl_se->dl_runtime = 0;
1429+
dl_se->dl_deadline = 1000 * NSEC_PER_MSEC;
1430+
dl_se->dl_period = 1000 * NSEC_PER_MSEC;
1431+
14181432
dl_se->dl_server = 1;
14191433
setup_new_dl_entity(dl_se);
14201434
}
1435+
1436+
if (!dl_se->dl_runtime)
1437+
return;
1438+
14211439
enqueue_dl_entity(dl_se, ENQUEUE_WAKEUP);
1440+
if (!dl_task(dl_se->rq->curr) || dl_entity_preempt(dl_se, &rq->curr->dl))
1441+
resched_curr(dl_se->rq);
14221442
}
14231443

14241444
void dl_server_stop(struct sched_dl_entity *dl_se)
14251445
{
1446+
if (!dl_se->dl_runtime)
1447+
return;
1448+
14261449
dequeue_dl_entity(dl_se, DEQUEUE_SLEEP);
14271450
}
14281451

kernel/sched/fair.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5765,6 +5765,7 @@ static bool throttle_cfs_rq(struct cfs_rq *cfs_rq)
57655765
struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg);
57665766
struct sched_entity *se;
57675767
long task_delta, idle_task_delta, dequeue = 1;
5768+
long rq_h_nr_running = rq->cfs.h_nr_running;
57685769

57695770
raw_spin_lock(&cfs_b->lock);
57705771
/* This will start the period timer if necessary */
@@ -5837,6 +5838,9 @@ static bool throttle_cfs_rq(struct cfs_rq *cfs_rq)
58375838
sub_nr_running(rq, task_delta);
58385839

58395840
done:
5841+
/* Stop the fair server if throttling resulted in no runnable tasks */
5842+
if (rq_h_nr_running && !rq->cfs.h_nr_running)
5843+
dl_server_stop(&rq->fair_server);
58405844
/*
58415845
* Note: distribution will already see us throttled via the
58425846
* throttled-list. rq->lock protects completion.
@@ -5854,6 +5858,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
58545858
struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg);
58555859
struct sched_entity *se;
58565860
long task_delta, idle_task_delta;
5861+
long rq_h_nr_running = rq->cfs.h_nr_running;
58575862

58585863
se = cfs_rq->tg->se[cpu_of(rq)];
58595864

@@ -5929,6 +5934,10 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
59295934
unthrottle_throttle:
59305935
assert_list_leaf_cfs_rq(rq);
59315936

5937+
/* Start the fair server if un-throttling resulted in new runnable tasks */
5938+
if (!rq_h_nr_running && rq->cfs.h_nr_running)
5939+
dl_server_start(&rq->fair_server);
5940+
59325941
/* Determine whether we need to wake up potentially idle CPU: */
59335942
if (rq->curr == rq->idle && rq->cfs.nr_running)
59345943
resched_curr(rq);
@@ -6759,6 +6768,9 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
67596768
*/
67606769
util_est_enqueue(&rq->cfs, p);
67616770

6771+
if (!throttled_hierarchy(task_cfs_rq(p)) && !rq->cfs.h_nr_running)
6772+
dl_server_start(&rq->fair_server);
6773+
67626774
/*
67636775
* If in_iowait is set, the code below may not trigger any cpufreq
67646776
* utilization updates, so do it here explicitly with the IOWAIT flag
@@ -6903,6 +6915,9 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
69036915
rq->next_balance = jiffies;
69046916

69056917
dequeue_throttle:
6918+
if (!throttled_hierarchy(task_cfs_rq(p)) && !rq->cfs.h_nr_running)
6919+
dl_server_stop(&rq->fair_server);
6920+
69066921
util_est_update(&rq->cfs, p, task_sleep);
69076922
hrtick_update(rq);
69086923
}
@@ -8602,6 +8617,25 @@ static struct task_struct *__pick_next_task_fair(struct rq *rq)
86028617
return pick_next_task_fair(rq, NULL, NULL);
86038618
}
86048619

8620+
static bool fair_server_has_tasks(struct sched_dl_entity *dl_se)
8621+
{
8622+
return !!dl_se->rq->cfs.nr_running;
8623+
}
8624+
8625+
static struct task_struct *fair_server_pick(struct sched_dl_entity *dl_se)
8626+
{
8627+
return pick_next_task_fair(dl_se->rq, NULL, NULL);
8628+
}
8629+
8630+
void fair_server_init(struct rq *rq)
8631+
{
8632+
struct sched_dl_entity *dl_se = &rq->fair_server;
8633+
8634+
init_dl_entity(dl_se);
8635+
8636+
dl_server_init(dl_se, rq, fair_server_has_tasks, fair_server_pick);
8637+
}
8638+
86058639
/*
86068640
* Account for a descheduled task:
86078641
*/

kernel/sched/sched.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
363363
dl_server_has_tasks_f has_tasks,
364364
dl_server_pick_f pick);
365365

366+
extern void fair_server_init(struct rq *rq);
367+
366368
#ifdef CONFIG_CGROUP_SCHED
367369

368370
extern struct list_head task_groups;
@@ -1039,6 +1041,8 @@ struct rq {
10391041
struct rt_rq rt;
10401042
struct dl_rq dl;
10411043

1044+
struct sched_dl_entity fair_server;
1045+
10421046
#ifdef CONFIG_FAIR_GROUP_SCHED
10431047
/* list of leaf cfs_rq on this CPU: */
10441048
struct list_head leaf_cfs_rq_list;

0 commit comments

Comments
 (0)