On 9/9/26 4:28 AM, Yury Norov wrote:
On Mon, Sep 07, 2026 at 08:53:19AM +0530, Shrikanth Hegde wrote:
Hi Yury, thanks for taking a look.
+ /* This could take rq lock. So call it before rq lock is taken */
+ cpu = select_fallback_rq(rq->cpu, p);
+ rq_lock(rq, &rf);
If select_fallback_rq() grabs the lock, then when it releases the
lock, there's a window for race between the other process and the
subsequent rq_lock(). Or I misunderstand it?
select_fallback_rq taking lock is for any state change that needs to happen
such as fallback to possible CPUs etc.
Most of the time it won't grab the rq lock. Even if the task got pulled by load
balancer
before grabbing the lock, Below (task_rq(p) == rq) will catch that, and it
bails out.
So it is safe.
OK... Can you please explain it in the comment above?
...
Ok.
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 6c3ad70e58b8..678e44134acf 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1298,6 +1298,8 @@ struct rq {
struct list_head cfs_tasks;
+ bool push_task_work_done;
+
It should be protected with CONFIG_PREFERRED_CPU. Also, the name
doesn't look correct. You set the variable to 'true' even before
calling the stopper. Maybe need_push_to_npc, or similar?
ok. npc_push_work_pending is probably a better one?
Why did you place it between cfs_tasks and avg_rt? If no specific
reason, maybe place it next to CONFIG_PARAVIRT-guarded fields.
I don't see a common empty space there. I could increase the size.
What about pahole?
I did check pahole on powerpc which has 128 byte cachelines.
int online; /* 4524 4 */
struct list_head cfs_tasks; /* 4528 16 */
/* XXX 64 bytes hole, try to pack */
It was empty space. Now, that i check 64 byte cachelines it may not be the
optimal one.
I do see, a couple common places for both 64 abd 126 byte cacheline. I believe
those
are better places. It won't increase the size or cause any existing fields to
misalign. It also makes sense to guard it again CONFIG_PREFERRED_CPU. I had not
done to avoid ifdefs. But it is used only under it. So i think that makes sense
too.
1.
struct balance_callback * balance_callback; /* 3608 8 */
unsigned char nohz_idle_balance; /* 3616 1 */
unsigned char idle_balance; /* 3617 1 */
/* XXX 6 bytes hole, try to pack */
long unsigned int misfit_task_load; /* 3624 8 */
2.
unsigned int ttwu_count; /* 5276 4 */
unsigned int ttwu_local; /* 5280 4 */
/* XXX 4 bytes hole, try to pack */
struct cpuidle_state * idle_state; /* 5288 8 */
The struct rq is highly configurable. Depending on your config,
the holes will migrate to different places. I'd not rely on just
'optimizing holes' problem. Just put the new field next to logically
related existing fields.
You've got paravirt-related prev_steal_time and prev_steal_time_rq,
and you've got the /* For active balancing */ section. Maybe one of
them?
Ok. Moving it after prev_steal_time_rq.
#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
u64 prev_steal_time_rq;
#endif
+#ifdef CONFIG_PREFERRED_CPU
+ bool npc_push_work_pending;
+#endif
I checked on 128 byte cachelines, it didn't increase the number of cachelines
with the change as well. So we are good there.
base:
/* size: 5632, cachelines: 44, members: 104 */
/* sum members: 5022, holes: 15, sum holes: 502 */
with above change:
/* size: 5632, cachelines: 44, members: 105 */
/* sum members: 5023, holes: 17, sum holes: 533 */
On 64 byte cachelines too, there is 16 bytes hole a bit below. So it should
absorb it
as well. So we are fine there as well.
u64 prev_steal_time_rq; /* 3960 8 */
/* --- cacheline 62 boundary (3968 bytes) --- */
long unsigned int calc_load_update; /* 3968 8 */
long int calc_load_active; /* 3976 8 */
/* XXX 16 bytes hole, try to pack */
call_single_data_t hrtick_csd __attribute__((__aligned__(32)));
/* 4000 32 */
I will make this change and send out v13 today.
Thanks,
Yury