* [PATCH] sched/eevdf: Fix vprot across reweighting
@ 2026-10-03 11:46 Kayra Cizmeci
2026-10-11 7:13 ` Christian Loehle
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Kayra Cizmeci @ 2026-10-03 11:46 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, K Prateek Nayak
Cc: kayracizmeci, christian.loehle, elif.topuz, linux-kernel, sh,
Ingo Molnar
Currently in reweighting, while a tasks vruntime changes dead protection
could go alive, or alive protection could decrease, increase and go dead.
To fix this, implement rel_vprot similar to rel_deadline. Only
major difference is that rel_vprot is not dependent on
PLACE_REL_DEADLINE, because there are no mechanisms (unlike deadline)
that recalculate vprot. So it gets carried.
Fixes: 80390ead2080 ("sched/fair: Separate se->vlag from se->vprot")
Fixes: bcd74b2ffdd0 ("sched/fair: Only set slice protection at pick time")
Link: https://lore.kernel.org/all/20261001164609.244156-1-kayracizmeci@gmail.com/
Link: https://lore.kernel.org/all/e4700a93-ebd5-4c7e-88b5-d606437a13c0@arm.com/
Co-developed-by: Christian Loehle <christian.loehle@arm.com>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
Signed-off-by: Kayra Cizmeci <kayracizmeci@gmail.com>
---
Hi all,
Base is commit 4a3b51aab6e25244d97936aa65e6d5425adf98e1
on tip/sched/core.
NOTE: Christian, this version is really different from yours.
I still added the tags, hope that's not a problem.
If it is tho, please let me know.
I've thought a lot about this. I was at first thinking about
a simpler approach, but to be similar and consistent with the
current approaches to the similar problem on rel_deadline,
I thought this would be better.
I also ran some tests, from a VM that was inside a VM that
was working on MacOS on my Mac. (This is like a war crime...)
MY GREAT AND DEFINITELY 100% CORRECT ULTRAMEGA TEST
We first pin 2 tasks to the same CPU, (let's say TA and TB)
Then we change TA's nice value 3000 times between 0 and 10 (like, 0,10,0,10...)
We save weight and rem = (s64)(se->vprot - se->vruntime) on both
__dequeue_task() and enqueue_task_fair().
Then, we multiply weight and rem for both savings and
divide them. If they are between 0.95-1.05 we accept the
results as correct, if not well... Wrong.
I'm also terrible at math and a bit less terrible on coding
so these results should be 100% correct.
MY GREAT AND DEFINITELY 100% CORRECT ULTRAMEGA TEST RESULTS:
NRTP = NO_RUN_TO_PARITY
Live Protection Wrong Counts
+--------+-------------+--------------+
| | BASE | BASE + PATCH |
+--------+-------------+--------------+
| Normal | 6002/6002 | 0/6003 |
+--------+-------------+--------------+
| NRTP | 53/53 | 0/55 |
+--------+-------------+--------------+
On Base Normal, maximum amount of increase was 4.49x,
while the maximum amount of decrease was 0.17x and the average was
1.64x.
While on Base NRTP, maximum amount of increase was 2.27x,
maximum amount of decrease was 0.31x and the average was
1.08x.
Well that's all. You may or may not ask where are the revived ones are.
This test does not really covers that part.
Or as I like to say it, my computer ate that part.
That's really really all. Aside from the code :-).
include/linux/sched.h | 1 +
kernel/sched/core.c | 1 +
kernel/sched/fair.c | 34 ++++++++++++++++++++++++----------
3 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 7b91cae4a59c..bd9e2d119910 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -584,6 +584,7 @@ struct sched_entity {
unsigned char on_rq;
unsigned char sched_delayed;
unsigned char rel_deadline;
+ unsigned char rel_vprot;
unsigned char custom_slice;
/* hole */
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 71d3c948e14a..f1241f572cdc 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4638,6 +4638,7 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p)
p->se.vruntime = 0;
p->se.vlag = 0;
p->se.rel_deadline = 0;
+ p->se.rel_vprot = 0;
INIT_LIST_HEAD(&p->se.group_node);
/* A delayed task cannot be in clone(). */
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index b42a0ca2a69e..0bcd3a77aba4 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4614,7 +4614,7 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
}
static void
-rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
+rescale_entity(struct sched_entity *se, unsigned long weight)
{
long old_weight = se->h_load.weight;
@@ -4712,7 +4712,7 @@ rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
if (se->rel_deadline)
se->deadline = div64_long(se->deadline * old_weight, weight);
- if (rel_vprot)
+ if (se->rel_vprot)
se->vprot = div64_long(se->vprot * old_weight, weight);
}
@@ -4720,7 +4720,6 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
unsigned long weight, bool on_rq)
{
bool curr = cfs_rq->curr == se;
- bool rel_vprot = false;
u64 avruntime = 0;
if (se->h_load.weight == weight)
@@ -4733,7 +4732,7 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
se->rel_deadline = 1;
if (curr && protect_slice(se)) {
se->vprot -= avruntime;
- rel_vprot = true;
+ se->rel_vprot = 1;
}
cfs_rq->h_nr_queued--;
@@ -4741,17 +4740,23 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
__dequeue_entity(cfs_rq, se);
}
- rescale_entity(se, weight, rel_vprot);
+ rescale_entity(se, weight);
update_load_set(&se->h_load, weight);
if (on_rq) {
- if (rel_vprot)
- se->vprot += avruntime;
se->deadline += avruntime;
se->rel_deadline = 0;
se->vruntime = avruntime - se->vlag;
+ if (se->rel_vprot) {
+ se->vprot += avruntime;
+ se->rel_vprot = 0;
+ } else if (curr) {
+ /* Reweighting must not revive expired slice protection. */
+ cancel_protect_slice(se);
+ }
+
if (!curr)
__enqueue_entity(cfs_rq, se);
cfs_rq->h_nr_queued++;
@@ -6297,6 +6302,11 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
se->vruntime = vruntime - lag;
+ if (se->rel_vprot) {
+ se->vprot += se->vruntime;
+ se->rel_vprot = 0;
+ }
+
if (update_zero)
update_zero_vruntime(cfs_rq, -lag);
@@ -8143,9 +8153,13 @@ static bool __dequeue_task(struct rq *rq, struct task_struct *p, int flags)
dequeue_hierarchy(p, flags);
- if (sched_feat(PLACE_REL_DEADLINE) && !task_sleep) {
- se->deadline -= se->vruntime;
- se->rel_deadline = 1;
+ if (!task_sleep) {
+ se->vprot = protect_slice(se) ? se->vprot - se->vruntime : 0;
+ se->rel_vprot = 1;
+ if (sched_feat(PLACE_REL_DEADLINE)) {
+ se->deadline -= se->vruntime;
+ se->rel_deadline = 1;
+ }
}
if (se != cfs_rq->curr)
__dequeue_entity(cfs_rq, se);
--
2.53.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] sched/eevdf: Fix vprot across reweighting
2026-10-03 11:46 [PATCH] sched/eevdf: Fix vprot across reweighting Kayra Cizmeci
@ 2026-10-11 7:13 ` Christian Loehle
2026-10-11 10:06 ` Kayra Cizmeci
2026-10-12 4:39 ` K Prateek Nayak
2026-10-12 13:40 ` Vincent Guittot
2 siblings, 1 reply; 9+ messages in thread
From: Christian Loehle @ 2026-10-11 7:13 UTC (permalink / raw)
To: Kayra Cizmeci, Peter Zijlstra, Ingo Molnar, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, K Prateek Nayak
Cc: elif.topuz, linux-kernel, sh, Ingo Molnar
On 10/3/26 12:46, Kayra Cizmeci wrote:
> Currently in reweighting, while a tasks vruntime changes dead protection
> could go alive, or alive protection could decrease, increase and go dead.
>
> To fix this, implement rel_vprot similar to rel_deadline. Only
Ah nice find, please allow me to look at this code for a bit if that's
the best way to implement this, will review then, for now
Tested-by: Christian Loehle <christian.loehle@arm.com>
> major difference is that rel_vprot is not dependent on
> PLACE_REL_DEADLINE, because there are no mechanisms (unlike deadline)
> that recalculate vprot. So it gets carried.
>
> Fixes: 80390ead2080 ("sched/fair: Separate se->vlag from se->vprot")
> Fixes: bcd74b2ffdd0 ("sched/fair: Only set slice protection at pick time")
> Link: https://lore.kernel.org/all/20261001164609.244156-1-kayracizmeci@gmail.com/
> Link: https://lore.kernel.org/all/e4700a93-ebd5-4c7e-88b5-d606437a13c0@arm.com/
> Co-developed-by: Christian Loehle <christian.loehle@arm.com>
> Signed-off-by: Christian Loehle <christian.loehle@arm.com>
FWIW my SOB shouldn't be there anymore.
> Signed-off-by: Kayra Cizmeci <kayracizmeci@gmail.com>
> ---
> Hi all,
>
> Base is commit 4a3b51aab6e25244d97936aa65e6d5425adf98e1
> on tip/sched/core.
>
> NOTE: Christian, this version is really different from yours.
> I still added the tags, hope that's not a problem.
> If it is tho, please let me know.
>
> I've thought a lot about this. I was at first thinking about
> a simpler approach, but to be similar and consistent with the
> current approaches to the similar problem on rel_deadline,
> I thought this would be better.
>
>
> I also ran some tests, from a VM that was inside a VM that
> was working on MacOS on my Mac. (This is like a war crime...)
>
>
> MY GREAT AND DEFINITELY 100% CORRECT ULTRAMEGA TEST
>
> We first pin 2 tasks to the same CPU, (let's say TA and TB)
> Then we change TA's nice value 3000 times between 0 and 10 (like, 0,10,0,10...)
> We save weight and rem = (s64)(se->vprot - se->vruntime) on both
> __dequeue_task() and enqueue_task_fair().
>
> Then, we multiply weight and rem for both savings and
> divide them. If they are between 0.95-1.05 we accept the
> results as correct, if not well... Wrong.
>
> I'm also terrible at math and a bit less terrible on coding
> so these results should be 100% correct.
>
> MY GREAT AND DEFINITELY 100% CORRECT ULTRAMEGA TEST RESULTS:
>
> NRTP = NO_RUN_TO_PARITY
>
> Live Protection Wrong Counts
> +--------+-------------+--------------+
> | | BASE | BASE + PATCH |
> +--------+-------------+--------------+
> | Normal | 6002/6002 | 0/6003 |
> +--------+-------------+--------------+
> | NRTP | 53/53 | 0/55 |
> +--------+-------------+--------------+
>
> On Base Normal, maximum amount of increase was 4.49x,
> while the maximum amount of decrease was 0.17x and the average was
> 1.64x.
>
> While on Base NRTP, maximum amount of increase was 2.27x,
> maximum amount of decrease was 0.31x and the average was
> 1.08x.
>
> Well that's all. You may or may not ask where are the revived ones are.
> This test does not really covers that part.
>
> Or as I like to say it, my computer ate that part.
>
> That's really really all. Aside from the code :-).
>
>
> include/linux/sched.h | 1 +
> kernel/sched/core.c | 1 +
> kernel/sched/fair.c | 34 ++++++++++++++++++++++++----------
> 3 files changed, 26 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index 7b91cae4a59c..bd9e2d119910 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -584,6 +584,7 @@ struct sched_entity {
> unsigned char on_rq;
> unsigned char sched_delayed;
> unsigned char rel_deadline;
> + unsigned char rel_vprot;
> unsigned char custom_slice;
> /* hole */
>
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 71d3c948e14a..f1241f572cdc 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -4638,6 +4638,7 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p)
> p->se.vruntime = 0;
> p->se.vlag = 0;
> p->se.rel_deadline = 0;
> + p->se.rel_vprot = 0;
> INIT_LIST_HEAD(&p->se.group_node);
>
> /* A delayed task cannot be in clone(). */
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index b42a0ca2a69e..0bcd3a77aba4 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -4614,7 +4614,7 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
> }
>
> static void
> -rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
> +rescale_entity(struct sched_entity *se, unsigned long weight)
> {
> long old_weight = se->h_load.weight;
>
> @@ -4712,7 +4712,7 @@ rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
> if (se->rel_deadline)
> se->deadline = div64_long(se->deadline * old_weight, weight);
>
> - if (rel_vprot)
> + if (se->rel_vprot)
> se->vprot = div64_long(se->vprot * old_weight, weight);
> }
>
> @@ -4720,7 +4720,6 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
> unsigned long weight, bool on_rq)
> {
> bool curr = cfs_rq->curr == se;
> - bool rel_vprot = false;
> u64 avruntime = 0;
>
> if (se->h_load.weight == weight)
> @@ -4733,7 +4732,7 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
> se->rel_deadline = 1;
> if (curr && protect_slice(se)) {
> se->vprot -= avruntime;
> - rel_vprot = true;
> + se->rel_vprot = 1;
> }
>
> cfs_rq->h_nr_queued--;
> @@ -4741,17 +4740,23 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
> __dequeue_entity(cfs_rq, se);
> }
>
> - rescale_entity(se, weight, rel_vprot);
> + rescale_entity(se, weight);
>
> update_load_set(&se->h_load, weight);
>
> if (on_rq) {
> - if (rel_vprot)
> - se->vprot += avruntime;
> se->deadline += avruntime;
> se->rel_deadline = 0;
> se->vruntime = avruntime - se->vlag;
>
> + if (se->rel_vprot) {
> + se->vprot += avruntime;
> + se->rel_vprot = 0;
> + } else if (curr) {
> + /* Reweighting must not revive expired slice protection. */
> + cancel_protect_slice(se);
> + }
> +
> if (!curr)
> __enqueue_entity(cfs_rq, se);
> cfs_rq->h_nr_queued++;
> @@ -6297,6 +6302,11 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
>
> se->vruntime = vruntime - lag;
>
> + if (se->rel_vprot) {
> + se->vprot += se->vruntime;
> + se->rel_vprot = 0;
> + }
> +
> if (update_zero)
> update_zero_vruntime(cfs_rq, -lag);
>
> @@ -8143,9 +8153,13 @@ static bool __dequeue_task(struct rq *rq, struct task_struct *p, int flags)
>
> dequeue_hierarchy(p, flags);
>
> - if (sched_feat(PLACE_REL_DEADLINE) && !task_sleep) {
> - se->deadline -= se->vruntime;
> - se->rel_deadline = 1;
> + if (!task_sleep) {
> + se->vprot = protect_slice(se) ? se->vprot - se->vruntime : 0;
> + se->rel_vprot = 1;
> + if (sched_feat(PLACE_REL_DEADLINE)) {
> + se->deadline -= se->vruntime;
> + se->rel_deadline = 1;
> + }
> }
> if (se != cfs_rq->curr)
> __dequeue_entity(cfs_rq, se);
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] sched/eevdf: Fix vprot across reweighting
2026-10-11 7:13 ` Christian Loehle
@ 2026-10-11 10:06 ` Kayra Cizmeci
0 siblings, 0 replies; 9+ messages in thread
From: Kayra Cizmeci @ 2026-10-11 10:06 UTC (permalink / raw)
To: christian.loehle
Cc: bsegall, dietmar.eggemann, elif.topuz, juri.lelli, kayracizmeci,
kprateek.nayak, linux-kernel, mgorman, mingo, mingo, peterz,
rostedt, sh, vincent.guittot, vschneid
Hi Christian,
> > Currently in reweighting, while a tasks vruntime changes dead protection
> > could go alive, or alive protection could decrease, increase and go dead.
> >
> > To fix this, implement rel_vprot similar to rel_deadline. Only
> Ah nice find, please allow me to look at this code for a bit if that's
> the best way to implement this, will review then, for now
> Tested-by: Christian Loehle <christian.loehle@arm.com>
Thanks for testing! And yeah, take your time.
> > major difference is that rel_vprot is not dependent on
> > PLACE_REL_DEADLINE, because there are no mechanisms (unlike deadline)
> > that recalculate vprot. So it gets carried.
> >
> > Fixes: 80390ead2080 ("sched/fair: Separate se->vlag from se->vprot")
> > Fixes: bcd74b2ffdd0 ("sched/fair: Only set slice protection at pick time")
> > Link: https://lore.kernel.org/all/20261001164609.244156-1-kayracizmeci@gmail.com/
> > Link: https://lore.kernel.org/all/e4700a93-ebd5-4c7e-88b5-d606437a13c0@arm.com/
> > Co-developed-by: Christian Loehle <christian.loehle@arm.com>
> > Signed-off-by: Christian Loehle <christian.loehle@arm.com>
> FWIW my SOB shouldn't be there anymore.
Right. I'll remove it on v2 aside with Co-developed-by.
Thanks!
Kayra
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] sched/eevdf: Fix vprot across reweighting
2026-10-03 11:46 [PATCH] sched/eevdf: Fix vprot across reweighting Kayra Cizmeci
2026-10-11 7:13 ` Christian Loehle
@ 2026-10-12 4:39 ` K Prateek Nayak
2026-10-12 13:40 ` Vincent Guittot
2 siblings, 0 replies; 9+ messages in thread
From: K Prateek Nayak @ 2026-10-12 4:39 UTC (permalink / raw)
To: Kayra Cizmeci, Peter Zijlstra, Ingo Molnar, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider
Cc: christian.loehle, elif.topuz, linux-kernel, sh, Ingo Molnar
Hello Kayra,
On 10/3/2026 5:16 PM, Kayra Cizmeci wrote:
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index 7b91cae4a59c..bd9e2d119910 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -584,6 +584,7 @@ struct sched_entity {
> unsigned char on_rq;
> unsigned char sched_delayed;
> unsigned char rel_deadline;
> + unsigned char rel_vprot;
> unsigned char custom_slice;
> /* hole */
>
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 71d3c948e14a..f1241f572cdc 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -4638,6 +4638,7 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p)
> p->se.vruntime = 0;
> p->se.vlag = 0;
> p->se.rel_deadline = 0;
> + p->se.rel_vprot = 0;
> INIT_LIST_HEAD(&p->se.group_node);
>
> /* A delayed task cannot be in clone(). */
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index b42a0ca2a69e..0bcd3a77aba4 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -4614,7 +4614,7 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
> }
>
> static void
> -rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
> +rescale_entity(struct sched_entity *se, unsigned long weight)
> {
> long old_weight = se->h_load.weight;
>
> @@ -4712,7 +4712,7 @@ rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
> if (se->rel_deadline)
> se->deadline = div64_long(se->deadline * old_weight, weight);
>
> - if (rel_vprot)
> + if (se->rel_vprot)
> se->vprot = div64_long(se->vprot * old_weight, weight);
> }
>
> @@ -4720,7 +4720,6 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
> unsigned long weight, bool on_rq)
> {
> bool curr = cfs_rq->curr == se;
> - bool rel_vprot = false;
> u64 avruntime = 0;
>
> if (se->h_load.weight == weight)
> @@ -4733,7 +4732,7 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
> se->rel_deadline = 1;
> if (curr && protect_slice(se)) {
> se->vprot -= avruntime;
> - rel_vprot = true;
> + se->rel_vprot = 1;
> }
>
> cfs_rq->h_nr_queued--;
> @@ -4741,17 +4740,23 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
> __dequeue_entity(cfs_rq, se);
> }
>
> - rescale_entity(se, weight, rel_vprot);
> + rescale_entity(se, weight);
>
> update_load_set(&se->h_load, weight);
>
> if (on_rq) {
> - if (rel_vprot)
> - se->vprot += avruntime;
> se->deadline += avruntime;
> se->rel_deadline = 0;
> se->vruntime = avruntime - se->vlag;
>
> + if (se->rel_vprot) {
> + se->vprot += avruntime;
> + se->rel_vprot = 0;
> + } else if (curr) {
> + /* Reweighting must not revive expired slice protection. */
> + cancel_protect_slice(se);
This is the only genuine fix I see in this entire patch where
vruntime adjustment will make the tasks protected and we
probably need to cancel it in that case but i don't get why
we need a new se->rel_vprot for that ...
> + }
> +
> if (!curr)
> __enqueue_entity(cfs_rq, se);
> cfs_rq->h_nr_queued++;
> @@ -6297,6 +6302,11 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
>
> se->vruntime = vruntime - lag;
>
> + if (se->rel_vprot) {
> + se->vprot += se->vruntime;
> + se->rel_vprot = 0;
> + }
> +
> if (update_zero)
> update_zero_vruntime(cfs_rq, -lag);
>
> @@ -8143,9 +8153,13 @@ static bool __dequeue_task(struct rq *rq, struct task_struct *p, int flags)
>
> dequeue_hierarchy(p, flags);
>
> - if (sched_feat(PLACE_REL_DEADLINE) && !task_sleep) {
> - se->deadline -= se->vruntime;
> - se->rel_deadline = 1;
> + if (!task_sleep) {
> + se->vprot = protect_slice(se) ? se->vprot - se->vruntime : 0;
> + se->rel_vprot = 1;
I'm having a super hard time understanding why we need this.
Protect slice is only required for current entities so why do we
care about it during migration? The set_next_task() during next
selection will override it anyway.
What am I missing?
> + if (sched_feat(PLACE_REL_DEADLINE)) {
> + se->deadline -= se->vruntime;
> + se->rel_deadline = 1;
> + }
> }
> if (se != cfs_rq->curr)
> __dequeue_entity(cfs_rq, se);
--
Thanks and Regards,
Prateek
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] sched/eevdf: Fix vprot across reweighting
2026-10-03 11:46 [PATCH] sched/eevdf: Fix vprot across reweighting Kayra Cizmeci
2026-10-11 7:13 ` Christian Loehle
2026-10-12 4:39 ` K Prateek Nayak
@ 2026-10-12 13:40 ` Vincent Guittot
2026-10-12 13:59 ` Kayra Cizmeci
2 siblings, 1 reply; 9+ messages in thread
From: Vincent Guittot @ 2026-10-12 13:40 UTC (permalink / raw)
To: Kayra Cizmeci
Cc: Peter Zijlstra, Ingo Molnar, Juri Lelli, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, christian.loehle, elif.topuz, linux-kernel, sh,
Ingo Molnar
On Sat, 3 Oct 2026 at 13:47, Kayra Cizmeci <kayracizmeci@gmail.com> wrote:
>
> Currently in reweighting, while a tasks vruntime changes dead protection
> could go alive, or alive protection could decrease, increase and go dead.
>
> To fix this, implement rel_vprot similar to rel_deadline. Only
> major difference is that rel_vprot is not dependent on
> PLACE_REL_DEADLINE, because there are no mechanisms (unlike deadline)
> that recalculate vprot. So it gets carried.
>
> Fixes: 80390ead2080 ("sched/fair: Separate se->vlag from se->vprot")
> Fixes: bcd74b2ffdd0 ("sched/fair: Only set slice protection at pick time")
> Link: https://lore.kernel.org/all/20261001164609.244156-1-kayracizmeci@gmail.com/
> Link: https://lore.kernel.org/all/e4700a93-ebd5-4c7e-88b5-d606437a13c0@arm.com/
> Co-developed-by: Christian Loehle <christian.loehle@arm.com>
> Signed-off-by: Christian Loehle <christian.loehle@arm.com>
> Signed-off-by: Kayra Cizmeci <kayracizmeci@gmail.com>
> ---
> Hi all,
>
> Base is commit 4a3b51aab6e25244d97936aa65e6d5425adf98e1
> on tip/sched/core.
>
> NOTE: Christian, this version is really different from yours.
> I still added the tags, hope that's not a problem.
> If it is tho, please let me know.
>
> I've thought a lot about this. I was at first thinking about
> a simpler approach, but to be similar and consistent with the
> current approaches to the similar problem on rel_deadline,
> I thought this would be better.
>
>
> I also ran some tests, from a VM that was inside a VM that
> was working on MacOS on my Mac. (This is like a war crime...)
>
>
> MY GREAT AND DEFINITELY 100% CORRECT ULTRAMEGA TEST
>
> We first pin 2 tasks to the same CPU, (let's say TA and TB)
> Then we change TA's nice value 3000 times between 0 and 10 (like, 0,10,0,10...)
> We save weight and rem = (s64)(se->vprot - se->vruntime) on both
> __dequeue_task() and enqueue_task_fair().
>
> Then, we multiply weight and rem for both savings and
> divide them. If they are between 0.95-1.05 we accept the
> results as correct, if not well... Wrong.
>
> I'm also terrible at math and a bit less terrible on coding
> so these results should be 100% correct.
>
> MY GREAT AND DEFINITELY 100% CORRECT ULTRAMEGA TEST RESULTS:
>
> NRTP = NO_RUN_TO_PARITY
>
> Live Protection Wrong Counts
> +--------+-------------+--------------+
> | | BASE | BASE + PATCH |
> +--------+-------------+--------------+
> | Normal | 6002/6002 | 0/6003 |
> +--------+-------------+--------------+
> | NRTP | 53/53 | 0/55 |
> +--------+-------------+--------------+
>
> On Base Normal, maximum amount of increase was 4.49x,
> while the maximum amount of decrease was 0.17x and the average was
> 1.64x.
>
> While on Base NRTP, maximum amount of increase was 2.27x,
> maximum amount of decrease was 0.31x and the average was
> 1.08x.
>
> Well that's all. You may or may not ask where are the revived ones are.
> This test does not really covers that part.
>
> Or as I like to say it, my computer ate that part.
>
> That's really really all. Aside from the code :-).
>
>
> include/linux/sched.h | 1 +
> kernel/sched/core.c | 1 +
> kernel/sched/fair.c | 34 ++++++++++++++++++++++++----------
> 3 files changed, 26 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index 7b91cae4a59c..bd9e2d119910 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -584,6 +584,7 @@ struct sched_entity {
> unsigned char on_rq;
> unsigned char sched_delayed;
> unsigned char rel_deadline;
> + unsigned char rel_vprot;
> unsigned char custom_slice;
> /* hole */
>
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 71d3c948e14a..f1241f572cdc 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -4638,6 +4638,7 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p)
> p->se.vruntime = 0;
> p->se.vlag = 0;
> p->se.rel_deadline = 0;
> + p->se.rel_vprot = 0;
> INIT_LIST_HEAD(&p->se.group_node);
>
> /* A delayed task cannot be in clone(). */
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index b42a0ca2a69e..0bcd3a77aba4 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -4614,7 +4614,7 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
> }
>
> static void
> -rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
> +rescale_entity(struct sched_entity *se, unsigned long weight)
> {
> long old_weight = se->h_load.weight;
>
> @@ -4712,7 +4712,7 @@ rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
> if (se->rel_deadline)
> se->deadline = div64_long(se->deadline * old_weight, weight);
>
> - if (rel_vprot)
> + if (se->rel_vprot)
> se->vprot = div64_long(se->vprot * old_weight, weight);
> }
>
> @@ -4720,7 +4720,6 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
> unsigned long weight, bool on_rq)
> {
> bool curr = cfs_rq->curr == se;
> - bool rel_vprot = false;
> u64 avruntime = 0;
>
> if (se->h_load.weight == weight)
> @@ -4733,7 +4732,7 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
> se->rel_deadline = 1;
> if (curr && protect_slice(se)) {
> se->vprot -= avruntime;
> - rel_vprot = true;
> + se->rel_vprot = 1;
> }
>
> cfs_rq->h_nr_queued--;
> @@ -4741,17 +4740,23 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
> __dequeue_entity(cfs_rq, se);
> }
>
> - rescale_entity(se, weight, rel_vprot);
> + rescale_entity(se, weight);
>
> update_load_set(&se->h_load, weight);
>
> if (on_rq) {
> - if (rel_vprot)
> - se->vprot += avruntime;
> se->deadline += avruntime;
> se->rel_deadline = 0;
> se->vruntime = avruntime - se->vlag;
>
> + if (se->rel_vprot) {
> + se->vprot += avruntime;
> + se->rel_vprot = 0;
> + } else if (curr) {
> + /* Reweighting must not revive expired slice protection. */
> + cancel_protect_slice(se);
> + }
> +
I don't get why you need to a se->rel_vprot and all these changes . If
we want to ensure that protection will not be re enabled because of
rescale, we just need the below
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 5c98d8dfce5d..e83836fe44ef 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4951,12 +4951,15 @@ static void reweight_eevdf(struct cfs_rq
*cfs_rq, struct sched_entity *se,
update_load_set(&se->h_load, weight);
if (on_rq) {
- if (rel_vprot)
- se->vprot += avruntime;
se->deadline += avruntime;
se->rel_deadline = 0;
se->vruntime = avruntime - se->vlag;
+ if (rel_vprot)
+ se->vprot += avruntime;
+ else if (curr)
+ se->vprot = se->vruntime;
+
if (!curr)
__enqueue_entity(cfs_rq, se);
cfs_rq->h_nr_queued++;
or the below which is even simpler because vprot, vlag and deadline
are rescaled with the same ratio but it implies useless div64_long()
when the protection is already canceled
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 5c98d8dfce5d..5d1b16780b52 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4936,7 +4936,7 @@ static void reweight_eevdf(struct cfs_rq
*cfs_rq, struct sched_entity *se,
se->vlag = entity_lag(cfs_rq, se, avruntime);
se->deadline -= avruntime;
se->rel_deadline = 1;
- if (curr && protect_slice(se)) {
+ if (curr) {
se->vprot -= avruntime;
rel_vprot = true;
}
> if (!curr)
> __enqueue_entity(cfs_rq, se);
> cfs_rq->h_nr_queued++;
> @@ -6297,6 +6302,11 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
>
> se->vruntime = vruntime - lag;
>
> + if (se->rel_vprot) {
> + se->vprot += se->vruntime;
> + se->rel_vprot = 0;
> + }
> +
> if (update_zero)
> update_zero_vruntime(cfs_rq, -lag);
>
> @@ -8143,9 +8153,13 @@ static bool __dequeue_task(struct rq *rq, struct task_struct *p, int flags)
>
> dequeue_hierarchy(p, flags);
>
> - if (sched_feat(PLACE_REL_DEADLINE) && !task_sleep) {
> - se->deadline -= se->vruntime;
> - se->rel_deadline = 1;
> + if (!task_sleep) {
> + se->vprot = protect_slice(se) ? se->vprot - se->vruntime : 0;
> + se->rel_vprot = 1;
> + if (sched_feat(PLACE_REL_DEADLINE)) {
> + se->deadline -= se->vruntime;
> + se->rel_deadline = 1;
> + }
> }
> if (se != cfs_rq->curr)
> __dequeue_entity(cfs_rq, se);
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] sched/eevdf: Fix vprot across reweighting
2026-10-12 13:40 ` Vincent Guittot
@ 2026-10-12 13:59 ` Kayra Cizmeci
2026-10-12 14:14 ` Vincent Guittot
0 siblings, 1 reply; 9+ messages in thread
From: Kayra Cizmeci @ 2026-10-12 13:59 UTC (permalink / raw)
To: vincent.guittot
Cc: bsegall, christian.loehle, dietmar.eggemann, elif.topuz,
juri.lelli, kayracizmeci, kprateek.nayak, linux-kernel, mgorman,
mingo, mingo, peterz, rostedt, sh, vschneid
> I don't get why you need to a se->rel_vprot and all these changes . If
> we want to ensure that protection will not be re enabled because of
> rescale, we just need the below
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 5c98d8dfce5d..e83836fe44ef 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -4951,12 +4951,15 @@ static void reweight_eevdf(struct cfs_rq
> *cfs_rq, struct sched_entity *se,
> update_load_set(&se->h_load, weight);
>
> if (on_rq) {
> - if (rel_vprot)
> - se->vprot += avruntime;
> se->deadline += avruntime;
> se->rel_deadline = 0;
> se->vruntime = avruntime - se->vlag;
>
> + if (rel_vprot)
> + se->vprot += avruntime;
> + else if (curr)
> + se->vprot = se->vruntime;
> +
> if (!curr)
> __enqueue_entity(cfs_rq, se);
> cfs_rq->h_nr_queued++;
> or the below which is even simpler because vprot, vlag and deadline
> are rescaled with the same ratio but it implies useless div64_long()
> when the protection is already canceled
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 5c98d8dfce5d..5d1b16780b52 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -4936,7 +4936,7 @@ static void reweight_eevdf(struct cfs_rq
> *cfs_rq, struct sched_entity *se,
> se->vlag = entity_lag(cfs_rq, se, avruntime);
> se->deadline -= avruntime;
> se->rel_deadline = 1;
> - if (curr && protect_slice(se)) {
> + if (curr) {
> se->vprot -= avruntime;
> rel_vprot = true;
> }
Here:
https://lore.kernel.org/all/20261001164609.244156-1-kayracizmeci@gmail.com/
https://lore.kernel.org/all/e4700a93-ebd5-4c7e-88b5-d606437a13c0@arm.com/
Because on_rq can get false. And alive protection complicates things.
And this diff alone wouldn't work.
IDK what else we could do to fix this both cases cleanly tbh.
But there could be a cleaner way.
Thanks,
Kayra
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] sched/eevdf: Fix vprot across reweighting
2026-10-12 13:59 ` Kayra Cizmeci
@ 2026-10-12 14:14 ` Vincent Guittot
2026-10-12 15:01 ` Kayra Cizmeci
0 siblings, 1 reply; 9+ messages in thread
From: Vincent Guittot @ 2026-10-12 14:14 UTC (permalink / raw)
To: Kayra Cizmeci
Cc: bsegall, christian.loehle, dietmar.eggemann, elif.topuz,
juri.lelli, kprateek.nayak, linux-kernel, mgorman, mingo, mingo,
peterz, rostedt, sh, vschneid
On Mon, 12 Oct 2026 at 15:59, Kayra Cizmeci <kayracizmeci@gmail.com> wrote:
>
> > I don't get why you need to a se->rel_vprot and all these changes . If
> > we want to ensure that protection will not be re enabled because of
> > rescale, we just need the below
>
> > diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> > index 5c98d8dfce5d..e83836fe44ef 100644
> > --- a/kernel/sched/fair.c
> > +++ b/kernel/sched/fair.c
> > @@ -4951,12 +4951,15 @@ static void reweight_eevdf(struct cfs_rq
> > *cfs_rq, struct sched_entity *se,
> > update_load_set(&se->h_load, weight);
> >
> > if (on_rq) {
> > - if (rel_vprot)
> > - se->vprot += avruntime;
> > se->deadline += avruntime;
> > se->rel_deadline = 0;
> > se->vruntime = avruntime - se->vlag;
> >
> > + if (rel_vprot)
> > + se->vprot += avruntime;
> > + else if (curr)
> > + se->vprot = se->vruntime;
> > +
> > if (!curr)
> > __enqueue_entity(cfs_rq, se);
> > cfs_rq->h_nr_queued++;
>
> > or the below which is even simpler because vprot, vlag and deadline
> > are rescaled with the same ratio but it implies useless div64_long()
> > when the protection is already canceled
>
> > diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> > index 5c98d8dfce5d..5d1b16780b52 100644
> > --- a/kernel/sched/fair.c
> > +++ b/kernel/sched/fair.c
> > @@ -4936,7 +4936,7 @@ static void reweight_eevdf(struct cfs_rq
> > *cfs_rq, struct sched_entity *se,
> > se->vlag = entity_lag(cfs_rq, se, avruntime);
> > se->deadline -= avruntime;
> > se->rel_deadline = 1;
> > - if (curr && protect_slice(se)) {
> > + if (curr) {
> > se->vprot -= avruntime;
> > rel_vprot = true;
> > }
>
> Here:
>
> https://lore.kernel.org/all/20261001164609.244156-1-kayracizmeci@gmail.com/
> https://lore.kernel.org/all/e4700a93-ebd5-4c7e-88b5-d606437a13c0@arm.com/
>
> Because on_rq can get false. And alive protection complicates things.
> And this diff alone wouldn't work.
>
> IDK what else we could do to fix this both cases cleanly tbh.
> But there could be a cleaner way.
Before 819224e506bc ("sched/fair: Remove dead code on
enqueue_task_fair()"), the reweight_eevdf() was not called for curr so
the false was always true. If we can finally have enqueue curr then we
should skip this case
>
> Thanks,
>
> Kayra
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] sched/eevdf: Fix vprot across reweighting
2026-10-12 14:14 ` Vincent Guittot
@ 2026-10-12 15:01 ` Kayra Cizmeci
2026-10-12 19:00 ` Kayra Cizmeci
0 siblings, 1 reply; 9+ messages in thread
From: Kayra Cizmeci @ 2026-10-12 15:01 UTC (permalink / raw)
To: vincent.guittot
Cc: bsegall, christian.loehle, dietmar.eggemann, elif.topuz,
juri.lelli, kayracizmeci, kprateek.nayak, linux-kernel, mgorman,
mingo, mingo, peterz, rostedt, sh, vschneid
I send one mail, one more to reply comes. Ah.. I love it tho :-)
> Before 819224e506bc ("sched/fair: Remove dead code on
> enqueue_task_fair()"), the reweight_eevdf() was not called for curr so
> the false was always true. If we can finally have enqueue curr then we
> should skip this case
Yeah. The beast I created kills me. Pretty nice.
On sched_change_begin(), cfs_rq->curr is set to NULL. So while entering enqueue_task_fair(), curr is false.
on_rq is false too. But the tasks weight is changed and vprot never gets touched so it got wrong. Then on set_next_task_fair(),
the task is curr again.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] sched/eevdf: Fix vprot across reweighting
2026-10-12 15:01 ` Kayra Cizmeci
@ 2026-10-12 19:00 ` Kayra Cizmeci
0 siblings, 0 replies; 9+ messages in thread
From: Kayra Cizmeci @ 2026-10-12 19:00 UTC (permalink / raw)
To: kayracizmeci, Ingo Molnar, Peter Zijlstra, Juri Lelli,
Vincent Guittot, Dietmar Eggemann, Steven Rostedt, Ben Segall,
Mel Gorman, Valentin Schneider, K Prateek Nayak
Cc: christian.loehle, elif.topuz, linux-kernel, mingo, sh
> I send one mail, one more to reply comes. Ah.. I love it tho :-)
> > Before 819224e506bc ("sched/fair: Remove dead code on
> > enqueue_task_fair()"), the reweight_eevdf() was not called for curr so
> > the false was always true. If we can finally have enqueue curr then we
> > should skip this case
> Yeah. The beast I created kills me. Pretty nice.
> On sched_change_begin(), cfs_rq->curr is set to NULL. So while entering enqueue_task_fair(), curr is false.
> on_rq is false too. But the tasks weight is changed and vprot never gets touched so it got wrong. Then on set_next_task_fair(),
> the task is curr again.
Would something like this works?
This diff was coded in the middle of the night, so there might be some little issues about it.
Not even 1% tested. But it should 100% work since I'm too smart, right? Right? :-)
(Also, I'll test it tomorrow. Normally I was going to test this, but I lost my test script. And tbh
I'm too tired to make it right now. I mean normally I wouldn't test it, since I'm too smart and this
is 100% correct. And because of this 'dead' code removal patch, there could be some extra handy issues.
Ah... I wanna swear so bad. But, I'll be a good and kind. Goodnight, good morning, good afternoon and good-whatever.)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index b42a0ca2a69e..1bea7b7e9cb3 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4731,7 +4731,7 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
se->vlag = entity_lag(cfs_rq, se, avruntime);
se->deadline -= avruntime;
se->rel_deadline = 1;
- if (curr && protect_slice(se)) {
+ if (curr) {
se->vprot -= avruntime;
rel_vprot = true;
}
@@ -7990,7 +7990,9 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
int task_new = !(flags & ENQUEUE_WAKEUP);
struct sched_entity *se = &p->se;
struct cfs_rq *cfs_rq = &rq->cfs;
- unsigned long weight;
+ unsigned long weight, old_weight;
+ bool live;
+ u64 dist;
if (task_is_throttled(p) && enqueue_throttled_task(p))
return;
@@ -8024,8 +8026,23 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
requeue_delayed_entity(cfs_rq, se);
weight = enqueue_hierarchy(p, flags);
+ live = protect_slice(se);
+
+ if (live) {
+ old_weight = se->h_load.weight;
+ dist = se->vprot - se->vruntime;
+ }
reweight_eevdf(cfs_rq, se, weight, false);
place_entity(cfs_rq, se, flags | ENQUEUE_QUEUED);
+ if (!live)
+ cancel_protect_slice(se);
+ else {
+ if (weight != old_weight)
+ dist = div64_long(dist * old_weight, weight);
+
+ se->vprot = se->vruntime + dist;
+ }
+
__enqueue_entity(cfs_rq, se);
if (!rq_h_nr_queued && rq->cfs.h_nr_queued)
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-10-12 19:00 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-03 11:46 [PATCH] sched/eevdf: Fix vprot across reweighting Kayra Cizmeci
2026-10-11 7:13 ` Christian Loehle
2026-10-11 10:06 ` Kayra Cizmeci
2026-10-12 4:39 ` K Prateek Nayak
2026-10-12 13:40 ` Vincent Guittot
2026-10-12 13:59 ` Kayra Cizmeci
2026-10-12 14:14 ` Vincent Guittot
2026-10-12 15:01 ` Kayra Cizmeci
2026-10-12 19:00 ` Kayra Cizmeci
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®