[PATCH v4 18/20] sched/core: Mark the direction of steal values to avoid oscillations

From: Shrikanth Hegde

Date: Wed Jun 17 2026 - 13:47:07 EST


Cache the previous decision on steal time. So consecutive values of
high values or low values are taken for increase/decrease of preferred
CPUs.

Also make lower threhold equal to less than to handle one setting it to
zero.

Signed-off-by: Shrikanth Hegde <sshegde@xxxxxxxxxxxxx>
---
v3->v4:
- Consider equal or less than for low threshold.
- reset the direction when disabling the feature.

kernel/sched/core.c | 12 ++++++++++--
kernel/sched/debug.c | 1 +
2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 657c36a0e7ca..57d52973ef0d 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -11483,12 +11483,20 @@ void sched_steal_detection_work(struct work_struct *work)
steal_ratio = (delta_steal * 100 * 100) / (delta_ns * num_active_cpus());

/* If the steal time values are high, reduce one core from preferred CPUs */
- if (steal_ratio > sm->high_threshold)
+ if (sm->previous_decision == 1 && steal_ratio > sm->high_threshold)
arch_dec_preferred_cpus(sm, steal_ratio);

/* If the steal time values are low, increase one core as preferred CPUs */
- if (steal_ratio < sm->low_threshold)
+ if (sm->previous_decision == -1 && steal_ratio <= sm->low_threshold)
arch_inc_preferred_cpus(sm, steal_ratio);
+
+ /* mark the direction. This helps to avoid ping-pongs */
+ if (steal_ratio > sm->high_threshold)
+ sm->previous_decision = 1;
+ else if (steal_ratio <= sm->low_threshold)
+ sm->previous_decision = -1;
+ else
+ sm->previous_decision = 0;
}

void sched_trigger_steal_computation(int cpu)
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 55b8beb42574..ae7a641931d1 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -650,6 +650,7 @@ static ssize_t sched_sm_en_write(struct file *filp, const char __user *ubuf,
} else if (!sched_sm_wr_enable && orig) {
static_branch_disable(&__sched_sm_enable);
cancel_work_sync(&steal_mon.work);
+ steal_mon.previous_decision = 0;
cpumask_copy(&__cpu_preferred_mask, cpu_active_mask);
}

--
2.47.3