mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/2] sched/fair: Optimize some active balance logic
@ 2026-06-15  5:38 Xin Zhao
  2026-06-15  5:38 ` [PATCH v3 1/2] sched/fair: Don't trigger active lb if src_rq->curr is CFS and not on_rq Xin Zhao
  2026-06-15  5:38 ` [PATCH v3 2/2] sched/fair: Simplify balance_interval reset logic in sched_balance_rq() Xin Zhao
  0 siblings, 2 replies; 8+ messages in thread
From: Xin Zhao @ 2026-06-15  5:38 UTC (permalink / raw)
  To: vschneid, mingo, peterz, juri.lelli, vincent.guittot,
	dietmar.eggemann, rostedt, bsegall, mgorman, kprateek.nayak,
	aiqun.yu
  Cc: linux-kernel, Xin Zhao

Active balancing needs the help by migration threads which will interrupt
task on src_rq. It has a certain impact on overall performance. Active
balancing often fails, there is a check to determine whether the current
task(say it 'curr') on src_rq can run on dst_rq. We have observed that
even that, if curr is a CFS task and on_rq is 0, the failure rate of
active balancing is very high. Below are the test data from a certain
fillback task scenario executed on a platform with 18 CPUs over 300
seconds:

total: the total count of cases that match
cpumask_test_cpu(this_cpu, busiest->curr->cpus_ptr) &&
busiest->curr->sched_class == &fair_sched_class &&
!busiest->curr->on_rq
succ/fail: the active balance success/fail cases that match
cpumask_......->on_rq

                      total    succ    fail
cpu0  domain0 00003       0       0       0
cpu0  domain1 3ffff      32       0      32
cpu1  domain0 00003       0       0       0
cpu1  domain1 3ffff      40       0      40
cpu2  domain0 0003c       3       0       3
cpu2  domain1 3ffff       6       0       6
cpu3  domain0 0003c       3       1       2
cpu3  domain1 3ffff       3       0       3
cpu4  domain0 0003c       3       0       3
cpu4  domain1 3ffff       4       0       4
cpu5  domain0 0003c       1       0       1
cpu5  domain1 3ffff       6       0       6
cpu6  domain0 003c0      39       0      39
cpu6  domain1 3ffff      36       0      36
cpu7  domain0 003c0     213       4     209
cpu7  domain1 3ffff      24       2      22
cpu8  domain0 003c0     242      16     226
cpu8  domain1 3ffff      16       0      16
cpu9  domain0 003c0       0       0       0
cpu9  domain1 3ffff       6       1       5
cpu10 domain0 03c00      58       1      57
cpu10 domain1 3ffff       0       0       0
cpu11 domain0 03c00      54       4      50
cpu11 domain1 3ffff       1       0       1
cpu12 domain0 03c00      66       1      65
cpu12 domain1 3ffff       0       0       0
cpu13 domain0 03c00      66       1      65
cpu13 domain1 3ffff       0       0       0
cpu14 domain0 3c000       0       0       0
cpu14 domain1 3ffff      57       5      52
cpu15 domain0 3c000      15       0      15
cpu15 domain1 3ffff      35       0      35
cpu16 domain0 3c000     148       3     145
cpu16 domain1 3ffff     109       1     108
cpu17 domain0 3c000     182       2     180
cpu17 domain1 3ffff      78       1      77

In __schedule(), before setting curr to next, during the execution of
pick_next_task(), sched_balance_rq() is called. It will unlock and then
re-lock the rq, creating "holes" during which other CPUs may see zero
rq->curr->on_rq. try_to_block_task() sets curr->on_rq to 0, and during the
rq lock "hole" in pick_next_task(), rq->curr has not yet been assigned to
next, resulting in curr->on_rq being seen as 0.

We do not need to perform active balancing when src_rq->curr is CFS task
but on_rq is 0, as other CFS tasks have been already checked just before.
For cases where src_rq->curr is a non-CFS task, we retain the affinity
check for dst_rq to trigger active balancing because such task is likely
to wake-up or woken-by src_rq CFS task which has similar affinity
characteristics to migrate.

Two reasons why not check sched_class and on_rq of busiest->curr with the
cpumask_test_cpu() check:
1. Let the PATCH not introduce new cases that skip logic for resetting
balance_interval to min_interval.
2. The check of whether busiest cpu has been just triggered active balance
filters a bit more cases than the check of sched_class and on_rq.

Additionally, in sched_balance_rq(), we unconditionally reset the
balance_interval to min_interval. The difference is that original logic
does not reset the balance_interval when dst_cpu softirq handler is
preempted while src_cpu successfully run the just-dispatched active
balancing, during the gaps between two need_active_balance() checks. It
seems that we haven't observed any substantial benefits from reducing the
opportunities for balance under such fluctuating conditions. So simplify
the need_active_balance() checks logic.

---
Changes in v3:
- Consider the cost by sched_class and on_rq check,
  as suggested by Aiqun(Maira) Yu.
  Move the check after the check of whether busiest cpu has been just
  triggered active balance.
- Separate the revise of balance_interval reset part to an independent
  patch, as suggested by Aiqun(Maira) Yu.
  Add more details about the independent patch.

Change in v2:
- Add reason in the commit log why we can see zero rq->curr->on_rq when we
  hold rq lock,
  as suggested by Valentin Schneider.
- Link to v2: https://lore.kernel.org/all/20260613073228.1951105-1-jackzxcui1989@163.com/

v1:
- Link to v1: https://lore.kernel.org/all/20260603125938.1938115-1-jackzxcui1989@163.com/

Xin Zhao (2):
  sched/fair: Don't trigger active lb if src_rq->curr is CFS and not
    on_rq
  sched/fair: Simplify balance_interval reset logic in
    sched_balance_rq()

 kernel/sched/fair.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 1/2] sched/fair: Don't trigger active lb if src_rq->curr is CFS and not on_rq
  2026-06-15  5:38 [PATCH v3 0/2] sched/fair: Optimize some active balance logic Xin Zhao
@ 2026-06-15  5:38 ` Xin Zhao
  2026-06-15 13:39   ` Valentin Schneider
  2026-06-15  5:38 ` [PATCH v3 2/2] sched/fair: Simplify balance_interval reset logic in sched_balance_rq() Xin Zhao
  1 sibling, 1 reply; 8+ messages in thread
From: Xin Zhao @ 2026-06-15  5:38 UTC (permalink / raw)
  To: vschneid, mingo, peterz, juri.lelli, vincent.guittot,
	dietmar.eggemann, rostedt, bsegall, mgorman, kprateek.nayak,
	aiqun.yu
  Cc: linux-kernel, Xin Zhao

Active balancing needs the help by migration threads which will interrupt
task on src_rq. It has a certain impact on overall performance. Active
balancing often fails, there is a check to determine whether the current
task(say it 'curr') on src_rq can run on dst_rq. We have observed that
even that, if curr is a CFS task and on_rq is 0, the failure rate of
active balancing is very high. Below are the test data from a certain
fillback task scenario executed on a platform with 18 CPUs over 300
seconds:

total: the total count of cases that match
cpumask_test_cpu(this_cpu, busiest->curr->cpus_ptr) &&
busiest->curr->sched_class == &fair_sched_class &&
!busiest->curr->on_rq
succ/fail: the active balance success/fail cases that match
cpumask_......->on_rq

                      total    succ    fail
cpu0  domain0 00003       0       0       0
cpu0  domain1 3ffff      32       0      32
cpu1  domain0 00003       0       0       0
cpu1  domain1 3ffff      40       0      40
cpu2  domain0 0003c       3       0       3
cpu2  domain1 3ffff       6       0       6
cpu3  domain0 0003c       3       1       2
cpu3  domain1 3ffff       3       0       3
cpu4  domain0 0003c       3       0       3
cpu4  domain1 3ffff       4       0       4
cpu5  domain0 0003c       1       0       1
cpu5  domain1 3ffff       6       0       6
cpu6  domain0 003c0      39       0      39
cpu6  domain1 3ffff      36       0      36
cpu7  domain0 003c0     213       4     209
cpu7  domain1 3ffff      24       2      22
cpu8  domain0 003c0     242      16     226
cpu8  domain1 3ffff      16       0      16
cpu9  domain0 003c0       0       0       0
cpu9  domain1 3ffff       6       1       5
cpu10 domain0 03c00      58       1      57
cpu10 domain1 3ffff       0       0       0
cpu11 domain0 03c00      54       4      50
cpu11 domain1 3ffff       1       0       1
cpu12 domain0 03c00      66       1      65
cpu12 domain1 3ffff       0       0       0
cpu13 domain0 03c00      66       1      65
cpu13 domain1 3ffff       0       0       0
cpu14 domain0 3c000       0       0       0
cpu14 domain1 3ffff      57       5      52
cpu15 domain0 3c000      15       0      15
cpu15 domain1 3ffff      35       0      35
cpu16 domain0 3c000     148       3     145
cpu16 domain1 3ffff     109       1     108
cpu17 domain0 3c000     182       2     180
cpu17 domain1 3ffff      78       1      77

In __schedule(), before setting curr to next, during the execution of
pick_next_task(), sched_balance_rq() is called. It will unlock and then
re-lock the rq, creating "holes" during which other CPUs may see zero
rq->curr->on_rq. try_to_block_task() sets curr->on_rq to 0, and during the
rq lock "hole" in pick_next_task(), rq->curr has not yet been assigned to
next, resulting in curr->on_rq being seen as 0.

We do not need to perform active balancing when src_rq->curr is CFS task
but on_rq is 0, as other CFS tasks have been already checked just before.
For cases where src_rq->curr is a non-CFS task, we retain the affinity
check for dst_rq to trigger active balancing because such task is likely
to wake-up or woken-by src_rq CFS task which has similar affinity
characteristics to migrate.

Two reasons why not check sched_class and on_rq of busiest->curr with the
cpumask_test_cpu() check:
1. Let the PATCH not introduce new cases that skip logic for resetting
balance_interval to min_interval.
2. The check of whether busiest cpu has been just triggered active balance
filters a bit more cases than the check of sched_class and on_rq.

Signed-off-by: Xin Zhao <jackzxcui1989@163.com>
---

Change in v3:
- Consider the cost by sched_class and on_rq check,
  as suggested by Aiqun(Maira) Yu.
  Move the check after the check of whether busiest cpu has been just
  triggered active balance.

Change in v2:
- Add reason in the commit log why we can see zero rq->curr->on_rq when we
  hold rq lock,
  as suggested by Valentin Schneider.
- Link to v2: https://lore.kernel.org/all/20260613073228.1951105-1-jackzxcui1989@163.com/

v1:
- Link to v1: https://lore.kernel.org/all/20260603125938.1938115-1-jackzxcui1989@163.com/
---
 kernel/sched/fair.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index b5819c489..1c5043629 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -13436,7 +13436,9 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
 			 * ->active_balance_work.  Once set, it's cleared
 			 * only after active load balance is finished.
 			 */
-			if (!busiest->active_balance) {
+			if (!busiest->active_balance &&
+			    !(busiest->curr->sched_class == &fair_sched_class &&
+			      !busiest->curr->on_rq)) {
 				busiest->active_balance = 1;
 				busiest->push_cpu = this_cpu;
 				active_balance = 1;
-- 
2.34.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 2/2] sched/fair: Simplify balance_interval reset logic in sched_balance_rq()
  2026-06-15  5:38 [PATCH v3 0/2] sched/fair: Optimize some active balance logic Xin Zhao
  2026-06-15  5:38 ` [PATCH v3 1/2] sched/fair: Don't trigger active lb if src_rq->curr is CFS and not on_rq Xin Zhao
@ 2026-06-15  5:38 ` Xin Zhao
  1 sibling, 0 replies; 8+ messages in thread
From: Xin Zhao @ 2026-06-15  5:38 UTC (permalink / raw)
  To: vschneid, mingo, peterz, juri.lelli, vincent.guittot,
	dietmar.eggemann, rostedt, bsegall, mgorman, kprateek.nayak,
	aiqun.yu
  Cc: linux-kernel, Xin Zhao

In sched_balance_rq(), it is possible to call need_active_balance() twice
in quick succession, which is not appropriate. There are two conditions in
sched_balance_rq() that reset balance_interval to min_interval, one is
when the local variable active_balance is 0, and the other is when
need_active_balance() returns a non-zero value. The local variable
active_balance is initialized to 0. Therefore, the only situation in which
balance_interval can be reset to min_interval is if need_active_balance()
has been executed once, marking the local variable active_balance as 1,
and then the second call to need_active_balance() returns 0. In other
words, the case is that during the interval between two close calls to
need_active_balance(), busiest rq completes the recently dispatched active
balance stop work, which is quite rare.

There are mainly two scenarios that lead to reaching sched_balance_rq():
one is the newly idle balance triggered by __schedule(), and the other is
the periodic balance logic controlled by sd->balance_interval or
nohz.next_balance, which ultimately executes in the softirq context. The
vast majority of cases executing sched_balance_rq() in the system fall
under the first scenario. During the execution of __schedule(), preemption
is disabled, so the interval between two checks of need_active_balance()
in this case will not be long. Thus, before applying this patch,
balance_interval would only be unlikely to reset to min_interval during
the periodic balance logic, which is relatively much more less frequent
than newly balance. In the case which is in softirq context, the execution
of the two need_active_balance() checks can indeed be preempted by other
tasks, leading to a longer interval between the two checks. However, there
is no evidence to suggest that not resetting min_interval in these
low-probability cases caused by scheduling preemption offers any
significant benefits. It would be better to simplify this complex reset
logic for balance_interval to an unconditional reset.

Signed-off-by: Xin Zhao <jackzxcui1989@163.com>
---
 kernel/sched/fair.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 1c5043629..b562a610b 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -13457,10 +13457,8 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
 		sd->nr_balance_failed = 0;
 	}
 
-	if (likely(!active_balance) || need_active_balance(&env)) {
-		/* We were unbalanced, so reset the balancing interval */
-		sd->balance_interval = sd->min_interval;
-	}
+	/* We were unbalanced, so reset the balancing interval */
+	sd->balance_interval = sd->min_interval;
 
 	goto out;
 
-- 
2.34.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 1/2] sched/fair: Don't trigger active lb if src_rq->curr is CFS and not on_rq
  2026-06-15  5:38 ` [PATCH v3 1/2] sched/fair: Don't trigger active lb if src_rq->curr is CFS and not on_rq Xin Zhao
@ 2026-06-15 13:39   ` Valentin Schneider
  2026-06-15 13:57     ` Phil Auld
  2026-06-15 14:09     ` Xin Zhao
  0 siblings, 2 replies; 8+ messages in thread
From: Valentin Schneider @ 2026-06-15 13:39 UTC (permalink / raw)
  To: Xin Zhao, mingo, peterz, juri.lelli, vincent.guittot,
	dietmar.eggemann, rostedt, bsegall, mgorman, kprateek.nayak,
	aiqun.yu
  Cc: linux-kernel, Xin Zhao

On 15/06/26 13:38, Xin Zhao wrote:
> Active balancing needs the help by migration threads which will interrupt
> task on src_rq. It has a certain impact on overall performance. Active
> balancing often fails, there is a check to determine whether the current
> task(say it 'curr') on src_rq can run on dst_rq. We have observed that
> even that, if curr is a CFS task and on_rq is 0, the failure rate of
> active balancing is very high. Below are the test data from a certain
> fillback task scenario executed on a platform with 18 CPUs over 300
> seconds:
>
> total: the total count of cases that match
> cpumask_test_cpu(this_cpu, busiest->curr->cpus_ptr) &&
> busiest->curr->sched_class == &fair_sched_class &&
> !busiest->curr->on_rq
> succ/fail: the active balance success/fail cases that match
> cpumask_......->on_rq
>
>                       total    succ    fail
> cpu0  domain0 00003       0       0       0
> cpu0  domain1 3ffff      32       0      32
> cpu1  domain0 00003       0       0       0
> cpu1  domain1 3ffff      40       0      40
> cpu2  domain0 0003c       3       0       3
> cpu2  domain1 3ffff       6       0       6
> cpu3  domain0 0003c       3       1       2
> cpu3  domain1 3ffff       3       0       3
> cpu4  domain0 0003c       3       0       3
> cpu4  domain1 3ffff       4       0       4
> cpu5  domain0 0003c       1       0       1
> cpu5  domain1 3ffff       6       0       6
> cpu6  domain0 003c0      39       0      39
> cpu6  domain1 3ffff      36       0      36
> cpu7  domain0 003c0     213       4     209
> cpu7  domain1 3ffff      24       2      22
> cpu8  domain0 003c0     242      16     226
> cpu8  domain1 3ffff      16       0      16
> cpu9  domain0 003c0       0       0       0
> cpu9  domain1 3ffff       6       1       5
> cpu10 domain0 03c00      58       1      57
> cpu10 domain1 3ffff       0       0       0
> cpu11 domain0 03c00      54       4      50
> cpu11 domain1 3ffff       1       0       1
> cpu12 domain0 03c00      66       1      65
> cpu12 domain1 3ffff       0       0       0
> cpu13 domain0 03c00      66       1      65
> cpu13 domain1 3ffff       0       0       0
> cpu14 domain0 3c000       0       0       0
> cpu14 domain1 3ffff      57       5      52
> cpu15 domain0 3c000      15       0      15
> cpu15 domain1 3ffff      35       0      35
> cpu16 domain0 3c000     148       3     145
> cpu16 domain1 3ffff     109       1     108
> cpu17 domain0 3c000     182       2     180
> cpu17 domain1 3ffff      78       1      77
>
> In __schedule(), before setting curr to next, during the execution of
> pick_next_task(), sched_balance_rq() is called. It will unlock and then
> re-lock the rq, creating "holes" during which other CPUs may see zero
> rq->curr->on_rq. try_to_block_task() sets curr->on_rq to 0, and during the
> rq lock "hole" in pick_next_task(), rq->curr has not yet been assigned to
> next, resulting in curr->on_rq being seen as 0.
>

Aaah, it's a load balance shaped hole... Urgh, okay I see it now, thanks.

> We do not need to perform active balancing when src_rq->curr is CFS task
> but on_rq is 0, as other CFS tasks have been already checked just before.
> For cases where src_rq->curr is a non-CFS task, we retain the affinity
> check for dst_rq to trigger active balancing because such task is likely
> to wake-up or woken-by src_rq CFS task which has similar affinity
> characteristics to migrate.
>
> Two reasons why not check sched_class and on_rq of busiest->curr with the
> cpumask_test_cpu() check:
> 1. Let the PATCH not introduce new cases that skip logic for resetting
> balance_interval to min_interval.
> 2. The check of whether busiest cpu has been just triggered active balance
> filters a bit more cases than the check of sched_class and on_rq.
>
> Signed-off-by: Xin Zhao <jackzxcui1989@163.com>
> ---
>
> Change in v3:
> - Consider the cost by sched_class and on_rq check,
>   as suggested by Aiqun(Maira) Yu.
>   Move the check after the check of whether busiest cpu has been just
>   triggered active balance.
>
> Change in v2:
> - Add reason in the commit log why we can see zero rq->curr->on_rq when we
>   hold rq lock,
>   as suggested by Valentin Schneider.
> - Link to v2: https://lore.kernel.org/all/20260613073228.1951105-1-jackzxcui1989@163.com/
>
> v1:
> - Link to v1: https://lore.kernel.org/all/20260603125938.1938115-1-jackzxcui1989@163.com/
> ---
>  kernel/sched/fair.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index b5819c489..1c5043629 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -13436,7 +13436,9 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
>                        * ->active_balance_work.  Once set, it's cleared
>                        * only after active load balance is finished.
>                        */
> -			if (!busiest->active_balance) {
> +			if (!busiest->active_balance &&
> +			    !(busiest->curr->sched_class == &fair_sched_class &&
> +			      !busiest->curr->on_rq)) {

This should be commented; I restructured this a little, it's one more label
but it reads better to me, what do you think?
---
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6ee13..a0ac31a3be988 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -13482,12 +13482,22 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
 			 * ->active_balance_work.  Once set, it's cleared
 			 * only after active load balance is finished.
 			 */
-			if (!busiest->active_balance) {
-				busiest->active_balance = 1;
-				busiest->push_cpu = this_cpu;
-				active_balance = 1;
-			}
+			if (busiest->active_balance)
+				goto no_active_balance;
 
+			/*
+			 * @busiest dropped its rq_lock in the middle of
+			 * scheduling out its ->curr task (->on_rq := 0), no
+			 * need to forcefully punt it away with active balance.
+			 */
+			if ((busiest->curr->sched_class == &fair_sched_class) &&
+			    !busiest->curr->on_rq)
+				goto no_active_balance;
+
+			busiest->active_balance = 1;
+			busiest->push_cpu = this_cpu;
+			active_balance = 1;
+no_active_balance:
 			preempt_disable();
 			raw_spin_rq_unlock_irqrestore(busiest, flags);
 			if (active_balance) {


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 1/2] sched/fair: Don't trigger active lb if src_rq->curr is CFS and not on_rq
  2026-06-15 13:39   ` Valentin Schneider
@ 2026-06-15 13:57     ` Phil Auld
  2026-06-15 14:09     ` Xin Zhao
  1 sibling, 0 replies; 8+ messages in thread
From: Phil Auld @ 2026-06-15 13:57 UTC (permalink / raw)
  To: Valentin Schneider
  Cc: Xin Zhao, mingo, peterz, juri.lelli, vincent.guittot,
	dietmar.eggemann, rostedt, bsegall, mgorman, kprateek.nayak,
	aiqun.yu, linux-kernel


Hi,

On Mon, Jun 15, 2026 at 03:39:22PM +0200 Valentin Schneider wrote:
> On 15/06/26 13:38, Xin Zhao wrote:
> > Active balancing needs the help by migration threads which will interrupt
> > task on src_rq. It has a certain impact on overall performance. Active
> > balancing often fails, there is a check to determine whether the current
> > task(say it 'curr') on src_rq can run on dst_rq. We have observed that
> > even that, if curr is a CFS task and on_rq is 0, the failure rate of
> > active balancing is very high. Below are the test data from a certain
> > fillback task scenario executed on a platform with 18 CPUs over 300
> > seconds:
> >
> > total: the total count of cases that match
> > cpumask_test_cpu(this_cpu, busiest->curr->cpus_ptr) &&
> > busiest->curr->sched_class == &fair_sched_class &&
> > !busiest->curr->on_rq
> > succ/fail: the active balance success/fail cases that match
> > cpumask_......->on_rq
> >
> >                       total    succ    fail
> > cpu0  domain0 00003       0       0       0
> > cpu0  domain1 3ffff      32       0      32
> > cpu1  domain0 00003       0       0       0
> > cpu1  domain1 3ffff      40       0      40
> > cpu2  domain0 0003c       3       0       3
> > cpu2  domain1 3ffff       6       0       6
> > cpu3  domain0 0003c       3       1       2
> > cpu3  domain1 3ffff       3       0       3
> > cpu4  domain0 0003c       3       0       3
> > cpu4  domain1 3ffff       4       0       4
> > cpu5  domain0 0003c       1       0       1
> > cpu5  domain1 3ffff       6       0       6
> > cpu6  domain0 003c0      39       0      39
> > cpu6  domain1 3ffff      36       0      36
> > cpu7  domain0 003c0     213       4     209
> > cpu7  domain1 3ffff      24       2      22
> > cpu8  domain0 003c0     242      16     226
> > cpu8  domain1 3ffff      16       0      16
> > cpu9  domain0 003c0       0       0       0
> > cpu9  domain1 3ffff       6       1       5
> > cpu10 domain0 03c00      58       1      57
> > cpu10 domain1 3ffff       0       0       0
> > cpu11 domain0 03c00      54       4      50
> > cpu11 domain1 3ffff       1       0       1
> > cpu12 domain0 03c00      66       1      65
> > cpu12 domain1 3ffff       0       0       0
> > cpu13 domain0 03c00      66       1      65
> > cpu13 domain1 3ffff       0       0       0
> > cpu14 domain0 3c000       0       0       0
> > cpu14 domain1 3ffff      57       5      52
> > cpu15 domain0 3c000      15       0      15
> > cpu15 domain1 3ffff      35       0      35
> > cpu16 domain0 3c000     148       3     145
> > cpu16 domain1 3ffff     109       1     108
> > cpu17 domain0 3c000     182       2     180
> > cpu17 domain1 3ffff      78       1      77
> >
> > In __schedule(), before setting curr to next, during the execution of
> > pick_next_task(), sched_balance_rq() is called. It will unlock and then
> > re-lock the rq, creating "holes" during which other CPUs may see zero
> > rq->curr->on_rq. try_to_block_task() sets curr->on_rq to 0, and during the
> > rq lock "hole" in pick_next_task(), rq->curr has not yet been assigned to
> > next, resulting in curr->on_rq being seen as 0.
> >
> 
> Aaah, it's a load balance shaped hole... Urgh, okay I see it now, thanks.
> 
> > We do not need to perform active balancing when src_rq->curr is CFS task
> > but on_rq is 0, as other CFS tasks have been already checked just before.
> > For cases where src_rq->curr is a non-CFS task, we retain the affinity
> > check for dst_rq to trigger active balancing because such task is likely
> > to wake-up or woken-by src_rq CFS task which has similar affinity
> > characteristics to migrate.
> >
> > Two reasons why not check sched_class and on_rq of busiest->curr with the
> > cpumask_test_cpu() check:
> > 1. Let the PATCH not introduce new cases that skip logic for resetting
> > balance_interval to min_interval.
> > 2. The check of whether busiest cpu has been just triggered active balance
> > filters a bit more cases than the check of sched_class and on_rq.
> >
> > Signed-off-by: Xin Zhao <jackzxcui1989@163.com>
> > ---
> >
> > Change in v3:
> > - Consider the cost by sched_class and on_rq check,
> >   as suggested by Aiqun(Maira) Yu.
> >   Move the check after the check of whether busiest cpu has been just
> >   triggered active balance.
> >
> > Change in v2:
> > - Add reason in the commit log why we can see zero rq->curr->on_rq when we
> >   hold rq lock,
> >   as suggested by Valentin Schneider.
> > - Link to v2: https://lore.kernel.org/all/20260613073228.1951105-1-jackzxcui1989@163.com/
> >
> > v1:
> > - Link to v1: https://lore.kernel.org/all/20260603125938.1938115-1-jackzxcui1989@163.com/
> > ---
> >  kernel/sched/fair.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> > index b5819c489..1c5043629 100644
> > --- a/kernel/sched/fair.c
> > +++ b/kernel/sched/fair.c
> > @@ -13436,7 +13436,9 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
> >                        * ->active_balance_work.  Once set, it's cleared
> >                        * only after active load balance is finished.
> >                        */
> > -			if (!busiest->active_balance) {
> > +			if (!busiest->active_balance &&
> > +			    !(busiest->curr->sched_class == &fair_sched_class &&
> > +			      !busiest->curr->on_rq)) {
> 
> This should be commented; I restructured this a little, it's one more label
> but it reads better to me, what do you think?

This below does look better to me as well, fwiw.


Cheers,
Phil

> ---
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index d78467ec6ee13..a0ac31a3be988 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -13482,12 +13482,22 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
>  			 * ->active_balance_work.  Once set, it's cleared
>  			 * only after active load balance is finished.
>  			 */
> -			if (!busiest->active_balance) {
> -				busiest->active_balance = 1;
> -				busiest->push_cpu = this_cpu;
> -				active_balance = 1;
> -			}
> +			if (busiest->active_balance)
> +				goto no_active_balance;
>  
> +			/*
> +			 * @busiest dropped its rq_lock in the middle of
> +			 * scheduling out its ->curr task (->on_rq := 0), no
> +			 * need to forcefully punt it away with active balance.
> +			 */
> +			if ((busiest->curr->sched_class == &fair_sched_class) &&
> +			    !busiest->curr->on_rq)
> +				goto no_active_balance;
> +
> +			busiest->active_balance = 1;
> +			busiest->push_cpu = this_cpu;
> +			active_balance = 1;
> +no_active_balance:
>  			preempt_disable();
>  			raw_spin_rq_unlock_irqrestore(busiest, flags);
>  			if (active_balance) {
> 
> 

-- 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 1/2] sched/fair: Don't trigger active lb if src_rq->curr is CFS and not on_rq
  2026-06-15 13:39   ` Valentin Schneider
  2026-06-15 13:57     ` Phil Auld
@ 2026-06-15 14:09     ` Xin Zhao
  2026-06-16  3:06       ` Aiqun(Maria) Yu
  1 sibling, 1 reply; 8+ messages in thread
From: Xin Zhao @ 2026-06-15 14:09 UTC (permalink / raw)
  To: vschneid
  Cc: aiqun.yu, bsegall, dietmar.eggemann, jackzxcui1989, juri.lelli,
	kprateek.nayak, linux-kernel, mgorman, mingo, peterz, rostedt,
	vincent.guittot

On Mon, 15 Jun 2026 15:39:22 +0200 Valentin Schneider <vschneid@redhat.com> wrote:

> > @@ -13436,7 +13436,9 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
> >                        * ->active_balance_work.  Once set, it's cleared
> >                        * only after active load balance is finished.
> >                        */
> > -			if (!busiest->active_balance) {
> > +			if (!busiest->active_balance &&
> > +			    !(busiest->curr->sched_class == &fair_sched_class &&
> > +			      !busiest->curr->on_rq)) {
> 
> This should be commented; I restructured this a little, it's one more label
> but it reads better to me, what do you think?

:) Thank you for your changes; it looks much better now, and the necessary
comments have been added.

> ---
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index d78467ec6ee13..a0ac31a3be988 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -13482,12 +13482,22 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
>  			 * ->active_balance_work.  Once set, it's cleared
>  			 * only after active load balance is finished.
>  			 */
> -			if (!busiest->active_balance) {
> -				busiest->active_balance = 1;
> -				busiest->push_cpu = this_cpu;
> -				active_balance = 1;
> -			}
> +			if (busiest->active_balance)
> +				goto no_active_balance;
>  
> +			/*
> +			 * @busiest dropped its rq_lock in the middle of
> +			 * scheduling out its ->curr task (->on_rq := 0), no
> +			 * need to forcefully punt it away with active balance.
> +			 */
> +			if ((busiest->curr->sched_class == &fair_sched_class) &&
> +			    !busiest->curr->on_rq)
> +				goto no_active_balance;
> +
> +			busiest->active_balance = 1;
> +			busiest->push_cpu = this_cpu;
> +			active_balance = 1;
> +no_active_balance:
>  			preempt_disable();
>  			raw_spin_rq_unlock_irqrestore(busiest, flags);
>  			if (active_balance) {

Thanks
Xin Zhao


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 1/2] sched/fair: Don't trigger active lb if src_rq->curr is CFS and not on_rq
  2026-06-15 14:09     ` Xin Zhao
@ 2026-06-16  3:06       ` Aiqun(Maria) Yu
  2026-06-16  4:07         ` Xin Zhao
  0 siblings, 1 reply; 8+ messages in thread
From: Aiqun(Maria) Yu @ 2026-06-16  3:06 UTC (permalink / raw)
  To: Xin Zhao, vschneid
  Cc: bsegall, dietmar.eggemann, juri.lelli, kprateek.nayak,
	linux-kernel, mgorman, mingo, peterz, rostedt, vincent.guittot

On 6/15/2026 10:09 PM, Xin Zhao wrote:
> On Mon, 15 Jun 2026 15:39:22 +0200 Valentin Schneider <vschneid@redhat.com> wrote:
> 
>>> @@ -13436,7 +13436,9 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
>>>                        * ->active_balance_work.  Once set, it's cleared
>>>                        * only after active load balance is finished.
>>>                        */
>>> -			if (!busiest->active_balance) {
>>> +			if (!busiest->active_balance &&
>>> +			    !(busiest->curr->sched_class == &fair_sched_class &&
>>> +			      !busiest->curr->on_rq)) {
>>
>> This should be commented; I restructured this a little, it's one more label
>> but it reads better to me, what do you think?
> 
> :) Thank you for your changes; it looks much better now, and the necessary
> comments have been added.

This format looks better.

> 
>> ---
>> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
>> index d78467ec6ee13..a0ac31a3be988 100644
>> --- a/kernel/sched/fair.c
>> +++ b/kernel/sched/fair.c
>> @@ -13482,12 +13482,22 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq,
>>  			 * ->active_balance_work.  Once set, it's cleared
>>  			 * only after active load balance is finished.
>>  			 */
>> -			if (!busiest->active_balance) {
>> -				busiest->active_balance = 1;
>> -				busiest->push_cpu = this_cpu;
>> -				active_balance = 1;
>> -			}
>> +			if (busiest->active_balance)
>> +				goto no_active_balance;
>>  
>> +			/*
>> +			 * @busiest dropped its rq_lock in the middle of
>> +			 * scheduling out its ->curr task (->on_rq := 0), no
>> +			 * need to forcefully punt it away with active balance.
>> +			 */
>> +			if ((busiest->curr->sched_class == &fair_sched_class) &&
>> +			    !busiest->curr->on_rq)

Still have the doubt why need to do active load balance when the current
is not CFS. And busiest->curr->on_rq==0 case only.

Is it should be like:
if ((busiest->curr->sched_class == &fair_sched_class) ||
unlikely(!task_on_rq_queued(busiest->curr)));

if busiest->curr->on_rq==2 (TASK_ON_RQ_MIGRATING), it is no need to do
active_balance as well.

>> +				goto no_active_balance;
>> +
>> +			busiest->active_balance = 1;
>> +			busiest->push_cpu = this_cpu;
>> +			active_balance = 1;
>> +no_active_balance:
>>  			preempt_disable();
>>  			raw_spin_rq_unlock_irqrestore(busiest, flags);
>>  			if (active_balance) {
> 
> Thanks
> Xin Zhao
> 


-- 
Thx and BRs,
Aiqun(Maria) Yu

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 1/2] sched/fair: Don't trigger active lb if src_rq->curr is CFS and not on_rq
  2026-06-16  3:06       ` Aiqun(Maria) Yu
@ 2026-06-16  4:07         ` Xin Zhao
  0 siblings, 0 replies; 8+ messages in thread
From: Xin Zhao @ 2026-06-16  4:07 UTC (permalink / raw)
  To: aiqun.yu
  Cc: bsegall, dietmar.eggemann, jackzxcui1989, juri.lelli,
	kprateek.nayak, linux-kernel, mgorman, mingo, peterz, rostedt,
	vincent.guittot, vschneid

On Tue, 16 Jun 2026 11:06:54 +0800 "Aiqun(Maria) Yu" <aiqun.yu@oss.qualcomm.com> wrote:

> >> +			 * need to forcefully punt it away with active balance.
> >> +			 */
> >> +			if ((busiest->curr->sched_class == &fair_sched_class) &&
> >> +			    !busiest->curr->on_rq)
> 
> Still have the doubt why need to do active load balance when the current
> is not CFS. And busiest->curr->on_rq==0 case only.
> 
> Is it should be like:
> if ((busiest->curr->sched_class == &fair_sched_class) ||
> unlikely(!task_on_rq_queued(busiest->curr)));

The platform I am using is quite close to actual usage, and the tasks
bound to different CPUs and different scheduling domains vary
significantly. From my data, there isn't a single CPU with an active
balance success rate below 50% under such scenarios. As for your earlier
comment that "just do detach_task and attach_task and the success rate
will be 100%", I believe you should take a closer look at the
implementation of active_load_balance_cpu_stop. That should make it clear
where the statistical code I previously sent you is located, instead of
simply questioning my approach of performing an ineffective "detach_task
and attach_task" operation to artificially inflate the success rate during
testing.

Regarding why the success rate of active balance is so high in this case,
I have my own reasonable explanations, and I prefer not to repeat them
over and over.

> if busiest->curr->on_rq==2 (TASK_ON_RQ_MIGRATING), it is no need to do
> active_balance as well.

There is a slight difference for the compiler between comparing == 1 and
comparing != 0. From my current understanding, comparing to a non-zero
value is generally faster than comparing to a specific number in most of
arch. I have previously tested whether on_rq would ever be equal to 2 and,
over a long period of time, I did not encounter a single instance where
on_rq was 2. This at least indicates that the probability is extremely
low, and it may even be theoretically impossible for such a situation to
occur.

Thanks
Xin Zhao


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-06-16  4:08 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-15  5:38 [PATCH v3 0/2] sched/fair: Optimize some active balance logic Xin Zhao
2026-06-15  5:38 ` [PATCH v3 1/2] sched/fair: Don't trigger active lb if src_rq->curr is CFS and not on_rq Xin Zhao
2026-06-15 13:39   ` Valentin Schneider
2026-06-15 13:57     ` Phil Auld
2026-06-15 14:09     ` Xin Zhao
2026-06-16  3:06       ` Aiqun(Maria) Yu
2026-06-16  4:07         ` Xin Zhao
2026-06-15  5:38 ` [PATCH v3 2/2] sched/fair: Simplify balance_interval reset logic in sched_balance_rq() Xin Zhao

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®