sched_ext: Count kicks denied for lacking baseline cid access

kick_one_cpu() silently skips a kick when the kicking sub-sched lacks
SCX_CAP_BASE on the target cid, as does kick_one_cpu_if_idle() for idle
kicks. The skips are sound with the same logic as the reenq gate but are
invisible today, unlike the preempt degradation counted in
SCX_EV_SUB_PREEMPT_DENIED. Count them in a new SCX_EV_SUB_KICK_DENIED event
so every cap denial is observable.

Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
This commit is contained in:
Tejun Heo 2026-07-24 09:09:28 -10:00
parent f879519db8
commit 7c80408fa9
2 changed files with 22 additions and 6 deletions

View File

@ -8118,6 +8118,7 @@ static bool kick_one_cpu(s32 cpu, struct scx_sched_pcpu *pcpu, struct rq *this_r
struct scx_rq *this_scx = &this_rq->scx;
const struct sched_class *cur_class;
bool should_wait = false;
bool kickable;
unsigned long flags;
raw_spin_rq_lock_irqsave(rq, flags);
@ -8131,9 +8132,10 @@ static bool kick_one_cpu(s32 cpu, struct scx_sched_pcpu *pcpu, struct rq *this_r
* business forcing a reschedule there - skip. This is the authoritative
* cap check: ecaps is read here under @rq's lock.
*/
if ((cpu_online(cpu) || cpu == cpu_of(this_rq)) &&
!sched_class_above(cur_class, &ext_sched_class) &&
!scx_missing_caps(pcpu->sch, cpu, SCX_CAP_BASE)) {
kickable = (cpu_online(cpu) || cpu == cpu_of(this_rq)) &&
!sched_class_above(cur_class, &ext_sched_class);
if (kickable && !scx_missing_caps(pcpu->sch, cpu, SCX_CAP_BASE)) {
if (cpumask_test_cpu(cpu, pcpu->cpus_to_preempt)) {
if (cur_class == &ext_sched_class) {
if (likely(!scx_missing_caps(pcpu->sch, cpu,
@ -8157,6 +8159,9 @@ static bool kick_one_cpu(s32 cpu, struct scx_sched_pcpu *pcpu, struct rq *this_r
resched_curr(rq);
} else {
/* a kickable cpu was skipped solely for the missing caps */
if (kickable)
__scx_add_event(pcpu->sch, SCX_EV_SUB_KICK_DENIED, 1);
cpumask_clear_cpu(cpu, pcpu->cpus_to_preempt);
cpumask_clear_cpu(cpu, pcpu->cpus_to_wait);
}
@ -8176,9 +8181,12 @@ static void kick_one_cpu_if_idle(s32 cpu, struct scx_sched_pcpu *pcpu,
/* idle kicks need baseline access too, see kick_one_cpu() */
if (!can_skip_idle_kick(rq) &&
(cpu_online(cpu) || cpu == cpu_of(this_rq)) &&
!scx_missing_caps(pcpu->sch, cpu, SCX_CAP_BASE))
resched_curr(rq);
(cpu_online(cpu) || cpu == cpu_of(this_rq))) {
if (likely(!scx_missing_caps(pcpu->sch, cpu, SCX_CAP_BASE)))
resched_curr(rq);
else
__scx_add_event(pcpu->sch, SCX_EV_SUB_KICK_DENIED, 1);
}
raw_spin_rq_unlock_irqrestore(rq, flags);
}

View File

@ -1194,6 +1194,13 @@ struct scx_event_stats {
*/
s64 SCX_EV_SUB_PREEMPT_DENIED;
/*
* The number of times a kick was skipped because the sub-sched lacked
* baseline access on the target cid. The preempt-part degradation of a
* delivered kick is counted in SCX_EV_SUB_PREEMPT_DENIED instead.
*/
s64 SCX_EV_SUB_KICK_DENIED;
/*
* The number of times a local DSQ reenq was dropped because the
* sub-sched lacked baseline access on the target cid.
@ -1219,6 +1226,7 @@ struct scx_event_stats {
SCX_EVENT(SCX_EV_SUB_BYPASS_DISPATCH); \
SCX_EVENT(SCX_EV_SUB_FORCED_ADMIT); \
SCX_EVENT(SCX_EV_SUB_PREEMPT_DENIED); \
SCX_EVENT(SCX_EV_SUB_KICK_DENIED); \
SCX_EVENT(SCX_EV_SUB_REENQ_DENIED)
struct scx_sched;