* [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys
@ 2025-04-08 23:06 Tejun Heo
2025-04-08 23:06 ` [PATCH 1/5] sched_ext: Indentation updates Tejun Heo
` (6 more replies)
0 siblings, 7 replies; 11+ messages in thread
From: Tejun Heo @ 2025-04-08 23:06 UTC (permalink / raw)
To: void, arighi, multics69; +Cc: linux-kernel, sched-ext
sched_ext uses static_keys to optimize branches on ops flags and which ops
are implemented. Some of those branches aren't that hot and while others are
hotter, they are unlikely to cause meaningful overhead difference given
everything else that's going on. static_keys were used more because there
was no reason not to use static_keys. However, the planned multiple
hierarchical scheduler support won't work with global static_keys as these
branches would have to be based on the specific ops instance.
This patchset replaces static_key usages with tests on ops.flags and a
bitmap tracking which operation is implemented. I couldn't see performance
difference in numerous hackbench runs on a Ryzen 3990x machine before and
after the patchset.
This patchset contains the following five patches:
0001-sched_ext-Indentation-updates.patch
0002-sched_ext-Remove-scx_ops_enq_-static_keys.patch
0003-sched_ext-Remove-scx_ops_cpu_preempt-static_key.patch
0004-sched_ext-Remove-scx_ops_allow_queued_wakeup-static_.patch
0005-sched_ext-Make-scx_has_op-a-bitmap.patch
and is also available in the following git branch:
git://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext.git scx-remove-static_keys
diffstat follows. Thanks.
kernel/sched/ext.c | 91 +++++++++++++++++++++++------------------------------
kernel/sched/ext.h | 8 ----
2 files changed, 42 insertions(+), 57 deletions(-)
--
tejun
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/5] sched_ext: Indentation updates
2025-04-08 23:06 [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Tejun Heo
@ 2025-04-08 23:06 ` Tejun Heo
2025-04-08 23:06 ` [PATCH 2/5] sched_ext: Remove scx_ops_enq_* static_keys Tejun Heo
` (5 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Tejun Heo @ 2025-04-08 23:06 UTC (permalink / raw)
To: void, arighi, multics69; +Cc: linux-kernel, sched-ext, Tejun Heo
Purely cosmetic.
Signed-off-by: Tejun Heo <tj@kernel.org>
---
kernel/sched/ext.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 3cc5d7b5e3a9..022343518f99 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -163,16 +163,16 @@ enum scx_ops_flags {
/*
* CPU cgroup support flags
*/
- SCX_OPS_HAS_CGROUP_WEIGHT = 1LLU << 16, /* DEPRECATED, will be removed on 6.18 */
-
- SCX_OPS_ALL_FLAGS = SCX_OPS_KEEP_BUILTIN_IDLE |
- SCX_OPS_ENQ_LAST |
- SCX_OPS_ENQ_EXITING |
- SCX_OPS_ENQ_MIGRATION_DISABLED |
- SCX_OPS_ALLOW_QUEUED_WAKEUP |
- SCX_OPS_SWITCH_PARTIAL |
- SCX_OPS_BUILTIN_IDLE_PER_NODE |
- SCX_OPS_HAS_CGROUP_WEIGHT,
+ SCX_OPS_HAS_CGROUP_WEIGHT = 1LLU << 16, /* DEPRECATED, will be removed on 6.18 */
+
+ SCX_OPS_ALL_FLAGS = SCX_OPS_KEEP_BUILTIN_IDLE |
+ SCX_OPS_ENQ_LAST |
+ SCX_OPS_ENQ_EXITING |
+ SCX_OPS_ENQ_MIGRATION_DISABLED |
+ SCX_OPS_ALLOW_QUEUED_WAKEUP |
+ SCX_OPS_SWITCH_PARTIAL |
+ SCX_OPS_BUILTIN_IDLE_PER_NODE |
+ SCX_OPS_HAS_CGROUP_WEIGHT,
};
/* argument container for ops.init_task() */
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/5] sched_ext: Remove scx_ops_enq_* static_keys
2025-04-08 23:06 [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Tejun Heo
2025-04-08 23:06 ` [PATCH 1/5] sched_ext: Indentation updates Tejun Heo
@ 2025-04-08 23:06 ` Tejun Heo
2025-04-08 23:06 ` [PATCH 3/5] sched_ext: Remove scx_ops_cpu_preempt static_key Tejun Heo
` (4 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Tejun Heo @ 2025-04-08 23:06 UTC (permalink / raw)
To: void, arighi, multics69; +Cc: linux-kernel, sched-ext, Tejun Heo
scx_ops_enq_last/exiting/migration_disabled are used to encode the
corresponding SCX_OPS_ flags into static_keys. These flags aren't hot enough
for static_key usage to make any meaningful difference and are made
static_keys mostly because there was no reason not to. However, global
static_keys can't work with the planned hierarchical multiple scheduler
support. Remove the static_keys and test the ops flags directly.
In repeated hackbench runs before and after static_keys removal on an AMD
Ryzen 3900X, I couldn't tell any measurable performance difference.
Signed-off-by: Tejun Heo <tj@kernel.org>
---
kernel/sched/ext.c | 22 +++++-----------------
1 file changed, 5 insertions(+), 17 deletions(-)
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 022343518f99..1e685e77b5e4 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -924,9 +924,6 @@ static struct sched_ext_ops scx_ops;
static bool scx_warned_zero_slice;
DEFINE_STATIC_KEY_FALSE(scx_ops_allow_queued_wakeup);
-static DEFINE_STATIC_KEY_FALSE(scx_ops_enq_last);
-static DEFINE_STATIC_KEY_FALSE(scx_ops_enq_exiting);
-static DEFINE_STATIC_KEY_FALSE(scx_ops_enq_migration_disabled);
static DEFINE_STATIC_KEY_FALSE(scx_ops_cpu_preempt);
static struct static_key_false scx_has_op[SCX_OPI_END] =
@@ -2144,14 +2141,14 @@ static void do_enqueue_task(struct rq *rq, struct task_struct *p, u64 enq_flags,
goto direct;
/* see %SCX_OPS_ENQ_EXITING */
- if (!static_branch_unlikely(&scx_ops_enq_exiting) &&
+ if (!(scx_ops.flags & SCX_OPS_ENQ_EXITING) &&
unlikely(p->flags & PF_EXITING)) {
__scx_add_event(SCX_EV_ENQ_SKIP_EXITING, 1);
goto local;
}
/* see %SCX_OPS_ENQ_MIGRATION_DISABLED */
- if (!static_branch_unlikely(&scx_ops_enq_migration_disabled) &&
+ if (!(scx_ops.flags & SCX_OPS_ENQ_MIGRATION_DISABLED) &&
is_migration_disabled(p)) {
__scx_add_event(SCX_EV_ENQ_SKIP_MIGRATION_DISABLED, 1);
goto local;
@@ -3022,8 +3019,8 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
* Didn't find another task to run. Keep running @prev unless
* %SCX_OPS_ENQ_LAST is in effect.
*/
- if (prev_on_rq && (!static_branch_unlikely(&scx_ops_enq_last) ||
- scx_rq_bypassing(rq))) {
+ if (prev_on_rq &&
+ (!(scx_ops.flags & SCX_OPS_ENQ_LAST) || scx_rq_bypassing(rq))) {
rq->scx.flags |= SCX_RQ_BAL_KEEP;
__scx_add_event(SCX_EV_DISPATCH_KEEP_LAST, 1);
goto has_tasks;
@@ -3228,7 +3225,7 @@ static void put_prev_task_scx(struct rq *rq, struct task_struct *p,
* which should trigger an explicit follow-up scheduling event.
*/
if (sched_class_above(&ext_sched_class, next->sched_class)) {
- WARN_ON_ONCE(!static_branch_unlikely(&scx_ops_enq_last));
+ WARN_ON_ONCE(!(scx_ops.flags & SCX_OPS_ENQ_LAST));
do_enqueue_task(rq, p, SCX_ENQ_LAST, -1);
} else {
do_enqueue_task(rq, p, 0, -1);
@@ -4728,9 +4725,6 @@ static void scx_disable_workfn(struct kthread_work *work)
for (i = SCX_OPI_BEGIN; i < SCX_OPI_END; i++)
static_branch_disable(&scx_has_op[i]);
static_branch_disable(&scx_ops_allow_queued_wakeup);
- static_branch_disable(&scx_ops_enq_last);
- static_branch_disable(&scx_ops_enq_exiting);
- static_branch_disable(&scx_ops_enq_migration_disabled);
static_branch_disable(&scx_ops_cpu_preempt);
scx_idle_disable();
synchronize_rcu();
@@ -5372,12 +5366,6 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
if (ops->flags & SCX_OPS_ALLOW_QUEUED_WAKEUP)
static_branch_enable(&scx_ops_allow_queued_wakeup);
- if (ops->flags & SCX_OPS_ENQ_LAST)
- static_branch_enable(&scx_ops_enq_last);
- if (ops->flags & SCX_OPS_ENQ_EXITING)
- static_branch_enable(&scx_ops_enq_exiting);
- if (ops->flags & SCX_OPS_ENQ_MIGRATION_DISABLED)
- static_branch_enable(&scx_ops_enq_migration_disabled);
if (scx_ops.cpu_acquire || scx_ops.cpu_release)
static_branch_enable(&scx_ops_cpu_preempt);
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/5] sched_ext: Remove scx_ops_cpu_preempt static_key
2025-04-08 23:06 [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Tejun Heo
2025-04-08 23:06 ` [PATCH 1/5] sched_ext: Indentation updates Tejun Heo
2025-04-08 23:06 ` [PATCH 2/5] sched_ext: Remove scx_ops_enq_* static_keys Tejun Heo
@ 2025-04-08 23:06 ` Tejun Heo
2025-04-08 23:06 ` [PATCH 4/5] sched_ext: Remove scx_ops_allow_queued_wakeup static_key Tejun Heo
` (3 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Tejun Heo @ 2025-04-08 23:06 UTC (permalink / raw)
To: void, arighi, multics69; +Cc: linux-kernel, sched-ext, Tejun Heo
scx_ops_cpu_preempt is used to encode whether ops.cpu_acquire/release() are
implemented into a static_key. These tests aren't hot enough for static_key
usage to make any meaningful difference and are made to use a static_key
mostly because there was no reason not to. However, global static_keys can't
work with the planned hierarchical multiple scheduler support. Remove the
static_key and instead use an internal ops flag SCX_OPS_HAS_CPU_PREEMPT to
record and test whether ops.cpu_acquire/release() are implemented.
In repeated hackbench runs before and after static_keys removal on an AMD
Ryzen 3900X, I couldn't tell any measurable performance difference.
Signed-off-by: Tejun Heo <tj@kernel.org>
---
kernel/sched/ext.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 1e685e77b5e4..1adf5c299cce 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -173,6 +173,11 @@ enum scx_ops_flags {
SCX_OPS_SWITCH_PARTIAL |
SCX_OPS_BUILTIN_IDLE_PER_NODE |
SCX_OPS_HAS_CGROUP_WEIGHT,
+
+ /* high 8 bits are internal, don't include in SCX_OPS_ALL_FLAGS */
+ __SCX_OPS_INTERNAL_MASK = 0xffLLU << 56,
+
+ SCX_OPS_HAS_CPU_PREEMPT = 1LLU << 56,
};
/* argument container for ops.init_task() */
@@ -924,7 +929,6 @@ static struct sched_ext_ops scx_ops;
static bool scx_warned_zero_slice;
DEFINE_STATIC_KEY_FALSE(scx_ops_allow_queued_wakeup);
-static DEFINE_STATIC_KEY_FALSE(scx_ops_cpu_preempt);
static struct static_key_false scx_has_op[SCX_OPI_END] =
{ [0 ... SCX_OPI_END-1] = STATIC_KEY_FALSE_INIT };
@@ -2931,7 +2935,7 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
rq->scx.flags |= SCX_RQ_IN_BALANCE;
rq->scx.flags &= ~(SCX_RQ_BAL_PENDING | SCX_RQ_BAL_KEEP);
- if (static_branch_unlikely(&scx_ops_cpu_preempt) &&
+ if ((scx_ops.flags & SCX_OPS_HAS_CPU_PREEMPT) &&
unlikely(rq->scx.cpu_released)) {
/*
* If the previous sched_class for the current CPU was not SCX,
@@ -3160,7 +3164,7 @@ static void switch_class(struct rq *rq, struct task_struct *next)
*/
smp_store_release(&rq->scx.pnt_seq, rq->scx.pnt_seq + 1);
#endif
- if (!static_branch_unlikely(&scx_ops_cpu_preempt))
+ if (!(scx_ops.flags & SCX_OPS_HAS_CPU_PREEMPT))
return;
/*
@@ -4725,7 +4729,6 @@ static void scx_disable_workfn(struct kthread_work *work)
for (i = SCX_OPI_BEGIN; i < SCX_OPI_END; i++)
static_branch_disable(&scx_has_op[i]);
static_branch_disable(&scx_ops_allow_queued_wakeup);
- static_branch_disable(&scx_ops_cpu_preempt);
scx_idle_disable();
synchronize_rcu();
@@ -5367,7 +5370,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
if (ops->flags & SCX_OPS_ALLOW_QUEUED_WAKEUP)
static_branch_enable(&scx_ops_allow_queued_wakeup);
if (scx_ops.cpu_acquire || scx_ops.cpu_release)
- static_branch_enable(&scx_ops_cpu_preempt);
+ scx_ops.flags |= SCX_OPS_HAS_CPU_PREEMPT;
/*
* Lock out forks, cgroup on/offlining and moves before opening the
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/5] sched_ext: Remove scx_ops_allow_queued_wakeup static_key
2025-04-08 23:06 [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Tejun Heo
` (2 preceding siblings ...)
2025-04-08 23:06 ` [PATCH 3/5] sched_ext: Remove scx_ops_cpu_preempt static_key Tejun Heo
@ 2025-04-08 23:06 ` Tejun Heo
2025-04-08 23:06 ` [PATCH 5/5] sched_ext: Make scx_has_op a bitmap Tejun Heo
` (2 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Tejun Heo @ 2025-04-08 23:06 UTC (permalink / raw)
To: void, arighi, multics69; +Cc: linux-kernel, sched-ext, Tejun Heo
scx_ops_allow_queued_wakeup is used to encode SCX_OPS_ALLOW_QUEUED_WAKEUP
into a static_key. The test is gated behind scx_enabled(), and, even when
sched_ext is enabled, is unlikely for the static_key usage to make any
meaningful difference. It is made to use a static_key mostly because there
was no reason not to. However, global static_keys can't work with the
planned hierarchical multiple scheduler support. Remove the static_key and
instead test SCX_OPS_ALLOW_QUEUED_WAKEUP directly.
In repeated hackbench runs before and after static_keys removal on an AMD
Ryzen 3900X, I couldn't tell any measurable performance difference.
Signed-off-by: Tejun Heo <tj@kernel.org>
---
kernel/sched/ext.c | 12 +++++++-----
kernel/sched/ext.h | 8 +-------
2 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 1adf5c299cce..f0ed0cec4c98 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -928,8 +928,6 @@ DEFINE_STATIC_KEY_FALSE(__scx_switched_all);
static struct sched_ext_ops scx_ops;
static bool scx_warned_zero_slice;
-DEFINE_STATIC_KEY_FALSE(scx_ops_allow_queued_wakeup);
-
static struct static_key_false scx_has_op[SCX_OPI_END] =
{ [0 ... SCX_OPI_END-1] = STATIC_KEY_FALSE_INIT };
@@ -4414,6 +4412,13 @@ bool task_should_scx(int policy)
return policy == SCHED_EXT;
}
+bool scx_allow_ttwu_queue(const struct task_struct *p)
+{
+ return !scx_enabled() ||
+ (scx_ops.flags & SCX_OPS_ALLOW_QUEUED_WAKEUP) ||
+ p->sched_class != &ext_sched_class;
+}
+
/**
* scx_softlockup - sched_ext softlockup handler
* @dur_s: number of seconds of CPU stuck due to soft lockup
@@ -4728,7 +4733,6 @@ static void scx_disable_workfn(struct kthread_work *work)
static_branch_disable(&__scx_enabled);
for (i = SCX_OPI_BEGIN; i < SCX_OPI_END; i++)
static_branch_disable(&scx_has_op[i]);
- static_branch_disable(&scx_ops_allow_queued_wakeup);
scx_idle_disable();
synchronize_rcu();
@@ -5367,8 +5371,6 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
if (((void (**)(void))ops)[i])
static_branch_enable(&scx_has_op[i]);
- if (ops->flags & SCX_OPS_ALLOW_QUEUED_WAKEUP)
- static_branch_enable(&scx_ops_allow_queued_wakeup);
if (scx_ops.cpu_acquire || scx_ops.cpu_release)
scx_ops.flags |= SCX_OPS_HAS_CPU_PREEMPT;
diff --git a/kernel/sched/ext.h b/kernel/sched/ext.h
index 1bda96b19a1b..3053cdd61eb9 100644
--- a/kernel/sched/ext.h
+++ b/kernel/sched/ext.h
@@ -21,6 +21,7 @@ void scx_rq_activate(struct rq *rq);
void scx_rq_deactivate(struct rq *rq);
int scx_check_setscheduler(struct task_struct *p, int policy);
bool task_should_scx(int policy);
+bool scx_allow_ttwu_queue(const struct task_struct *p);
void init_sched_ext_class(void);
static inline u32 scx_cpuperf_target(s32 cpu)
@@ -36,13 +37,6 @@ static inline bool task_on_scx(const struct task_struct *p)
return scx_enabled() && p->sched_class == &ext_sched_class;
}
-static inline bool scx_allow_ttwu_queue(const struct task_struct *p)
-{
- return !scx_enabled() ||
- static_branch_likely(&scx_ops_allow_queued_wakeup) ||
- p->sched_class != &ext_sched_class;
-}
-
#ifdef CONFIG_SCHED_CORE
bool scx_prio_less(const struct task_struct *a, const struct task_struct *b,
bool in_fi);
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 5/5] sched_ext: Make scx_has_op a bitmap
2025-04-08 23:06 [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Tejun Heo
` (3 preceding siblings ...)
2025-04-08 23:06 ` [PATCH 4/5] sched_ext: Remove scx_ops_allow_queued_wakeup static_key Tejun Heo
@ 2025-04-08 23:06 ` Tejun Heo
2025-04-09 7:57 ` Andrea Righi
2025-04-09 1:37 ` [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Changwoo Min
2025-04-09 19:06 ` Tejun Heo
6 siblings, 1 reply; 11+ messages in thread
From: Tejun Heo @ 2025-04-08 23:06 UTC (permalink / raw)
To: void, arighi, multics69; +Cc: linux-kernel, sched-ext, Tejun Heo
scx_has_op is used to encode which ops are implemented by the BPF scheduler
into an array of static_keys. While this saves a bit of branching overhead,
that is unlikely to be noticeable compared to the overall cost. As the
global static_keys can't work with the planned hierarchical multiple
scheduler support, replace the static_key array with a bitmap.
In repeated hackbench runs before and after static_keys removal on an AMD
Ryzen 3900X, I couldn't tell any measurable performance difference.
Signed-off-by: Tejun Heo <tj@kernel.org>
---
kernel/sched/ext.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index f0ed0cec4c98..8ae85ec6d9a2 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -928,8 +928,7 @@ DEFINE_STATIC_KEY_FALSE(__scx_switched_all);
static struct sched_ext_ops scx_ops;
static bool scx_warned_zero_slice;
-static struct static_key_false scx_has_op[SCX_OPI_END] =
- { [0 ... SCX_OPI_END-1] = STATIC_KEY_FALSE_INIT };
+static DECLARE_BITMAP(scx_has_op, SCX_OPI_END);
static atomic_t scx_exit_kind = ATOMIC_INIT(SCX_EXIT_DONE);
static struct scx_exit_info *scx_exit_info;
@@ -1055,7 +1054,7 @@ static __printf(3, 4) void __scx_exit(enum scx_exit_kind kind, s64 exit_code,
#define scx_error(fmt, args...) \
__scx_error(SCX_EXIT_ERROR, fmt, ##args)
-#define SCX_HAS_OP(op) static_branch_likely(&scx_has_op[SCX_OP_IDX(op)])
+#define SCX_HAS_OP(op) test_bit(SCX_OP_IDX(op), scx_has_op)
static long jiffies_delta_msecs(unsigned long at, unsigned long now)
{
@@ -1774,7 +1773,7 @@ static void touch_core_sched_dispatch(struct rq *rq, struct task_struct *p)
lockdep_assert_rq_held(rq);
#ifdef CONFIG_SCHED_CORE
- if (SCX_HAS_OP(core_sched_before))
+ if (unlikely(SCX_HAS_OP(core_sched_before)))
touch_core_sched(rq, p);
#endif
}
@@ -2156,7 +2155,7 @@ static void do_enqueue_task(struct rq *rq, struct task_struct *p, u64 enq_flags,
goto local;
}
- if (!SCX_HAS_OP(enqueue))
+ if (unlikely(!SCX_HAS_OP(enqueue)))
goto global;
/* DSQ bypass didn't trigger, enqueue on the BPF scheduler */
@@ -2972,7 +2971,7 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
if (consume_global_dsq(rq))
goto has_tasks;
- if (!SCX_HAS_OP(dispatch) || scx_rq_bypassing(rq) || !scx_rq_online(rq))
+ if (unlikely(!SCX_HAS_OP(dispatch)) || scx_rq_bypassing(rq) || !scx_rq_online(rq))
goto no_tasks;
dspc->rq = rq;
@@ -3373,7 +3372,7 @@ static int select_task_rq_scx(struct task_struct *p, int prev_cpu, int wake_flag
return prev_cpu;
rq_bypass = scx_rq_bypassing(task_rq(p));
- if (SCX_HAS_OP(select_cpu) && !rq_bypass) {
+ if (likely(SCX_HAS_OP(select_cpu)) && !rq_bypass) {
s32 cpu;
struct task_struct **ddsp_taskp;
@@ -4638,7 +4637,7 @@ static void scx_disable_workfn(struct kthread_work *work)
struct task_struct *p;
struct rhashtable_iter rht_iter;
struct scx_dispatch_q *dsq;
- int i, kind, cpu;
+ int kind, cpu;
kind = atomic_read(&scx_exit_kind);
while (true) {
@@ -4731,8 +4730,7 @@ static void scx_disable_workfn(struct kthread_work *work)
/* no task is on scx, turn off all the switches and flush in-progress calls */
static_branch_disable(&__scx_enabled);
- for (i = SCX_OPI_BEGIN; i < SCX_OPI_END; i++)
- static_branch_disable(&scx_has_op[i]);
+ bitmap_zero(scx_has_op, SCX_OPI_END);
scx_idle_disable();
synchronize_rcu();
@@ -5328,7 +5326,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
for (i = SCX_OPI_CPU_HOTPLUG_BEGIN; i < SCX_OPI_CPU_HOTPLUG_END; i++)
if (((void (**)(void))ops)[i])
- static_branch_enable_cpuslocked(&scx_has_op[i]);
+ set_bit(i, scx_has_op);
check_hotplug_seq(ops);
scx_idle_update_selcpu_topology(ops);
@@ -5369,7 +5367,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
for (i = SCX_OPI_NORMAL_BEGIN; i < SCX_OPI_NORMAL_END; i++)
if (((void (**)(void))ops)[i])
- static_branch_enable(&scx_has_op[i]);
+ set_bit(i, scx_has_op);
if (scx_ops.cpu_acquire || scx_ops.cpu_release)
scx_ops.flags |= SCX_OPS_HAS_CPU_PREEMPT;
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys
2025-04-08 23:06 [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Tejun Heo
` (4 preceding siblings ...)
2025-04-08 23:06 ` [PATCH 5/5] sched_ext: Make scx_has_op a bitmap Tejun Heo
@ 2025-04-09 1:37 ` Changwoo Min
2025-04-09 19:06 ` Tejun Heo
6 siblings, 0 replies; 11+ messages in thread
From: Changwoo Min @ 2025-04-09 1:37 UTC (permalink / raw)
To: Tejun Heo, void, arighi, Changwoo Min; +Cc: linux-kernel, sched-ext
Hi Tejun,
Thank you for the cleanup. Looks good to me.
Acked-by: Changwoo Min <changwoo@igalia.com>
Regards,
Changwoo Min
On 4/9/25 08:06, Tejun Heo wrote:
> sched_ext uses static_keys to optimize branches on ops flags and which ops
> are implemented. Some of those branches aren't that hot and while others are
> hotter, they are unlikely to cause meaningful overhead difference given
> everything else that's going on. static_keys were used more because there
> was no reason not to use static_keys. However, the planned multiple
> hierarchical scheduler support won't work with global static_keys as these
> branches would have to be based on the specific ops instance.
>
> This patchset replaces static_key usages with tests on ops.flags and a
> bitmap tracking which operation is implemented. I couldn't see performance
> difference in numerous hackbench runs on a Ryzen 3990x machine before and
> after the patchset.
>
> This patchset contains the following five patches:
>
> 0001-sched_ext-Indentation-updates.patch
> 0002-sched_ext-Remove-scx_ops_enq_-static_keys.patch
> 0003-sched_ext-Remove-scx_ops_cpu_preempt-static_key.patch
> 0004-sched_ext-Remove-scx_ops_allow_queued_wakeup-static_.patch
> 0005-sched_ext-Make-scx_has_op-a-bitmap.patch
>
> and is also available in the following git branch:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext.git scx-remove-static_keys
>
> diffstat follows. Thanks.
>
> kernel/sched/ext.c | 91 +++++++++++++++++++++++------------------------------
> kernel/sched/ext.h | 8 ----
> 2 files changed, 42 insertions(+), 57 deletions(-)
>
> --
> tejun
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 5/5] sched_ext: Make scx_has_op a bitmap
2025-04-08 23:06 ` [PATCH 5/5] sched_ext: Make scx_has_op a bitmap Tejun Heo
@ 2025-04-09 7:57 ` Andrea Righi
2025-04-09 18:51 ` Tejun Heo
0 siblings, 1 reply; 11+ messages in thread
From: Andrea Righi @ 2025-04-09 7:57 UTC (permalink / raw)
To: Tejun Heo; +Cc: void, multics69, linux-kernel, sched-ext
On Tue, Apr 08, 2025 at 01:06:05PM -1000, Tejun Heo wrote:
> scx_has_op is used to encode which ops are implemented by the BPF scheduler
> into an array of static_keys. While this saves a bit of branching overhead,
> that is unlikely to be noticeable compared to the overall cost. As the
> global static_keys can't work with the planned hierarchical multiple
> scheduler support, replace the static_key array with a bitmap.
>
> In repeated hackbench runs before and after static_keys removal on an AMD
> Ryzen 3900X, I couldn't tell any measurable performance difference.
At this point I'm wondering if we should just do something like:
#define SCX_HAS_OP(op) (scx_ops.op != NULL)
Do you think the bitmap can provide some measurable benefits? For the most
frequently used hot paths (enqueue, dispatch, select_cpu, running,
stopping) we likely have to fetch scx_ops.op anyway, so cache-wise the
difference should be minimal.
Thanks,
-Andrea
>
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---
> kernel/sched/ext.c | 22 ++++++++++------------
> 1 file changed, 10 insertions(+), 12 deletions(-)
>
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index f0ed0cec4c98..8ae85ec6d9a2 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -928,8 +928,7 @@ DEFINE_STATIC_KEY_FALSE(__scx_switched_all);
> static struct sched_ext_ops scx_ops;
> static bool scx_warned_zero_slice;
>
> -static struct static_key_false scx_has_op[SCX_OPI_END] =
> - { [0 ... SCX_OPI_END-1] = STATIC_KEY_FALSE_INIT };
> +static DECLARE_BITMAP(scx_has_op, SCX_OPI_END);
>
> static atomic_t scx_exit_kind = ATOMIC_INIT(SCX_EXIT_DONE);
> static struct scx_exit_info *scx_exit_info;
> @@ -1055,7 +1054,7 @@ static __printf(3, 4) void __scx_exit(enum scx_exit_kind kind, s64 exit_code,
> #define scx_error(fmt, args...) \
> __scx_error(SCX_EXIT_ERROR, fmt, ##args)
>
> -#define SCX_HAS_OP(op) static_branch_likely(&scx_has_op[SCX_OP_IDX(op)])
> +#define SCX_HAS_OP(op) test_bit(SCX_OP_IDX(op), scx_has_op)
>
> static long jiffies_delta_msecs(unsigned long at, unsigned long now)
> {
> @@ -1774,7 +1773,7 @@ static void touch_core_sched_dispatch(struct rq *rq, struct task_struct *p)
> lockdep_assert_rq_held(rq);
>
> #ifdef CONFIG_SCHED_CORE
> - if (SCX_HAS_OP(core_sched_before))
> + if (unlikely(SCX_HAS_OP(core_sched_before)))
> touch_core_sched(rq, p);
> #endif
> }
> @@ -2156,7 +2155,7 @@ static void do_enqueue_task(struct rq *rq, struct task_struct *p, u64 enq_flags,
> goto local;
> }
>
> - if (!SCX_HAS_OP(enqueue))
> + if (unlikely(!SCX_HAS_OP(enqueue)))
> goto global;
>
> /* DSQ bypass didn't trigger, enqueue on the BPF scheduler */
> @@ -2972,7 +2971,7 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
> if (consume_global_dsq(rq))
> goto has_tasks;
>
> - if (!SCX_HAS_OP(dispatch) || scx_rq_bypassing(rq) || !scx_rq_online(rq))
> + if (unlikely(!SCX_HAS_OP(dispatch)) || scx_rq_bypassing(rq) || !scx_rq_online(rq))
> goto no_tasks;
>
> dspc->rq = rq;
> @@ -3373,7 +3372,7 @@ static int select_task_rq_scx(struct task_struct *p, int prev_cpu, int wake_flag
> return prev_cpu;
>
> rq_bypass = scx_rq_bypassing(task_rq(p));
> - if (SCX_HAS_OP(select_cpu) && !rq_bypass) {
> + if (likely(SCX_HAS_OP(select_cpu)) && !rq_bypass) {
> s32 cpu;
> struct task_struct **ddsp_taskp;
>
> @@ -4638,7 +4637,7 @@ static void scx_disable_workfn(struct kthread_work *work)
> struct task_struct *p;
> struct rhashtable_iter rht_iter;
> struct scx_dispatch_q *dsq;
> - int i, kind, cpu;
> + int kind, cpu;
>
> kind = atomic_read(&scx_exit_kind);
> while (true) {
> @@ -4731,8 +4730,7 @@ static void scx_disable_workfn(struct kthread_work *work)
>
> /* no task is on scx, turn off all the switches and flush in-progress calls */
> static_branch_disable(&__scx_enabled);
> - for (i = SCX_OPI_BEGIN; i < SCX_OPI_END; i++)
> - static_branch_disable(&scx_has_op[i]);
> + bitmap_zero(scx_has_op, SCX_OPI_END);
> scx_idle_disable();
> synchronize_rcu();
>
> @@ -5328,7 +5326,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
>
> for (i = SCX_OPI_CPU_HOTPLUG_BEGIN; i < SCX_OPI_CPU_HOTPLUG_END; i++)
> if (((void (**)(void))ops)[i])
> - static_branch_enable_cpuslocked(&scx_has_op[i]);
> + set_bit(i, scx_has_op);
>
> check_hotplug_seq(ops);
> scx_idle_update_selcpu_topology(ops);
> @@ -5369,7 +5367,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
>
> for (i = SCX_OPI_NORMAL_BEGIN; i < SCX_OPI_NORMAL_END; i++)
> if (((void (**)(void))ops)[i])
> - static_branch_enable(&scx_has_op[i]);
> + set_bit(i, scx_has_op);
>
> if (scx_ops.cpu_acquire || scx_ops.cpu_release)
> scx_ops.flags |= SCX_OPS_HAS_CPU_PREEMPT;
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 5/5] sched_ext: Make scx_has_op a bitmap
2025-04-09 7:57 ` Andrea Righi
@ 2025-04-09 18:51 ` Tejun Heo
2025-04-09 18:58 ` Andrea Righi
0 siblings, 1 reply; 11+ messages in thread
From: Tejun Heo @ 2025-04-09 18:51 UTC (permalink / raw)
To: Andrea Righi; +Cc: void, multics69, linux-kernel, sched-ext
Hello,
On Wed, Apr 09, 2025 at 09:57:59AM +0200, Andrea Righi wrote:
> On Tue, Apr 08, 2025 at 01:06:05PM -1000, Tejun Heo wrote:
> > scx_has_op is used to encode which ops are implemented by the BPF scheduler
> > into an array of static_keys. While this saves a bit of branching overhead,
> > that is unlikely to be noticeable compared to the overall cost. As the
> > global static_keys can't work with the planned hierarchical multiple
> > scheduler support, replace the static_key array with a bitmap.
> >
> > In repeated hackbench runs before and after static_keys removal on an AMD
> > Ryzen 3900X, I couldn't tell any measurable performance difference.
>
> At this point I'm wondering if we should just do something like:
>
> #define SCX_HAS_OP(op) (scx_ops.op != NULL)
>
> Do you think the bitmap can provide some measurable benefits? For the most
> frequently used hot paths (enqueue, dispatch, select_cpu, running,
> stopping) we likely have to fetch scx_ops.op anyway, so cache-wise the
> difference should be minimal.
Performance-wise, unlikely. However, we need to be able to enable ops in
stages during init - CPU hotplug ops need to be enabled before other ops. We
can do that by setting the op pointers in stages but the code was already
structured in a way which is easy to convert to bitmap, so that was the path
of least resistance. We surely can change it.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 5/5] sched_ext: Make scx_has_op a bitmap
2025-04-09 18:51 ` Tejun Heo
@ 2025-04-09 18:58 ` Andrea Righi
0 siblings, 0 replies; 11+ messages in thread
From: Andrea Righi @ 2025-04-09 18:58 UTC (permalink / raw)
To: Tejun Heo; +Cc: void, multics69, linux-kernel, sched-ext
On Wed, Apr 09, 2025 at 08:51:24AM -1000, Tejun Heo wrote:
> Hello,
>
> On Wed, Apr 09, 2025 at 09:57:59AM +0200, Andrea Righi wrote:
> > On Tue, Apr 08, 2025 at 01:06:05PM -1000, Tejun Heo wrote:
> > > scx_has_op is used to encode which ops are implemented by the BPF scheduler
> > > into an array of static_keys. While this saves a bit of branching overhead,
> > > that is unlikely to be noticeable compared to the overall cost. As the
> > > global static_keys can't work with the planned hierarchical multiple
> > > scheduler support, replace the static_key array with a bitmap.
> > >
> > > In repeated hackbench runs before and after static_keys removal on an AMD
> > > Ryzen 3900X, I couldn't tell any measurable performance difference.
> >
> > At this point I'm wondering if we should just do something like:
> >
> > #define SCX_HAS_OP(op) (scx_ops.op != NULL)
> >
> > Do you think the bitmap can provide some measurable benefits? For the most
> > frequently used hot paths (enqueue, dispatch, select_cpu, running,
> > stopping) we likely have to fetch scx_ops.op anyway, so cache-wise the
> > difference should be minimal.
>
> Performance-wise, unlikely. However, we need to be able to enable ops in
> stages during init - CPU hotplug ops need to be enabled before other ops. We
> can do that by setting the op pointers in stages but the code was already
> structured in a way which is easy to convert to bitmap, so that was the path
> of least resistance. We surely can change it.
Ah good point about the init stages. In that case, I agree that it's safer
to introduce the bitmap for now and, later, we can refactor the code to use
pointers if we want. Thanks for the clarification.
Acked-by: Andrea Righi <arighi@nvidia.com>
-Andrea
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys
2025-04-08 23:06 [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Tejun Heo
` (5 preceding siblings ...)
2025-04-09 1:37 ` [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Changwoo Min
@ 2025-04-09 19:06 ` Tejun Heo
6 siblings, 0 replies; 11+ messages in thread
From: Tejun Heo @ 2025-04-09 19:06 UTC (permalink / raw)
To: void, arighi, multics69; +Cc: linux-kernel, sched-ext
On Tue, Apr 08, 2025 at 01:06:00PM -1000, Tejun Heo wrote:
> sched_ext uses static_keys to optimize branches on ops flags and which ops
> are implemented. Some of those branches aren't that hot and while others are
> hotter, they are unlikely to cause meaningful overhead difference given
> everything else that's going on. static_keys were used more because there
> was no reason not to use static_keys. However, the planned multiple
> hierarchical scheduler support won't work with global static_keys as these
> branches would have to be based on the specific ops instance.
>
> This patchset replaces static_key usages with tests on ops.flags and a
> bitmap tracking which operation is implemented. I couldn't see performance
> difference in numerous hackbench runs on a Ryzen 3990x machine before and
> after the patchset.
>
> This patchset contains the following five patches:
>
> 0001-sched_ext-Indentation-updates.patch
> 0002-sched_ext-Remove-scx_ops_enq_-static_keys.patch
> 0003-sched_ext-Remove-scx_ops_cpu_preempt-static_key.patch
> 0004-sched_ext-Remove-scx_ops_allow_queued_wakeup-static_.patch
> 0005-sched_ext-Make-scx_has_op-a-bitmap.patch
Applied to sched_ext/for-6.16.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-04-09 19:06 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-08 23:06 [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Tejun Heo
2025-04-08 23:06 ` [PATCH 1/5] sched_ext: Indentation updates Tejun Heo
2025-04-08 23:06 ` [PATCH 2/5] sched_ext: Remove scx_ops_enq_* static_keys Tejun Heo
2025-04-08 23:06 ` [PATCH 3/5] sched_ext: Remove scx_ops_cpu_preempt static_key Tejun Heo
2025-04-08 23:06 ` [PATCH 4/5] sched_ext: Remove scx_ops_allow_queued_wakeup static_key Tejun Heo
2025-04-08 23:06 ` [PATCH 5/5] sched_ext: Make scx_has_op a bitmap Tejun Heo
2025-04-09 7:57 ` Andrea Righi
2025-04-09 18:51 ` Tejun Heo
2025-04-09 18:58 ` Andrea Righi
2025-04-09 1:37 ` [PATCHSET sched_ext/for-6.16] sched_ext: Reduce usage of static_keys Changwoo Min
2025-04-09 19:06 ` Tejun Heo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox