mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
sched/eevdf: Move to a single runqueue
Change fair/cgroup to a single runqueue.
Infamously fair/cgroup isn't working for a number of people; typically
the complaint is latencies and/or overhead. The latency issue is due
to the intermediate entries that represent a combination of tasks and
thereby obfuscate the runnability of tasks.
The approach here is to leave the cgroup hierarchy as is; including
the intermediate enqueue/dequeue but move the actual EEVDF runqueue
outside. This means things like the shares_weight approximation are
fully preserved.
That is, given a hierarchy like:
R
|
se--G1
/ \
G2--se se--G3
/ \ |
T1--se se--T2 se--T3
This is fully maintained for load tracking, however the EEVDF parts of
cfs_rq/se go unused for the intermediates and are instead connected
like:
_R_
/ | \
T1 T2 T3
Since the effective weight of the entities is determined by the
hierarchy, this gets recomputed on enqueue,set_next_task and tick.
Notably, the effective weight (se->h_load) is computed from the
hierarchical fraction: se->load / cfs_rq->load.
Since EEVDF is now exclusively operating on rq->cfs, it needs to
consider cfs_rq->h_nr_queued rather than cfs_rq->nr_queued. Similarly,
only tasks can get delayed, simplifying some of the cgroup cleanup.
One place where additional information was required was
set_next_task() / put_prev_task(), where we need to track 'current'
both in the hierarchical sense (cfs_rq->h_curr) and in the flat sense
(cfs_rq->curr).
As a result of only having a single level to pick from, much of the
complications in pick_next_task() and preemption go away.
Since many of the hierarchical operations are still there, this won't
immediately fix the performance issues, but hopefully it will fix some
of the latency issues.
TODO: split struct cfs_rq / struct sched_entity
TODO: try and get rid of h_curr
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260605124052.227463677%40infradead.org
This commit is contained in:
committed by
Peter Zijlstra
parent
fb1050ac8e
commit
85570f10a4
@@ -575,6 +575,7 @@ struct sched_statistics {
|
||||
struct sched_entity {
|
||||
/* For load-balancing: */
|
||||
struct load_weight load;
|
||||
struct load_weight h_load;
|
||||
struct rb_node run_node;
|
||||
u64 deadline;
|
||||
u64 min_vruntime;
|
||||
|
||||
+1
-4
@@ -5657,11 +5657,8 @@ EXPORT_PER_CPU_SYMBOL(kernel_cpustat);
|
||||
*/
|
||||
static inline void prefetch_curr_exec_start(struct task_struct *p)
|
||||
{
|
||||
#ifdef CONFIG_FAIR_GROUP_SCHED
|
||||
struct sched_entity *curr = p->se.cfs_rq->curr;
|
||||
#else
|
||||
struct sched_entity *curr = task_rq(p)->cfs.curr;
|
||||
#endif
|
||||
|
||||
prefetch(curr);
|
||||
prefetch(&curr->exec_start);
|
||||
}
|
||||
|
||||
@@ -975,10 +975,11 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
|
||||
else
|
||||
SEQ_printf(m, " %c", task_state_to_char(p));
|
||||
|
||||
SEQ_printf(m, " %15s %5d %9Ld.%06ld %c %9Ld.%06ld %c %9Ld.%06ld %9Ld.%06ld %9Ld %5d ",
|
||||
SEQ_printf(m, " %15s %5d %10ld %9Ld.%06ld %c %9Ld.%06ld %c %9Ld.%06ld %9Ld.%06ld %9Ld %5d ",
|
||||
p->comm, task_pid_nr(p),
|
||||
p->se.h_load.weight,
|
||||
SPLIT_NS(p->se.vruntime),
|
||||
entity_eligible(cfs_rq_of(&p->se), &p->se) ? 'E' : 'N',
|
||||
entity_eligible(&rq->cfs, &p->se) ? 'E' : 'N',
|
||||
SPLIT_NS(p->se.deadline),
|
||||
p->se.custom_slice ? 'S' : ' ',
|
||||
SPLIT_NS(p->se.slice),
|
||||
@@ -1007,7 +1008,7 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
|
||||
|
||||
SEQ_printf(m, "\n");
|
||||
SEQ_printf(m, "runnable tasks:\n");
|
||||
SEQ_printf(m, " S task PID vruntime eligible "
|
||||
SEQ_printf(m, " S task PID weight vruntime eligible "
|
||||
"deadline slice sum-exec switches "
|
||||
"prio wait-time sum-sleep sum-block"
|
||||
#ifdef CONFIG_NUMA_BALANCING
|
||||
@@ -1115,6 +1116,8 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
|
||||
cfs_rq->tg_load_avg_contrib);
|
||||
SEQ_printf(m, " .%-30s: %ld\n", "tg_load_avg",
|
||||
atomic_long_read(&cfs_rq->tg->load_avg));
|
||||
SEQ_printf(m, " .%-30s: %lu\n", "h_load",
|
||||
cfs_rq->h_load);
|
||||
#endif /* CONFIG_FAIR_GROUP_SCHED */
|
||||
#ifdef CONFIG_CFS_BANDWIDTH
|
||||
SEQ_printf(m, " .%-30s: %d\n", "throttled",
|
||||
|
||||
+350
-451
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -206,7 +206,7 @@ ___update_load_sum(u64 now, struct sched_avg *sa,
|
||||
/*
|
||||
* running is a subset of runnable (weight) so running can't be set if
|
||||
* runnable is clear. But there are some corner cases where the current
|
||||
* se has been already dequeued but cfs_rq->curr still points to it.
|
||||
* se has been already dequeued but cfs_rq->h_curr still points to it.
|
||||
* This means that weight will be 0 but not running for a sched_entity
|
||||
* but also for a cfs_rq if the latter becomes idle. As an example,
|
||||
* this happens during sched_balance_newidle() which calls
|
||||
@@ -307,7 +307,7 @@ int __update_load_avg_blocked_se(u64 now, struct sched_entity *se)
|
||||
int __update_load_avg_se(u64 now, struct cfs_rq *cfs_rq, struct sched_entity *se)
|
||||
{
|
||||
if (___update_load_sum(now, &se->avg, !!se->on_rq, se_runnable(se),
|
||||
cfs_rq->curr == se)) {
|
||||
cfs_rq->h_curr == se)) {
|
||||
|
||||
___update_load_avg(&se->avg, se_weight(se));
|
||||
cfs_se_util_change(&se->avg);
|
||||
@@ -323,7 +323,7 @@ int __update_load_avg_cfs_rq(u64 now, struct cfs_rq *cfs_rq)
|
||||
if (___update_load_sum(now, &cfs_rq->avg,
|
||||
scale_load_down(cfs_rq->load.weight),
|
||||
cfs_rq->h_nr_runnable,
|
||||
cfs_rq->curr != NULL)) {
|
||||
cfs_rq->h_curr != NULL)) {
|
||||
|
||||
___update_load_avg(&cfs_rq->avg, 1);
|
||||
trace_pelt_cfs_tp(cfs_rq);
|
||||
|
||||
+13
-13
@@ -530,21 +530,8 @@ struct task_group {
|
||||
|
||||
};
|
||||
|
||||
#ifdef CONFIG_GROUP_SCHED_WEIGHT
|
||||
#define ROOT_TASK_GROUP_LOAD NICE_0_LOAD
|
||||
|
||||
/*
|
||||
* A weight of 0 or 1 can cause arithmetics problems.
|
||||
* A weight of a cfs_rq is the sum of weights of which entities
|
||||
* are queued on this cfs_rq, so a weight of a entity should not be
|
||||
* too large, so as the shares value of a task group.
|
||||
* (The default weight is 1024 - so there's no practical
|
||||
* limitation from this.)
|
||||
*/
|
||||
#define MIN_SHARES (1UL << 1)
|
||||
#define MAX_SHARES (1UL << 18)
|
||||
#endif
|
||||
|
||||
typedef int (*tg_visitor)(struct task_group *, void *);
|
||||
|
||||
extern int walk_tg_tree_from(struct task_group *from,
|
||||
@@ -631,6 +618,17 @@ static inline bool cfs_task_bw_constrained(struct task_struct *p) { return false
|
||||
|
||||
#endif /* !CONFIG_CGROUP_SCHED */
|
||||
|
||||
/*
|
||||
* A weight of 0 or 1 can cause arithmetics problems.
|
||||
* A weight of a cfs_rq is the sum of weights of which entities
|
||||
* are queued on this cfs_rq, so a weight of a entity should not be
|
||||
* too large, so as the shares value of a task group.
|
||||
* (The default weight is 1024 - so there's no practical
|
||||
* limitation from this.)
|
||||
*/
|
||||
#define MIN_SHARES (1UL << 1)
|
||||
#define MAX_SHARES (1UL << 18)
|
||||
|
||||
extern void unregister_rt_sched_group(struct task_group *tg);
|
||||
extern void free_rt_sched_group(struct task_group *tg);
|
||||
extern int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent);
|
||||
@@ -709,6 +707,7 @@ struct cfs_rq {
|
||||
/*
|
||||
* CFS load tracking
|
||||
*/
|
||||
struct sched_entity *h_curr;
|
||||
struct sched_avg avg;
|
||||
#ifndef CONFIG_64BIT
|
||||
u64 last_update_time_copy;
|
||||
@@ -2575,6 +2574,7 @@ extern const u32 sched_prio_to_wmult[40];
|
||||
#define ENQUEUE_MIGRATED 0x00040000
|
||||
#define ENQUEUE_INITIAL 0x00080000
|
||||
#define ENQUEUE_RQ_SELECTED 0x00100000
|
||||
#define ENQUEUE_QUEUED 0x00200000
|
||||
|
||||
#define RETRY_TASK ((void *)-1UL)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user