Re: [PATCH v2 1/2] sched/numa: Drive NUMA task tick from execution context

From: Chen, Yu C

Date: Tue Sep 08 2026 - 01:41:03 EST


On 9/5/2026 9:58 PM, Hui Su wrote:
On Fri, Sep 4, 2026 at 1:15 PM, Tim Chen wrote:
Yes, you have a good point. The code I proposed just look at whether
we have consumed our allotment in the current slice.

What we should have looked at is whether the donor's total run time has
exceeded its quota when doing core scheduling. And we may happen to
hit __entity_slice_used() at the front of the slice after advancing
the deadline and __entity_slice_used()
returns false instead of true, even though I have consumed more than
my fair share when looking at longer time period across multiple slices.

The accumulated run time of the donor since it was picked for running
should be used for selection time baseline.

So maybe a patch like the following instead.


[ ... ]


In this example reweight_eevdf() did not change se->vruntime, so the
divergence does not depend on a vruntime coordinate adjustment. The
weight change alone is enough for the accumulated vused and the
current-weight vslice to no longer necessarily use the same scale.


Makes sense. In the current kernel with a flat cgroup(commit 85570f10a4c6
("sched/eevdf: Move to a single runqueue")), task_tick_fair()
tries to re-calculate the task's h_load.weight - if the cgroup changes
its share at runtime, the task se's h_load.weight changes accordingly.
Thus comparing the delta derived from the snapshot vruntime and the
slice using the latest weight is unreliable. (While before the flat cgroup
was introduced, a task's se->load.weight will not be re-evaluated during the tick, even if the cgroup changes its share at runtime.
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 8b3d47a325cc..c32d9931129f 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -590,6 +590,9 @@ struct sched_entity {
u64 sum_exec_runtime;
u64 prev_sum_exec_runtime;
u64 vruntime;
+#ifdef CONFIG_SCHED_CORE
+ u64 core_sched_start;
+#endif
/* Approximated virtual lag: */
s64 vlag;
/* 'Protected' deadline, to give out minimum quantums: */
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index f78275192036..22ae5dc57337 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4580,6 +4580,9 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p)
p->se.prev_sum_exec_runtime = 0;
p->se.nr_migrations = 0;
p->se.vruntime = 0;
+#ifdef CONFIG_SCHED_CORE
+ p->se.core_sched_start = 0;
+#endif
p->se.vlag = 0;
p->se.rel_deadline = 0;
INIT_LIST_HEAD(&p->se.group_node);
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 8dff37059faf..1bd05c906d3a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6502,6 +6502,9 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
}
se->prev_sum_exec_runtime = se->sum_exec_runtime;
+#ifdef CONFIG_SCHED_CORE
+ se->core_sched_start = se->exec_start;

if (entity_is_task(se)) ?

+#endif
}
static bool __dequeue_task(struct rq *rq, struct task_struct *p, int flags);
@@ -14748,10 +14751,9 @@ static void rq_offline_fair(struct rq *rq)
static inline bool
__entity_slice_used(struct sched_entity *se, int min_nr_tasks)
{
- u64 rtime = se->sum_exec_runtime - se->prev_sum_exec_runtime;
- u64 slice = se->slice;
+ u64 rtime = se->exec_start - se->core_sched_start;

- return (rtime * min_nr_tasks > slice);
+ return (rtime * min_nr_tasks > se->slice);
}
#define MIN_NR_TASKS_DURING_FORCEIDLE 2

The task-clock version has matched the existing predicate in the
non-proxy tests so far and fixes the proxy reproducer as well. I am
still validating reselection, migration, and the remaining proxy
boundary cases, so I have not posted either implementation.

Do you think keeping the check in the original real-time/task-clock
domain is a reasonable direction here, or would you prefer preserving
the vruntime approach by carrying the accumulated service across
reweights?


I would vote for the real-time comparison. What do you think, Tim?

thanks,
Chenyu