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

Re: [Xen-devel] [PATCH v7]xen: sched: convert RTDS from time to event driven model



On Wed, Mar 9, 2016 at 10:46 AM, Dario Faggioli
<dario.faggioli@xxxxxxxxxx> wrote:
> On Tue, 2016-03-08 at 23:33 -0500, Meng Xu wrote:
>> I didn't mark out all repeated style issues. I think you can correct
>> all of the style issues, such as the spaces in the code, in the next
>> version.
>>
> Yes, please. At v7, style issues shouldn't definitely be there any
> longer.
>
> Have another look at CODING_STYLE, perhaps, especially focusing on
> spaces in conditional expressions and line length.

Tianyang, please correct those coding styles in next version. Now it's
time to pay more attention to coding style...

>
>> Hi Dario,
>> Could you help check if my two concerns in the comments below make
>> sense?
>> One is small, about if we should use () to make the code clearer.
>> The other is about the logic in the replenishment handler.
>>
> I think tickling during replenishment does have issues, yes. See below.
>
> Anyway, Meng, can you trim your quotes when replying? By this, I mean
> cut the part of conversation/patches that are not relevant for what you
> are saying in this very email (but leave enough context in place for
> making what you want to point out understandable).

Sure.. Got it.

>> > @@ -1150,6 +1276,71 @@ rt_dom_cntl(
>> >      return rc;
>> >  }
>> >
>> > +/*
>> > + * The replenishment timer handler picks vcpus
>> > + * from the replq and does the actual replenishment.
>> > + */
>> > +static void repl_handler(void *data){
>> > +    unsigned long flags;
>> > +    s_time_t now = NOW();
>> > +    struct scheduler *ops = data;
>> > +    struct rt_private *prv = rt_priv(ops);
>> > +    struct list_head *replq = rt_replq(ops);
>> > +    struct timer *repl_timer = prv->repl_timer;
>> > +    struct list_head *iter, *tmp;
>> > +    struct rt_vcpu *svc = NULL;
>> > +
>> > +    spin_lock_irqsave(&prv->lock, flags);
>> > +
>> > +    stop_timer(repl_timer);
>> > +
>> > +    list_for_each_safe(iter, tmp, replq)
>> > +    {
>> > +        svc = replq_elem(iter);
>> > +
>> > +        if ( now < svc->cur_deadline )
>> > +            break;
>> > +
>> > +        rt_update_deadline(now, svc);
>> > +
>> > +        /*
>> > +         * when the replenishment happens
>> > +         * svc is either on a pcpu or on
>> > +         * runq/depletedq
>> > +         */
>> > +        if( __vcpu_on_q(svc) )
>> > +        {
>> > +            /* put back to runq */
>> > +            __q_remove(svc);
>> > +            __runq_insert(ops, svc);
>> > +        }
>> > +
>> > +        /*
>> > +         * tickle regardless where it's at
>> > +         * because a running vcpu could have
>> > +         * a later deadline than others after
>> > +         * replenishment
>> > +         */
>> > +        runq_tickle(ops, svc);
>> Well, I'm thinking about the correctness of tickle here.
>> The svc is running on a core, say P_i, right now. After replenishing
>> the budget for svc, svc's deadline also changes. So svc  should
>> probably be preempted by the head vcpu in the runq. If that's the
>> case, we should use the head of runq to tickle, instead of using svc.
>> Right?
>>
> I agree that, in case of replenishment of a running vcpu, calling
> runq_tickle() like this is not correct. In fact, the whole idea of
> tickling in Credit1 and 2, from which it has been borrowed to here, was
> meant at (potentially) putting a vcpu in execution, not vice versa. :-/
>
> I therefore agree that, if svc ends up with a later deadline than the
> first vcpu in the runque, we should actually call run_tickle() on the
> latter!
>
>> Actually, is the runq_tickle necessary here? Can we just check if the
>> updated svc has higher priority (smaller deadline) than the head vcpu
>> in the runq? If so, we just tickle the cpu P_i, where svc is
>> currently
>> running on.
>>
> Well, if we are replenishing a vcpu that is depleted, whose new
> deadline can be earlier than any of the ones of the vcpus that are
> running (can't it?) and/or there can be idle vcpus on which you can run
> it, now that it has budget. So, in this case, I think we need what's
> done in runq_tickle()...
>
> The third case is that we replenish a vcpu that is in the runqueue, so
> it had budget, but was not running. In that case, there should be no
> chance that it should preempt a running vcpu, as it was waiting in the
> runqueue, which means --if we have M pcpus-- it was not among the M
> earliest deadline vcpus, and we just pushed its deadline away!
> It should also not be necessary to do any deadline comparison with
> other vcpus in the runqueue. In fact, still considering that we are
> moving the deadline ahead, it's going to either be in the same or
> "worst" position in the runqueue.
>
>> But either way, I'm thinking the logic here is incorrect. If the
>> updated svc has a lower priority, you will end up tickle no core
>> although the svc should be preempted.
>>
> It seems to me that the logic here could be (sort-of):
>
>   for_each_to_be_replenished_vcpu(v)
>   {
>     deadline_queue_remove(replq, v);
>     rt_update_deadline(v);
>
>     if ( curr_on_cpu(v->processor) == v)) //running
>     {
>         if ( v->cur_deadline >= runq[0]->cur_deadline )
>           tickle(runq[0]); /* runq[0] => first vcpu in the runq */
>     }
>     else if ( __vcpu_on_q(v) )
>     {
>         if ( v->cur_budget == 0 )         //depleted
>           tickle(v);
>         else                              //runnable
>           /* do nothing */
>     }
>     deadline_queue_insert(v, replq);
>   }
>
> Thoughts?

I like the logic here. But there is one thing to note/change.

After we run rt_update_deadline(v), the v->cur_deadline will be set to
v->budget, which means that we cannot use the v->cur_deadline to
determine if it is in runq or depletedq.

I suggest to have a flag to determine if the v is in depletedq by
v->cur_budget == 0 first before we run rt_update_deadline(v); and use
the flag later.

>
> I actually think there may be room for a nasty race, in case we do more
> than one replenishments.
>
> In fact, assume that, at time t:
>  - we do the replenishment of v1, which is running and v2, which is
>    runnable,
>  - we have 1 cpu,
>  - v1 and v2 have, currently, the same deadline == t,
>  - v1's new deadline is going to be t+100, and v2's new deadline is
>    going to be t+150,
>  - v2 is the only (i.e., also the first) runnable vcpu,
>  - v1's replenishment event comes first in the replenishment queue.
>
> With the code above, we update v1's deadline (to t+100), go check it
> against v2's _not_updated_ deadline (t) and (since t+100 > t) find that
> a preemption is necessary, so we call tickle(v2). That will raise
> SCHEDULE_SOFTIRQ for the cpu, because v2 should --as far as situation
> is right now-- preempt v1.
>
> However, right after that, we update v2's deadline to t+150, and we do
> nothing. So, even if the vcpu with the earliest deadline (v1) is
> running, we reschedule.

Hmm, I kind of get what you want to deliver with the example here. I agree.
I will just summarize what I understand here:
When we replenish VCPU one by one and tickle them one by one, we may
end up use a to-be-updated vcpu to tickle, which will probably be
"kicked out" by the next to-be-updated vcpu.

The rt_schedule will probably do a noop for the to-be-updated vcpu
since it can tell this vcpu actually misses deadline (because this
vcpu is about to update the deadline, it means this vcpu just
reaches/passed the current deadline.)

>
> This should be harmless, as we do figure out during rt_schedule() that
> no real context switch is necessary, but I think it would better be
> avoided, if possible.
Right
.

>
> It looks to me that we can re-arrange the code above as follows:
>
>   for_each_to_be_replenished_vcpu(v)
>   {
>     rt_update_deadline(v);
>   }

we have to record the number of VCPUs that has updated their deadline,
so that we know when to stop for the next loop..
>
>   for_each_to_be_replenished_vcpu(v)
>   {
>     deadline_queue_remove(replq, v);
>
>     if ( curr_on_cpu(v->processor) == v)) //running
>     {
>         if ( v->cur_deadline >= runq[0]->cur_deadline )
>           tickle(runq[0]); /* runq[0] => first vcpu in the runq */
>     }
>     else if ( __vcpu_on_q(v) )
>     {
>         if ( v->cur_budget == 0 )         //depleted
>           tickle(v);
>         else                              //runnable
>           /* do nothing */
>     }
>     deadline_queue_insert(v, replq);
>   }
>
> Basically, by doing all the replenishments (which includes updating all
> the deadlines) upfront, we should be able to prevent the above
> situation.
>
> So, again, thoughts?

I think we need to decide which vcpu is on depleted q before update
deadline and we also need to record which vcpus should be updated. So
I added some code into your code:

#define __RTDS_is_depleted     3
#define RTDS_is_depleted  (1<<__RTDS_is_depleted)


int num_repl_vcpus = 0;
 for_each_to_be_replenished_vcpu(v)
 {
   if (v->cur_budget <= 0)
       set_bit(__RTDS_is_depleted, &v->flags);

    rt_update_deadline(v);
    num_repl_vcpus++;
 }

  for_each_to_be_replenished_vcpu(v)
  {
    deadline_queue_remove(replq, v);

    if ( curr_on_cpu(v->processor) == v)) //running
    {
        if ( v->cur_deadline >= runq[0]->cur_deadline )
          tickle(runq[0]); /* runq[0] => first vcpu in the runq */
    }
    else if ( __vcpu_on_q(v) )
    {
        if ( v->flags & RTDS_is_depleted )         //depleted
        {
          clear_bit(__RTDS_is_depleted, &v->flags);
          tickle(v);
        }
        else                              //runnable
          /* do nothing */
    }
    deadline_queue_insert(v, replq);

    /* stop at the vcpu that does not need replenishment */
    num_repl_vcpus--;
    if (!num_repl_vcpus)
        break;
 }

What do you think this version?

Thanks and Best Regards,

Meng

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

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