[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 1/5] xen/sched: rtds: add global-EDF utilization admission control



On 9/14/26 12:10, Juergen Gross wrote:
> On 26.08.26 06:57, Furkan Caliskan wrote:
>> RTDS has no admission control: nothing stops the sum of all admitted
>> units' (budget/period) reservations in a cpupool from exceeding
>> what its pCPUs can actually provide. Once that happens, none of the
>> EDF deadline guarantees this scheduler is built around still hold
>> for the units sharing that pool.
>>
>> Introduce admission control to prevent this: reject a reservation
>> whenever admitting it would push a cpupool's units over its capacity.
>> Track a running utilization total per cpupool, and enforce it in
>> rt_alloc_udata()/rt_free_udata(), the paired lifecycle hooks for a
>> unit's creation and destruction. This catches the default
>> period/budget every new unit gets.
>>
>> Utilization is represented as a fixed-point value: budget is
>> left shifted by RTDS_UTIL_SHIFT (20 bits) and divided by period.
>> A plain "(budget << RTDS_UTIL_SHIFT) / period" risks overflowing
>> the multiply for large enough budgets. Rather than widen the
>> arithmetic to tolerate any input, the input itself is bounded:
>> rt_validate_params() rejects any budget above RTDS_MAX_BUDGET,
>> chosen as the largest value that can be left-shifted by
>> RTDS_UTIL_SHIFT without overflowing 64 bits, so the shift in
>> rt_unit_utilization() can never overflow.
>>
>> A cpupool's capacity rt_utilization_cap() scales with the number of
>> scheduling resources in it. It is calculated as:
>> (number of sched_resources * RTDS_UTIL_SCALE * RTDS_UTIL_CAP_PCT / 100),
>> where RTDS_UTIL_CAP_PCT controls how much of that capacity can
>> actually be reserved; at 100% (its current value), all of it can be.
>>
>> Signed-off-by: Furkan Caliskan <frn1furkan10@xxxxxxxxx>
>> ---
>>   xen/common/sched/rt.c | 105 +++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 104 insertions(+), 1 deletion(-)
>>
>> diff --git a/xen/common/sched/rt.c b/xen/common/sched/rt.c
>> index 0e9f04ea72..9126320801 100644
>> --- a/xen/common/sched/rt.c
>> +++ b/xen/common/sched/rt.c
>> @@ -114,6 +114,24 @@
>>    */
>>   #define RTDS_MAX_PRIORITY_LEVEL (~0U)
>>   +/*
>> + * Fixed-point scale for utilization (budget/period)
>> + */
>> +#define RTDS_UTIL_SHIFT     20
>> +#define RTDS_UTIL_SCALE     (1ULL << RTDS_UTIL_SHIFT)
>> +
>> +/*
>> + * Largest budget safe to left-shift by RTDS_UTIL_SHIFT without
>> + * overflowing 64 bits. Enforced in rt_validate_params().
>> + */
>> +#define RTDS_MAX_BUDGET_BITS  (64 - RTDS_UTIL_SHIFT)
>> +#define RTDS_MAX_BUDGET       ((1ULL << RTDS_MAX_BUDGET_BITS) - 1)
>> +
>> +/*
>> + * % of a cpupool's sched_resource capacity admitted units may sum up to.
>> + */
>> +#define RTDS_UTIL_CAP_PCT   100
>> +
>>   /*
>>    * UPDATE_LIMIT_SHIFT: a constant used in rt_update_deadline(). When 
>> finding
>>    * the next deadline, performing addition could be faster if the difference
>> @@ -195,6 +213,9 @@ struct rt_private {
>>       struct list_head replq;     /* ordered list of units that need 
>> replenishment */
>>         cpumask_t tickled;          /* cpus been tickled */
>> +
>> +    /* Sum of admitted units' (budget/period), scaled by RTDS_UTIL_SCALE */
>> +    uint64_t utilization;
>>   };
>>     /*
>> @@ -635,6 +656,54 @@ replq_reinsert(const struct scheduler *ops, struct 
>> rt_unit *svc)
>>           set_timer(&rt_priv(ops)->repl_timer, rearm_svc->cur_deadline);
>>   }
>>   +/*
>> + * budget << RTDS_UTIL_SHIFT can't overflow: rt_validate_params()
>> + * caps budget at RTDS_MAX_BUDGET. period == 0 means "no
>> + * reservation" (a unit being removed), not an error.
>> + */
>> +static uint64_t
>> +rt_unit_utilization(s_time_t period, s_time_t budget)
>> +{
>> +    if ( period <= 0 )
>> +        return 0;
>> +
>> +    return ((uint64_t)budget << RTDS_UTIL_SHIFT) / (uint64_t)period;
>> +}
>> +
>> +/*
>> + * Utilization capacity of the cpupool domain d resides in.
>> + */
>> +static uint64_t
>> +rt_utilization_cap(const struct domain *d)
>> +{
>> +    unsigned int cpus = cpumask_weight(cpupool_domain_master_cpumask(d));
>> +
>> +    return (uint64_t)cpus * RTDS_UTIL_SCALE * RTDS_UTIL_CAP_PCT / 100;
>> +}
>> +
>> +/*
>> + * Replaces a unit's reservation and updates prv->utilization
>> + * to match. Growth that would push utilization over the
>> + * cpupool's cap is refused. Removing a unit or shrinking
>> + * a unit's reservation always succeed.
>> + */
>> +static int
>> +rt_admission_test(struct rt_private *prv, const struct domain *d,
>> +           s_time_t old_period, s_time_t old_budget,
>> +           s_time_t new_period, s_time_t new_budget)
> 
> I think the function name isn't appropriate. The function doesn't test only, 
> it
> is setting the utilization, too.
> 
> What about rt_try_set_utilization() instead? And make the return type bool
> (true on success).
> 

Okay, I'll change the name in v2. And the return type too.

>> +{
>> +    uint64_t old_util = rt_unit_utilization(old_period, old_budget);
>> +    uint64_t new_util = rt_unit_utilization(new_period, new_budget);
>> +    uint64_t total    = prv->utilization - old_util + new_util;
>> +
>> +    if ( new_util > old_util && total > rt_utilization_cap(d) )
>> +        return -EINVAL;
>> +
>> +    prv->utilization = total;
>> +
>> +    return 0;
>> +}
>> +
>>   /*
>>    * Pick a valid resource for the unit vc
>>    * Valid resource of an unit is intesection of unit's affinity
>> @@ -864,6 +933,7 @@ rt_free_domdata(const struct scheduler *ops, void *data)
>>   static void * cf_check
>>   rt_alloc_udata(const struct scheduler *ops, struct sched_unit *unit, void 
>> *dd)
>>   {
>> +    struct rt_private *prv = rt_priv(ops);
>>       struct rt_unit *svc;
>>         /* Allocate per-UNIT info */
>> @@ -881,9 +951,30 @@ rt_alloc_udata(const struct scheduler *ops, struct 
>> sched_unit *unit, void *dd)
>>       __set_bit(__RTDS_extratime, &svc->flags);
>>       svc->priority_level = 0;
>>       svc->period = RTDS_DEFAULT_PERIOD;
>> +
>>       if ( !is_idle_unit(unit) )
>> +    {
>> +        unsigned long flags;
>> +        int rc;
>> +
>>           svc->budget = RTDS_DEFAULT_BUDGET;
>>   +        spin_lock_irqsave(&prv->lock, flags);
>> +        rc = rt_admission_test(prv, unit->domain, 0, 0,
>> +                                svc->period, svc->budget);
>> +        spin_unlock_irqrestore(&prv->lock, flags);
>> +
>> +        if ( rc )
>> +        {
>> +            printk(XENLOG_WARNING
>> +                   "RTDS: ADMISSION CONTROL: refusing unit %u of d%d,"
>> +                   " would exceed utilization capacity of the cpupool\n",
>> +                   unit->unit_id, unit->domain->domain_id);
>> +            xfree(svc);
>> +            return NULL;
>> +        }
>> +    }
>> +
>>       SCHED_STAT_CRANK(unit_alloc);
>>         return svc;
>> @@ -892,8 +983,19 @@ rt_alloc_udata(const struct scheduler *ops, struct 
>> sched_unit *unit, void *dd)
>>   static void cf_check
>>   rt_free_udata(const struct scheduler *ops, void *priv)
>>   {
>> +    struct rt_private *prv = rt_priv(ops);
>>       struct rt_unit *svc = priv;
>>   +    if ( svc && !is_idle_unit(svc->unit) )
>> +    {
>> +        unsigned long flags;
>> +
>> +        spin_lock_irqsave(&prv->lock, flags);
>> +        rt_admission_test(prv, svc->unit->domain,
>> +                           svc->period, svc->budget, 0, 0);
> 
> This use case clearly shows you are not only testing. :-)
> 
>> +        spin_unlock_irqrestore(&prv->lock, flags);
>> +    }
>> +
>>       xfree(svc);
>>   }
>>   @@ -1389,7 +1491,8 @@ rt_validate_params(const struct 
>> xen_domctl_sched_rtds *rtds,
>>       s_time_t b = MICROSECS(rtds->budget);
>>         if ( p < RTDS_MIN_PERIOD || p > RTDS_MAX_PERIOD ||
>> -         b < RTDS_MIN_BUDGET || b > p )
>> +         b < RTDS_MIN_BUDGET || b > p ||
>> +         b > (s_time_t)RTDS_MAX_BUDGET )
>>           return -EINVAL;
>>         *period = p;
> 
> 
> Juergen
> 

Thanks,

Furkan



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.