v5.3.1 Starved Tasks

rtel wrote on Friday, July 03, 2009:

I’m quite confused by some of the statements in this thread.  The CPU provides a certain amount of power - either it is fast enough to run the user task and the comms tasks or it isn’t. 

Using a kernel adds an overhead in that there is a tick interrupt, but can also save a whole lot of CPU cycles by allowing your application to be completely event driven - any cycles that would otherwise be spent polling are freed for other processing.  On balance whether you get more or less grunt from using a kernel depends on the application, but generally on a well designed event driven system you will get more processing done with the kernel.

If the user task must run "as fast as possible" then this is a really soft real time requirement, as it means it does not need to run at all if its impossible for it to get CPU processing. 

If on the other hand it needs to run whenever an event occurs then you need to specify how often the event can occur, and what the response time must be along with how long it would take in the worst case to respond to the event.

If on yet another hand it needs to run at a certain frequency then you need to say what that frequency is.

If the required execution frequency is in the KHz range then I would suggest using a port that implements efficient interrupt nesting.  For example any of the Cortex M3 ports.  Some of the M3 demos run a 20KHz timer in an interrupt that has a priority above the priority used by the kernel (note here I’m talking about interrupt priorities, not task priorities).  That works just fine.  The tasks then run whenever the interrupt is not running.

If the required frequency is in the 10’s of ms then a scheme whereby a task runs periodically using vTaskDelayUntil() might be a simpler solution.

Regards.

enginayd wrote on Friday, July 03, 2009:

Third solution suggests adjusting the rate of task. Is there such a thing ? Or do you mean rate of the hardware timer interrupt ?

This is what I mean by complex stuff btw.

To make such a measurement I’d need a hardware timer to keep track of the time in micro seconds. Do-able.

I started to embrace dynamically adjusting timer frequency.

Hardware timers are perfect for many many things. Only problem it has is the fixed frequency rate was inefficient for small programs.

Tasks are good, as it will automagically adopt itself to best performance. But it turned out that I cannot let other processes to run for a very short period of time, that is due to time resolution of systick which is 1khz at the moment, and even that is considered very high for FreeRTOS.

I’m losing the line where it starts being Real Time and where not. It looks like _I_ could not create the real-time application I needed with FreeRTOS.

And I think the hardware timer interrupt with adjustable frequency looks like a more stable way to go.

Kind regards,

Engin

richard_damon wrote on Friday, July 03, 2009:

Since your delays sound like they are going to be shorter than your main timer tick, have your user task delay by waiting on a semaphore, and have a second higher speed timer signal that semaphore when it is time for the user task to run.

You could then even drop the rate of the system timer tick, as you don’t really need a small time slice for anything, the limiting factor will be what resolution delays the comm tasks will need.

enginayd wrote on Friday, July 03, 2009:

You mean; make the user program task highest priority and block it using a semaphore. So that I can signal the task to unblock from a high frequency hardware timer ? And if it needs to be waken up the FreeRTOS will immediately issue a context switch upon the return of the timer ISR. Via portEND_SWITCHING_ISR( xSwitchRequired ).

Is that so ?

aturowski wrote on Friday, July 03, 2009:

Yes.

enginayd wrote on Monday, July 06, 2009:

Hmm. Now that I’ve started implementing this I’ve noticed that this approach will also starve other tasks also just like other approach we have talked earlier.

Imagine I’m waking up the user task in every 250us with timer interrupt. If the execution of the user task took longer than that. It will be immediately executed again once it is over, since it is the highest priority task. If this is the case, this is not a robust design. Right ?

Kind regards,

Engin

enginayd wrote on Monday, July 06, 2009:

I think one last approach, maybe the simplest, could be to use a one-shot timer to provide a finer resolution vTaskDelay functionality.

i.e. in every loop-end of the user-task, I’ll initiate a one-shot timer, that will unblock the next loop round. So my user-task will wait, say, 50us all the time.

This looks like a good idea, right ?

Only disadvantage will be that that 50us could be a waste of time on some occasions, hence lower efficiency.

aturowski wrote on Monday, July 06, 2009:

No, it is not robust. Thats why it have been suggested to go for adaptive scheme to avoid that kind of situation. It seems that you cannot rely on how long user application execute and if this time is relatively constant.

Personally I would do two things to get around that:
1) I would create global variable (flag), which would be increased every time idle task is called. It could be done in vAplicationIdleHook().
2) I would create the monitoring task with highest prority in the system (higher that user app task). This task has to be executed say every 50ms and it checks the value of flag variable, clearing it afterwards. If the value is greater that zero, it means that idle task has been executed and there was no task starving. In that case timer period can be decreased. If this value is zero it means that there is starving and timer period has to be increased.

Of course you should start with relatively large timer period.to prevent starving at the beginning. Then whole system will adapt and provide you the best achievable performance.

Hope that helps,
Adam

jwestmoreland wrote on Tuesday, July 07, 2009:

>> Yes, FreeRTOS scheduler concept is a bit non-traditional with 
>> respect to modern
>> OSes, hence the confusion I believe.

> It’s a fixed priority preemptive scheduler - about as traditional as you can get for this class >of RTOS. [fixed priority meaning the scheduler does not change the task priorities itself, not >that application writers cannot change the priority].

>Regards.

If a fixed priority preemptive scheduler starves tasks that are n-1in priority, with n being the highest priority - then you have a round-robin scheduler (at n).  I think this is what I am seeing.

Here’s a great link that explains the differences in schedulers - I am providing this as a reference and not as a direct response to Richard -

http://www1bpt.bridgeport.edu/sed/projects/cs503/Spring_2001/kode/os/scheduling.htm

I know I’ve seen this asked before - but if you have say, 27 tasks, and 7 priorities, is that better or worse than having 27 tasks, and 4 priorities?  Will the tasks running at priority 7 and 4 respectively always starve tasks scheduled with priority 1?

Thanks,
John

richard_damon wrote on Tuesday, July 07, 2009:

Fixed priority means that the highest priority tasks get the cpu when they ask for it. It WILL cause starvation of lower priority tasks if the higher priority tasks ask for all the CPU time, just like that article talks about. Priority N will ALWAYS run before priority N-1, if it is available to run.

How many priority levels do you need, well that depends on your application. Tasks that should share the CPU using round robin scheduling should be at the same priority. tasks that should interrupt another as soon as they are ready to run should be at distinct levels in order of priority.

jwestmoreland wrote on Wednesday, July 08, 2009:

I must be missing something in this discussion - what is the point of having priorities if it is guaranteed that n-1 will be starved?  This is the same as round-robin and makes priorities moot, doesn’t it.

I thought the intent of the preemptive scheduler in FreeRTOS was to be a bit more cooperative - giving time slices to lower priority tasks.  What am I missing here?

Thanks,
John

richard_damon wrote on Wednesday, July 08, 2009:

n-1 will get starved only if n uses all available time. In most systems, the higher priority task do short important tasks, and the lower priority tasks do longer operations which are less time critical. The Fixed Priority system has the advantage of simplicity, and is sufficient for many applications. There are other scheduling algorithms used in real time systems like nearest deadline, that may give better results but require more planing. A scheduling system that would keep a priority n task from staving the n-1, would tend to actually have poorer real time performance, as it is harder to make sure the high priority task completes in time.

Preemptive actually means that higher priority tasks get more priority, as the high priority task will start as soon as it becomes ready, even if this requires “preempting” the lower priority task in the middle of its work. The alternative are “Cooperative” scheduling, where tasks need to periodically yield control, giving what ever task now is the highest priority ready task. Cooperative systems are simpler, and sometimes faster as you don’t need to worry about as many synchronization issues, it does suffer from more latency for the high priority task as they need to wait for the next yeild before they can start.

rtel wrote on Wednesday, July 08, 2009:

There are three main types of task:

1) Periodic.  Runs at a fixed frequency, remaining in the blocked state (allowing other tasks to run) when its not running.  If the frequency has to be very accurate then it needs to be a high priority.  If its timing requirements are not so strict then it can be a lower priority.

2) Event driven.  Unblocks and does something only when necessary (maybe a data packet arrived, or somebody pressed a button).  When its not processing an event it remains in the blocked state and allows lower priority tasks to run.  The important thing here is polling should be avoided as it wastes CPU time.  The faster the response needs to be the higher the event driven task priority should be.

3) Continuous processing tasks.  These are tasks that always have something to do and are therefore always in the ready state - meaning tasks of lower priority will not run but tasks of equal priority will time slice.  Continuous processing tasks are very rare.

Regards.