[PATCH v2] sched_ext: Skip per-CPU data allocation for built-in DSQs
From: Qiurong Fang
Date: Mon Aug 31 2026 - 21:33:39 EST
From: fangqiurong <fangqiurong@xxxxxxxxxx>
Deferred reenqueue tracking is only supported for user DSQs:
schedule_dsq_reenq() serves the local DSQ through
sch->pcpu->deferred_reenq_local and rejects all other built-in DSQ
ids. Every DSQ still allocates nr_cpu_ids * sizeof(struct scx_dsq_pcpu)
bytes of per-CPU memory for it.
Skip the allocation for built-in DSQ ids. While at it, rename ->pcpu to
->pcpu_user so that the per-CPU data reads as user-DSQ only.
Signed-off-by: fangqiurong <fangqiurong@xxxxxxxxxx>
---
v2: Rename ->pcpu to ->pcpu_user as suggested by Tejun. Describe the
memory waste as quadratic as pointed out by Zhan Xusheng. Drop the
Fixes: tag as this is a plain memory saving with no correctness
impact.
---
include/linux/sched/ext.h | 2 +-
kernel/sched/ext/ext.c | 20 ++++++++++++++------
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/include/linux/sched/ext.h b/include/linux/sched/ext.h
index 582d7cd4a983..3c793d51c000 100644
--- a/include/linux/sched/ext.h
+++ b/include/linux/sched/ext.h
@@ -91,7 +91,7 @@ struct scx_dispatch_q {
struct rhash_head hash_node;
struct llist_node free_node;
struct scx_sched *sched;
- struct scx_dsq_pcpu __percpu *pcpu;
+ struct scx_dsq_pcpu __percpu *pcpu_user;
struct rcu_head rcu;
};
diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
index c539d15cda63..efb492876cd6 100644
--- a/kernel/sched/ext/ext.c
+++ b/kernel/sched/ext/ext.c
@@ -1127,7 +1127,8 @@ void schedule_dsq_reenq(struct scx_sched *sch, struct scx_dispatch_q *dsq,
} else if (!(dsq->id & SCX_DSQ_FLAG_BUILTIN)) {
rq = this_rq();
- struct scx_dsq_pcpu *dsq_pcpu = per_cpu_ptr(dsq->pcpu, cpu_of(rq));
+ struct scx_dsq_pcpu *dsq_pcpu =
+ per_cpu_ptr(dsq->pcpu_user, cpu_of(rq));
struct scx_deferred_reenq_user *dru = &dsq_pcpu->deferred_reenq_user;
/*
@@ -5048,12 +5049,16 @@ s32 scx_init_dsq(struct scx_dispatch_q *dsq, u64 dsq_id, struct scx_sched *sch)
dsq->id = dsq_id;
dsq->sched = sch;
- dsq->pcpu = alloc_percpu(struct scx_dsq_pcpu);
- if (!dsq->pcpu)
+ /* Deferred reenqueue tracking is only supported for user DSQs */
+ if (dsq_id & SCX_DSQ_FLAG_BUILTIN)
+ return 0;
+
+ dsq->pcpu_user = alloc_percpu(struct scx_dsq_pcpu);
+ if (!dsq->pcpu_user)
return -ENOMEM;
for_each_possible_cpu(cpu) {
- struct scx_dsq_pcpu *pcpu = per_cpu_ptr(dsq->pcpu, cpu);
+ struct scx_dsq_pcpu *pcpu = per_cpu_ptr(dsq->pcpu_user, cpu);
pcpu->dsq = dsq;
INIT_LIST_HEAD(&pcpu->deferred_reenq_user.node);
@@ -5066,8 +5071,11 @@ static void exit_dsq(struct scx_dispatch_q *dsq)
{
s32 cpu;
+ if (!dsq->pcpu_user)
+ return;
+
for_each_possible_cpu(cpu) {
- struct scx_dsq_pcpu *pcpu = per_cpu_ptr(dsq->pcpu, cpu);
+ struct scx_dsq_pcpu *pcpu = per_cpu_ptr(dsq->pcpu_user, cpu);
struct scx_deferred_reenq_user *dru = &pcpu->deferred_reenq_user;
struct rq *rq = cpu_rq(cpu);
@@ -5081,7 +5089,7 @@ static void exit_dsq(struct scx_dispatch_q *dsq)
}
}
- free_percpu(dsq->pcpu);
+ free_percpu(dsq->pcpu_user);
}
static void free_dsq_rcufn(struct rcu_head *rcu)
--
2.43.0