Re: [PATCH 2/2] evl/sched/quota: Correct budget tracking for preempted threads
Philippe Gerum <[email protected]> Mon, 15 Jun 2026 10:47:00 +0200
| Newsgroups | dev.linux.lists.xenomai |
|---|---|
| Message-ID | <[email protected]> |
Jan Kiszka <[email protected]> writes: > From: Jan Kiszka <[email protected]> > > This was so far not possible due to a missing sched_class callback, > causing threads being credited for the preemption time of threads from > higher-weighted classes. > > Signed-off-by: Jan Kiszka <[email protected]> > --- > kernel/evl/sched/quota.c | 56 +++++++++++++++++++++++++++++----------- > 1 file changed, 41 insertions(+), 15 deletions(-) > > diff --git a/kernel/evl/sched/quota.c b/kernel/evl/sched/quota.c > index 0829da711a66a..d331dc2e8f7ac 100644 > --- a/kernel/evl/sched/quota.c > +++ b/kernel/evl/sched/quota.c > @@ -187,11 +187,28 @@ static void quota_refill_handler(struct evl_timer *timer) /* oob stage stalled * > raw_spin_unlock(&rq->lock); > } > > +static void charge_usage(struct evl_quota_group *tg, ktime_t now) > +{ > + ktime_t elapsed; > + > + elapsed = ktime_sub(now, tg->run_start); > + if (elapsed < tg->run_budget) > + tg->run_budget = ktime_sub(tg->run_budget, elapsed); > + else > + tg->run_budget = 0; > +} > + > static void quota_limit_handler(struct evl_timer *timer) /* oob stage stalled */ > { > + struct evl_quota_group *tg; > struct evl_rq *rq; > > rq = container_of(timer, struct evl_rq, quota.limit_timer); > + > + tg = rq->curr->quota; > + if (tg) > + charge_usage(tg, evl_ktime_monotonic()); > + > /* > * Force a rescheduling on the return path of the current > * interrupt, so that the budget is re-evaluated for the > @@ -253,6 +270,8 @@ static bool quota_setparam(struct evl_thread *thread, > /* Dequeued earlier by our caller. */ > list_del(&thread->quota_next); > thread->quota->nr_threads--; > + } else if (thread == evl_current()) { > + tg->run_start = evl_ktime_monotonic(); > } > thread->quota = tg; > list_add(&thread->quota_next, &tg->members); > @@ -400,21 +419,11 @@ static struct evl_thread *quota_pick(struct evl_rq *rq) > struct evl_thread *next, *curr = rq->curr; > struct evl_sched_quota *qs = &rq->quota; > struct evl_quota_group *otg, *tg; > - ktime_t now, elapsed; > + ktime_t now; > > now = evl_ktime_monotonic(); > otg = curr->quota; > - if (otg == NULL) > - goto pick; > - /* > - * Charge the time consumed by the outgoing thread to the > - * group it belongs to. > - */ > - elapsed = ktime_sub(now, otg->run_start); > - if (elapsed < otg->run_budget) > - otg->run_budget = ktime_sub(otg->run_budget, elapsed); > - else > - otg->run_budget = 0; > + > pick: > next = evl_get_schedq(&rq->fifo.runnable); > if (next == NULL) { > @@ -430,8 +439,6 @@ static struct evl_thread *quota_pick(struct evl_rq *rq) > if (tg == NULL) > return next; > > - tg->run_start = now; > - > /* > * Don't consider budget if kicked, we have to allow this > * thread to run until it eventually switches to in-band > @@ -448,9 +455,12 @@ static struct evl_thread *quota_pick(struct evl_rq *rq) > goto pick; > } > > - if (otg == tg && evl_timer_is_running(&qs->limit_timer)) > + if (otg != tg) { > + tg->run_start = now; > + } else if (evl_timer_is_running(&qs->limit_timer)) { > /* Same group, leave the running timer untouched. */ > goto out; > + } > > /* Arm limit timer for the new running group. */ > evl_start_timer(&qs->limit_timer, > @@ -462,6 +472,21 @@ static struct evl_thread *quota_pick(struct evl_rq *rq) > return next; > } > > +static void quota_out(struct evl_thread *thread, struct evl_thread *next) > +{ > + struct evl_quota_group *otg = thread->quota; > + struct evl_quota_group *ntg = next->quota; > + ktime_t now; > + > + if (otg && otg != ntg) { otg can't be NULL by construction since quota_out() is called for thread->sched_class. -- Philippe.