This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: round-robin behaviour of MLQ wrt particular prioritylevel


Thanks Nick and Andrew,

I guess, i shouldn't be even more careful before posting at the end of an intense day, couple of silly mistakes in misreading/understanding the sources. :(

priority threads. When the higher priority thread gets blocked and the
lower priority thread gets to run again, it makes more sense to
continue running the thread that was descheduled since it more likely
there is something useful in the cache for this thread. The next
thread in the queue has been sleeping for longer so its more likely
its data in the cache has been flushed.
Am i right in vaguely remembering some discussion to similar effect, on the list, in past?

I find this idea bit biased, when there are other threads of same priority, ready to run . This descheduled thread would end up enjoying more than a fair share of processor time, more than it's timeslice.

However, as i gather from Nick's reply and further looking at insert, this won't be happening. new thread goes at the end of runqueue for corresponding priority level.

Here is the problem that lead me here (the mail is quite detailed as i am trying to elucidate the problem to make it possible for others to provide some pointers into it, marked with ****).

In a test setup, we had a single processor build with two threads (T1, T2) at same high priority and one idle thread as usual.

T2 was application thread running at priority 1. in test setup it did a cyg_thread_delay for 0-3 ticks and incremented a counter.

T1 was thread added to runqueue to handle an event rising from an interrupt. it also ran at priority 1.

when appropriate interrupt came, it posted a dsr, that woke up thread T1. T1 finished the task and went to sleep again, till next time it is woken up. before sleeping it sent some indications of having finished the task and incremented a counter. only after this indication interrupt was generated again by external-to-ecos source.

In simple test setup, T1 executed cyg_thread_delay on (same throughout) data that it was made available via some global location.

When that data (value it passed for cyg_thred_delay) was made as 0, it resulted in quite high interrupt rate for getting T1 to service the request.

In this scenario, T2 was getting starved (it managed to increment it's counter once in very long time), **** even when it was doing a delay for 0 ticks. ****

On the contrary counter for T1 was incrementing very fast.

On investigation it was found that by the time T1 entered unlock_inner (with new_lock as 0) in the process of it's sleeping, a DSR was posted to wake it up. since this DSR was processed, somehow that caused T1 to continue running again.

An initial solution for this was found out by doing following in T1 -

lock scheduler (this locking was needed as we didn't want to be scheduled out during sending the notification)
sleep
disable interrupt +++++ (new interrupt to request T1 back won't come before T1 is taken off)
send notification of having finished the job
unlock scheduler
restore interrupts +++++


a later solution was tried

lock scheduler
sleep
send notification of having finished the job
reschedule (so that DSRs are not processed and T1 is taken off)
unlock scheduler

i am still not happy about if second solution being better than first, as it would end up executing more code for more or less same things, as it looks now.

**** ANY opinions on which one would be better?? Though I guess, better would change depending upon the exact application/needs.

What is not clear to me - T1 and T2 are same priority, and T2 is almost starved even when it is doing a cyg_thread_delay for 0 units and incrementing a counter. since timeslice for T1 should get over often and T2 should get chance often??

here is my preliminary effort in solving the mystery, any constructive and helpful comments would be useful --

0. DSR pertaining to waking up T1 was getting processed, that woke up
   the outgoing T1.
1. T1 changed state to RUNNING (wake() in thread.cxx)
2. T1 was added to (tail of) runqueue for it's priority level.
   (add_thread() in mlqueue.cxx)
3. set_need_reschedule (mlqueue.cxx) is called from add_thread.
   In current case current_thread and thread (argument to this function) are
   same, hence both the conditions evaluate to false leading to
   need_reschedule not set to true.

   if( current_thread[0]->priority > thread->priority ||
          current_thread[0]->get_state() != Cyg_Thread::RUNNING )
          need_reschedule[0] = true;

**** did designers expect current_thread to be same as thread in above ??
**** should need_reschedule[0] be set to true for (current_thread == thread) case (compare for equality)? if there is no thread at it's priority level, it will continue anyways. but what if some thread was waiting in runqueue, it might endup waiting for long.


4. This caused following conditon in unlock_inner() to evaluate
   to false, leading to no switching actions.

if( current->state != Cyg_Thread::RUNNING || get_need_reschedule() )

It looks like some race condition b/w processing the RealTimeClock DSR and DSR for waking up T1.
If RTC DSR gets processed later and T2 is in runqueue, switching (T1->T2)would happen, otherwise not. but in either case timeslice count will be reset.


**** however if it doesn't happen, conditon mentioned in 4 above evaluates to false, T1 continues to run and on next RTC dsr processing during T1's execution, T1 gets a very huge timeslice for it, because of following code in timeslice (mlqueue.cxx). after this T2 should forget about getting a chance to run.

    if( --timeslice_count[CYG_KERNEL_CPU_THIS()] == 0 )
         timeslice_cpu();

timeslice_count being a cyg_ucount32 variable.

possibly if check for 0 was done before decrement or it were a signed type and checks were for >0, things would be different. but i don't expect public ecos repository to take care of every such situation arising from a very fast interrupt scenario as happened in testsetup i worked on.

hope the problem, investigation and questions proves useful for some other folks too.

sandeep


-- Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]