Re: [PATCH 1/2] evl/sched: Add sched_out handler to sched_class
Jan Kiszka <[email protected]> Mon, 15 Jun 2026 12:24:40 +0200
| Newsgroups | dev.linux.lists.xenomai |
|---|---|
| Message-ID | <[email protected]> |
On 15.06.26 11:59, Philippe Gerum wrote: > Jan Kiszka <[email protected]> writes: > >> On 15.06.26 08:42, Philippe Gerum wrote: >>> Philippe Gerum <[email protected]> writes: >>> >> >> You also need to update tg->run_start. Otherwise, you will overcharge >> the next time this group is checked here. >> > > Yes, this needs fixing. > >>> + } else { >>> + tg->run_budget = 0; >>> + evl_stop_timer(&qs->limit_timer); >>> + } >>> +} >>> + >>> +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 *tg; >>> + >>> pick: >>> - next = evl_get_schedq(&rq->fifo.runnable); >>> + next = evl_get_schedq(&qs->runnable); >>> if (next == NULL) { >>> evl_stop_timer(&qs->limit_timer); >>> return NULL; >>> } >>> >>> - /* >>> - * As we basically piggyback on the SCHED_FIFO runqueue, make >>> - * sure to detect non-quota threads. >>> - */ >>> tg = next->quota; >>> - if (tg == NULL) >>> - return next; >>> - >>> - tg->run_start = now; >>> + tg->nr_active--; >>> >>> /* >>> * Don't consider budget if kicked, we have to allow this >>> @@ -439,25 +437,29 @@ static struct evl_thread *quota_pick(struct evl_rq *rq) >>> */ >>> if (next->info & EVL_T_KICKED) { >>> evl_stop_timer(&qs->limit_timer); >>> - goto out; >>> + return next; >>> } >>> >>> + /* >>> + * __pick_next_thread() might have requeued the current >>> + * thread which is still leading the pack. >>> + */ >>> + if (curr == next) >>> + return next; >>> + >>> if (ktime_to_ns(tg->run_budget) == 0) { >>> - /* Flush expired group members as we go. */ >>> + /* Park expired group members as we go. */ >>> list_add_tail(&next->quota_expired, &tg->expired); >>> goto pick; >>> } >>> >>> - if (otg == tg && 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, >>> - ktime_add(now, tg->run_budget), >>> - EVL_INFINITE); >>> -out: >>> - tg->nr_active--; >>> + /* Arm new limit timer on change of running group. */ >>> + if (curr->quota != tg || !evl_timer_is_running(&qs->limit_timer)) { >>> + tg->run_start = evl_ktime_monotonic(); >>> + evl_start_timer(&qs->limit_timer, >>> + ktime_add(tg->run_start, tg->run_budget), >>> + EVL_INFINITE); >>> + } >> >> I still don't fully get how the limit timer should be started on >> setparam over the current thread. Will curr be NULL in that case, thus >> curr != next? Is that the reason to go for a separate runqueue? >> > > Nope, that one is only to make things clearer, since there is no upside > in sharing the runqueues (this was inherited from SCHED_SPORADIC for no > obvious reason with hindsight). At some point, I noticed that it would > even have introduced a bug in a previous tentative implementation using > sched_class as a discriminator between threads, to figure out whether we > should call the sched_out() handler. So, the simpler, the better: > distinct classes, distinct runqueues. > > Regarding the limit timer issue, sched_pick() should not shortcut on > curr == next. IOW, the rest of the code should run even in this case. By > turning on the resched bit (which the quota_setparam() caller does), we > would end up in sched_pick() with either of those outcomes out of > quota_setparam(): > > - 'current' switched group, in which case we would arm a limit timer in > sched_pick() because curr->quota != next->quota (provided the shortcut > on curr == next is gone). > > - 'current' stays in the same group, so the limit timer still runs unless > the budget was already fully consumed. > Makes sense, now. > So I would revise my latest patch as follows: > > diff --git a/kernel/evl/sched/quota.c b/kernel/evl/sched/quota.c > index 3ac650c08ccb..8f1321d46cac 100644 > --- a/kernel/evl/sched/quota.c > +++ b/kernel/evl/sched/quota.c > @@ -407,6 +407,7 @@ static void quota_out(struct evl_thread *thread) > now = evl_ktime_monotonic(); > consumed = ktime_sub(now, tg->run_start); > if (consumed < tg->run_budget) { > + tg->run_start = now; > tg->run_budget = ktime_sub(tg->run_budget, consumed); > } else { > tg->run_budget = 0; > @@ -440,20 +441,13 @@ static struct evl_thread *quota_pick(struct evl_rq *rq) > return next; > } > > - /* > - * __pick_next_thread() might have requeued the current > - * thread which is still leading the pack. > - */ > - if (curr == next) > - return next; > - > if (ktime_to_ns(tg->run_budget) == 0) { > /* Park expired group members as we go. */ > list_add_tail(&next->quota_expired, &tg->expired); > goto pick; > } > > - /* Arm new limit timer on change of running group. */ > + /* Arm new limit timer if need be. */ > if (curr->quota != tg || !evl_timer_is_running(&qs->limit_timer)) { > tg->run_start = evl_ktime_monotonic(); > evl_start_timer(&qs->limit_timer, > >> >> Looks ok otherwise, tests pass as well. >> > > Uh? Ok. That was absolutely unintentional at this stage! > Tests aren't perfect either: sched-quota was "tested" before, and my current proposal apparently missed the corner-cases we just discussed above. Jan -- Siemens AG, Foundational Technologies Linux Expert Center