Re: [PATCH v4 06/20] sched/core: allow only preferred CPUs in is_cpu_allowed
From: Shrikanth Hegde
Date: Thu Jun 18 2026 - 10:12:58 EST
Hi Prateek, Yury,
On 6/18/26 9:52 AM, Shrikanth Hegde wrote:
Hi Prateek.
On 6/18/26 9:19 AM, K Prateek Nayak wrote:
Hello Shrikanth,
On 6/17/2026 11:11 PM, Shrikanth Hegde wrote:
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1657,6 +1657,7 @@ struct task_struct {
#ifdef CONFIG_UNWIND_USER
struct unwind_task_info unwind_info;
#endif
+ int has_preferred_cpu_state;
Since this only really needs 2 bits, perhaps you can use the "u8 __pad"
in the task struct? ...
/* CPU-specific state of this task: */
struct thread_struct thread;
[...snip...]
@@ -3549,6 +3568,14 @@ static int select_fallback_rq(int cpu, struct task_struct *p)
enum { cpuset, possible, fail } state = cpuset;
int dest_cpu;
+ /*
+ * Cache value whether task's affinity spans preferred CPUs.
+ * This helps to avoid repeating the same for each CPU
+ * later in the loop. Encode call to is_cpu_allowed coming
+ * via select_fallback_rq.
+ */
+ p->has_preferred_cpu_state = task_has_preferred_cpus(p) << 8 | 0x1;
... Or maybe it can be an s8 and this indicator can be a tri-state like:
-1: Cached; preferred CPUs exists
0: preferred CPUs not cached
1: Cached; preferred CPUs don't exist
Yes. Current encoding has.
1. call came from select_fallback_rq and preferred CPUs exists
2. call came from select_fallback_rq and preferred CPUs doesn't exists
3. Call didn't come from select_fallback_rq and evaluate the cpumask_interesect.
and then the comparison can simply be:
if (cached)
return cached < 0;
ppc64le and arm64 seems to generates slightly smaller code for "< 0"
check compared to the current scheme of (& + >>) in
task_has_preferred_cpus().
Yes, this seems better. I will give it a try.
I guess below captures the discussion on this patch.
Other way is pass it as local variable to is_cpu_allowed.
---
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e435f3073ffc..8c2fe953f19b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1658,7 +1658,7 @@ struct task_struct {
#ifdef CONFIG_UNWIND_USER
struct unwind_task_info unwind_info;
#endif
- int has_preferred_cpu_state;
+ s8 has_preferred_cpu_state;
/* CPU-specific state of this task: */
struct thread_struct thread;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 9342aae315ca..26c82cd0bcec 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2504,7 +2504,7 @@ static inline bool rq_has_pinned_tasks(struct rq *rq)
*/
static inline bool is_cpu_allowed(struct task_struct *p, int cpu)
{
- bool task_check_preferred_cpu = false;
+ bool task_check_preferred_cpu;
/* When not in the task's cpumask, no point in looking further. */
if (!task_allowed_on_cpu(p, cpu))
@@ -3573,12 +3573,12 @@ static int select_fallback_rq(int cpu, struct task_struct *p)
int dest_cpu;
/*
- * Cache value whether task's affinity spans preferred CPUs.
+ * Cache the value whether task's affinity spans preferred CPUs.
* This helps to avoid repeating the same for each CPU
* later in the loop. Encode call to is_cpu_allowed coming
* via select_fallback_rq.
*/
- p->has_preferred_cpu_state = task_has_preferred_cpus(p) << 8 | 0x1;
+ p->has_preferred_cpu_state = task_has_preferred_cpus(p) ? 1 : -1;
/*
* If the node that the CPU is on has been offlined, cpu_to_node()
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index f3814099cc0b..da8134568229 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -4220,20 +4220,20 @@ DEFINE_CLASS_IS_UNCONDITIONAL(sched_change)
#include "ext.h"
/*
- * has_preferred_cpu_state is encoding two bits of information.
- * First Byte is to encode where the call to is_cpu_allowed coming from.
- * Second Byte is to encode the intersection of task affinity
- * and cpu_preferred_mask.
+ * has_preferred_cpu_state could have the value cached from
+ * select_fallback_rq. It is set/cleared while holding pi_lock
+ * and irq disabled.
*
- * If 1st Byte is set, call to is_cpu_allowed coming from select_fallback_rq.
- * That helps to avoid repeated calculation keeping time complexity same.
+ * 1: Cached and preferred CPUs exists in task's affinity.
+ * 0: Not cached and need to evaluate.
+ * -1: Cached and preferred CPU doesn't exits task's affinity
*/
static inline bool task_has_preferred_cpus(struct task_struct *p)
{
- int cached_value = p->has_preferred_cpu_state;
+ int cached = p->has_preferred_cpu_state;
- if (cached_value & 0x1)
- return p->has_preferred_cpu_state >> 8;
+ if (cached)
+ return cached > 0;
else
return cpumask_intersects(p->cpus_ptr, cpu_preferred_mask);
}