Re: [RFC] sched/fair: avoid redundant updates for unchanged default slices
From: Chengfeng Lin
Date: Tue Oct 13 2026 - 06:06:39 EST
Hi Peter,
Sorry for the long and confusing explanation. The performance test was
not a PI test: it repeatedly called sched_setparam(0, priority=0) from an
ordinary SCHED_OTHER task using the default slice. PI was only part of
the correctness checks.
You are right that equal runtimes alone are not enough. Both problems
occur in unmodified v7.2 and my previous prototype. The attached revision
uses your mode-first comparison and fixes both in the tests:
- Requesting a custom slice now switches the task to custom mode, even
if its duration equals the current default. Later changes to the
default no longer change that task's slice.
- In the RT-PI test, sched_setparam() resets the implicit uclamp_min
from 1024 to 0 after the boost ends, even though the slice duration
is unchanged.
The revision and unmodified v7.2 also passed the basic syscall checks
and the other controls: RT/DL PI, default-duration changes, explicit
uclamp requests and bounded concurrent default changes.
The revision keeps the update path when the default
duration has changed, an implicit clamp needs resetting, or the task is
not currently in the fair class. Explicit uclamp requests still take the
existing update path.
I reran the benchmark with the same parameters on unmodified v7.2,
the revision, and unmodified v7.2 again. These are new measurements,
not the previous prototype's numbers (ns per sched_setparam call):
Original A Revision Original B
Unchanged default slice 615.98 162.39 617.03
Unchanged custom slice 162.69 163.22 162.45
The default-slice case saves about 454 ns (73.66%); the existing custom
fast path costs about 0.65 ns more (0.40%), relative to the midpoint of
the two original runs. The runs used the same GCC 15.2 build settings
apart from the release suffix, CPU 2 on the same bare-metal machine,
full preemption, performance mode with turbo disabled, and 15 samples
of 500,000 calls per case per boot. Control drift was below 0.18% and
within-run CV below 0.30%. Probes were used separately, not during timing.
The attached default-slice-peter-v4.patch is the revision tested here,
against unmodified v7.2. Does this look like a reasonable way to keep
the unchanged-parameter fast path while handling these cases?
Thanks,
Chengfeng
Assisted-by: LLM
Subject: [RFC prototype] sched/fair: distinguish slice mode before skipping updates
Use separate checks for default/custom mode and requested duration.
Keep stale-default refreshes, implicit clamp resets and the full
update path outside the actual fair class. Equal numeric runtimes
alone must not skip a requested mode change or clamp reset.
This experimental prototype was prepared with LLM assistance.
It is not a signed-off submission.
---
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -488,6 +488,38 @@
return -EPERM;
return 0;
+}
+
+static bool fair_params_changed(struct task_struct *p,
+ const struct sched_attr *attr)
+{
+ if (attr->sched_nice != task_nice(p))
+ return true;
+
+ /* Keep the full update path for PI-boosted and sched_ext tasks. */
+ if (p->sched_class != &fair_sched_class)
+ return true;
+
+ if (!!attr->sched_runtime != !!p->se.custom_slice)
+ return true;
+
+ if (attr->sched_runtime && attr->sched_runtime != p->se.slice)
+ return true;
+
+ if (!attr->sched_runtime &&
+ p->se.slice != READ_ONCE(sysctl_sched_base_slice))
+ return true;
+
+#ifdef CONFIG_UCLAMP_TASK
+ /* Equal fair parameters do not rule out an implicit clamp reset. */
+ if ((!p->uclamp_req[UCLAMP_MIN].user_defined &&
+ p->uclamp_req[UCLAMP_MIN].value != uclamp_none(UCLAMP_MIN)) ||
+ (!p->uclamp_req[UCLAMP_MAX].user_defined &&
+ p->uclamp_req[UCLAMP_MAX].value != uclamp_none(UCLAMP_MAX)))
+ return true;
+#endif
+
+ return false;
}
int __sched_setscheduler(struct task_struct *p,
@@ -589,8 +621,7 @@
*/
if (unlikely(policy == p->policy)) {
if (fair_policy(policy) &&
- (attr->sched_nice != task_nice(p) ||
- (attr->sched_runtime != p->se.slice)))
+ fair_params_changed(p, attr))
goto change;
if (rt_policy(policy) && attr->sched_priority != p->rt_priority)
goto change;