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

Configure Feed

Select the types of activity you want to include in your feed.

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) <peterz@infradead.org>
Signed-off-by: Daniel Bristot de Oliveira <bristot@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Juri Lelli <juri.lelli@redhat.com>
Link: https://lore.kernel.org/r/b6b0bcefaf25391bcf5b6ecdb9f1218de402d42e.1716811044.git.bristot@kernel.org

+62
+1
kernel/sched/core.c
··· 8336 8336 #endif /* CONFIG_SMP */ 8337 8337 hrtick_rq_init(rq); 8338 8338 atomic_set(&rq->nr_iowait, 0); 8339 + fair_server_init(rq); 8339 8340 8340 8341 #ifdef CONFIG_SCHED_CORE 8341 8342 rq->core = rq;
+23
kernel/sched/deadline.c
··· 1382 1382 } 1383 1383 1384 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 + 1391 + /* 1385 1392 * Because -- for now -- we share the rt bandwidth, we need to 1386 1393 * account our runtime there too, otherwise actual rt tasks 1387 1394 * would be able to exceed the shared quota. ··· 1421 1414 1422 1415 void dl_server_start(struct sched_dl_entity *dl_se) 1423 1416 { 1417 + struct rq *rq = dl_se->rq; 1418 + 1424 1419 if (!dl_server(dl_se)) { 1420 + /* Disabled */ 1421 + dl_se->dl_runtime = 0; 1422 + dl_se->dl_deadline = 1000 * NSEC_PER_MSEC; 1423 + dl_se->dl_period = 1000 * NSEC_PER_MSEC; 1424 + 1425 1425 dl_se->dl_server = 1; 1426 1426 setup_new_dl_entity(dl_se); 1427 1427 } 1428 + 1429 + if (!dl_se->dl_runtime) 1430 + return; 1431 + 1428 1432 enqueue_dl_entity(dl_se, ENQUEUE_WAKEUP); 1433 + if (!dl_task(dl_se->rq->curr) || dl_entity_preempt(dl_se, &rq->curr->dl)) 1434 + resched_curr(dl_se->rq); 1429 1435 } 1430 1436 1431 1437 void dl_server_stop(struct sched_dl_entity *dl_se) 1432 1438 { 1439 + if (!dl_se->dl_runtime) 1440 + return; 1441 + 1433 1442 dequeue_dl_entity(dl_se, DEQUEUE_SLEEP); 1434 1443 } 1435 1444
+34
kernel/sched/fair.c
··· 5765 5765 struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg); 5766 5766 struct sched_entity *se; 5767 5767 long task_delta, idle_task_delta, dequeue = 1; 5768 + long rq_h_nr_running = rq->cfs.h_nr_running; 5768 5769 5769 5770 raw_spin_lock(&cfs_b->lock); 5770 5771 /* This will start the period timer if necessary */ ··· 5838 5837 sub_nr_running(rq, task_delta); 5839 5838 5840 5839 done: 5840 + /* Stop the fair server if throttling resulted in no runnable tasks */ 5841 + if (rq_h_nr_running && !rq->cfs.h_nr_running) 5842 + dl_server_stop(&rq->fair_server); 5841 5843 /* 5842 5844 * Note: distribution will already see us throttled via the 5843 5845 * throttled-list. rq->lock protects completion. ··· 5858 5854 struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg); 5859 5855 struct sched_entity *se; 5860 5856 long task_delta, idle_task_delta; 5857 + long rq_h_nr_running = rq->cfs.h_nr_running; 5861 5858 5862 5859 se = cfs_rq->tg->se[cpu_of(rq)]; 5863 5860 ··· 5933 5928 5934 5929 unthrottle_throttle: 5935 5930 assert_list_leaf_cfs_rq(rq); 5931 + 5932 + /* Start the fair server if un-throttling resulted in new runnable tasks */ 5933 + if (!rq_h_nr_running && rq->cfs.h_nr_running) 5934 + dl_server_start(&rq->fair_server); 5936 5935 5937 5936 /* Determine whether we need to wake up potentially idle CPU: */ 5938 5937 if (rq->curr == rq->idle && rq->cfs.nr_running) ··· 6768 6759 */ 6769 6760 util_est_enqueue(&rq->cfs, p); 6770 6761 6762 + if (!throttled_hierarchy(task_cfs_rq(p)) && !rq->cfs.h_nr_running) 6763 + dl_server_start(&rq->fair_server); 6764 + 6771 6765 /* 6772 6766 * If in_iowait is set, the code below may not trigger any cpufreq 6773 6767 * utilization updates, so do it here explicitly with the IOWAIT flag ··· 6915 6903 rq->next_balance = jiffies; 6916 6904 6917 6905 dequeue_throttle: 6906 + if (!throttled_hierarchy(task_cfs_rq(p)) && !rq->cfs.h_nr_running) 6907 + dl_server_stop(&rq->fair_server); 6908 + 6918 6909 util_est_update(&rq->cfs, p, task_sleep); 6919 6910 hrtick_update(rq); 6920 6911 } ··· 8615 8600 static struct task_struct *__pick_next_task_fair(struct rq *rq) 8616 8601 { 8617 8602 return pick_next_task_fair(rq, NULL, NULL); 8603 + } 8604 + 8605 + static bool fair_server_has_tasks(struct sched_dl_entity *dl_se) 8606 + { 8607 + return !!dl_se->rq->cfs.nr_running; 8608 + } 8609 + 8610 + static struct task_struct *fair_server_pick(struct sched_dl_entity *dl_se) 8611 + { 8612 + return pick_next_task_fair(dl_se->rq, NULL, NULL); 8613 + } 8614 + 8615 + void fair_server_init(struct rq *rq) 8616 + { 8617 + struct sched_dl_entity *dl_se = &rq->fair_server; 8618 + 8619 + init_dl_entity(dl_se); 8620 + 8621 + dl_server_init(dl_se, rq, fair_server_has_tasks, fair_server_pick); 8618 8622 } 8619 8623 8620 8624 /*
+4
kernel/sched/sched.h
··· 363 363 dl_server_has_tasks_f has_tasks, 364 364 dl_server_pick_f pick); 365 365 366 + extern void fair_server_init(struct rq *rq); 367 + 366 368 #ifdef CONFIG_CGROUP_SCHED 367 369 368 370 extern struct list_head task_groups; ··· 1040 1038 struct cfs_rq cfs; 1041 1039 struct rt_rq rt; 1042 1040 struct dl_rq dl; 1041 + 1042 + struct sched_dl_entity fair_server; 1043 1043 1044 1044 #ifdef CONFIG_FAIR_GROUP_SCHED 1045 1045 /* list of leaf cfs_rq on this CPU: */