<font face="courier new, monospace">Thanks Joel and Gedare for the help.</font><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">Joel, when I changed the clock tick rate to 1 ms, it 'fixed' the problem. But I think it must work with any clock tick rate! :-) Else, everything I learned as a Computer Scientist is wrong! (LOL).<br>
</font><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">I've verified (by debugging) that (TCB)->cpu_time_budget is replenished in two different places:</font></div>
<div><font face="courier new, monospace">  1 - void _Thread_Dispatch( void ), currently has:</font></div><div><font face="courier new, monospace">    (...)</font></div><div><div><font face="courier new, monospace">    if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )</font></div>
<div><font face="courier new, monospace">        heir->cpu_time_budget = _Thread_Ticks_per_timeslice;</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">  2 - void _Thread_Tickle_timeslice( void ):</font></div>
<div><font face="courier new, monospace">     (...)</font></div><div><span style="font-family:'courier new',monospace">      if ( (int)(--executing->cpu_time_budget) <= 0 ) {</span></div><div><font face="courier new, monospace">        _Thread_Reset_timeslice();</font></div>
<div><font face="courier new, monospace">        executing->cpu_time_budget = _Thread_Ticks_per_timeslice;</font></div><div><font face="courier new, monospace">      }</font></div><div><font face="courier new, monospace">      break;</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">To fix the problem, I just prevented _Thread_Dispatch() from replenish cpu_time_buget if it has not being exhausted yet:</font></div>
<div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">void _Thread_Dispatch( void ) { ...</font></div><div><div><font face="courier new, monospace">    if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )</font></div>
<div><font face="courier new, monospace">       <b>if ( </b></font><span style="font-family:'courier new',monospace"><b>heir->cpu_time_budget == 0) // prevent starvation</b></span></div><div><font face="courier new, monospace">            heir->cpu_time_budget = _Thread_Ticks_per_timeslice;</font></div>
</div></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">It sounds good. But, it makes me think if the first 'if' is really necessary in _Thread_Dispatch, since 'cpu_time_buget' is being mananged by </font><span style="font-family:'courier new',monospace">_Thread_Tickle_timeslice() already.</span></div>
<div><font face="courier new, monospace">Then, I simply deleted both 'if's' and, consequently 'heir->cpu_time_budget = _Thread_Ticks_per_timeslice;' And guess what: the problem gone for good, as the first approach. :-) </font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">I don't know the real impact of such modification, but I presume we must analyse it very carefully, since _Thread_Dispatch lives in the Super Core.</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">So the question now is: Is the following code:</font></div><div><div><font face="courier new, monospace">    if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )</font></div>
<div><font face="courier new, monospace">        heir->cpu_time_budget = _Thread_Ticks_per_timeslice;</font></div><div><font face="courier new, monospace">really required in _Thread_Dispatch()?</font></div><div><font face="courier new, monospace"><br>
</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">Regards,</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">--Wendell.</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">p.s.: The test code is listed below:</font></div><div><font face="courier new, monospace"><div>/**</div><div> * @file</div>
<div> *</div><div> * RM versus RR.</div><div> */</div><div><br></div><div>//==============================================================================</div><div>//                              USED INTERFACES</div><div>
//==============================================================================</div><div>#include <bsp.h></div><div>#include <rtems/cpuuse.h></div><div>#include <stdbool.h></div><div>#include <stdio.h></div>
<div>//==============================================================================</div><div>//                        MACROS AND DATATYPE DEFINITIONS</div><div>//==============================================================================</div>
<div><br></div><div>//==============================================================================</div><div>//                     STATIC (PRIVATE) FUNCTION PROTOTYPES</div><div>//==============================================================================</div>
<div>static rtems_task task_rr(rtems_task_argument msg);</div><div>static rtems_task task_rm(rtems_task_argument msg);</div><div>static void halt_if_error(const char* p_msg, rtems_status_code s);</div><div>//==============================================================================</div>
<div>//                          STATIC GLOBAL VARIABLES</div><div>//==============================================================================</div><div><br></div><div>//==============================================================================</div>
<div>//                      IMPLEMENTATION OF PUBLIC FUNCTIONS</div><div>//==============================================================================</div><div><br></div><div>rtems_task Init(rtems_task_argument noargs)</div>
<div>{</div><div>   rtems_status_code rc;</div><div>   rtems_id rr1, rr2, rm;</div><div><br></div><div>   rc = rtems_task_create(</div><div>      rtems_build_name('R','R','0','1'),</div><div>
      10,</div><div>      RTEMS_MINIMUM_STACK_SIZE,</div><div>      (RTEMS_PREEMPT | RTEMS_TIMESLICE),</div><div>      RTEMS_FLOATING_POINT,</div><div>      &rr1);</div><div>   halt_if_error("task RR01: unable to create task:", rc);</div>
<div><br></div><div>   rc = rtems_task_create(</div><div>      rtems_build_name('R','R','0','2'),</div><div>      10,</div><div>      RTEMS_MINIMUM_STACK_SIZE,</div><div>      (RTEMS_PREEMPT | RTEMS_TIMESLICE),</div>
<div>      RTEMS_FLOATING_POINT,</div><div>      &rr2);</div><div>   halt_if_error("task RR02: unable to create task:", rc);</div><div><br></div><div>   rc = rtems_task_create(</div><div>      rtems_build_name('R','M','O','N'),</div>
<div>      5,</div><div>      RTEMS_MINIMUM_STACK_SIZE,</div><div>      RTEMS_DEFAULT_MODES,</div><div>      RTEMS_FLOATING_POINT,</div><div>      &rm);</div><div>   halt_if_error("task RMON: unable to create task:", rc);</div>
<div><br></div><div>   rc = rtems_task_start(rr1, task_rr, (rtems_task_argument)"A");</div><div>   halt_if_error("task RR01: unable to start task:", rc);</div><div><br></div><div>   rc = rtems_task_start(rr2, task_rr, (rtems_task_argument)"B");</div>
<div>   halt_if_error("task RR01: unable to start task:", rc);</div><div><br></div><div>   rc = rtems_task_start(rm, task_rm, (rtems_task_argument)"C");</div><div>   halt_if_error("task RMON: unable to start task:", rc);</div>
<div><br></div><div>   while(true)</div><div>   {</div><div>      rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(10000));</div><div>      rtems_cpu_usage_report();</div><div>      rtems_cpu_usage_reset();</div><div>   }</div>
<div><br></div><div>}</div><div><br></div><div>//==============================================================================</div><div>//                IMPLEMENTATION OF STATIC (PRIVATE) FUNCTIONS</div><div>//==============================================================================</div>
<div><br></div><div>static rtems_task task_rr(rtems_task_argument msg)</div><div>{</div><div>   char* p_msg = (char *)msg;</div><div><br></div><div>   while(true)</div><div>   {</div><div>      volatile uint32_t c;</div><div>
<br></div><div>      for (c = 0; c < 1000000; c++);</div><div>      printk(p_msg);</div><div>   }</div><div>}</div><div><br></div><div>static rtems_task task_rm(rtems_task_argument msg)</div><div>{</div><div>   rtems_status_code rc;</div>
<div>   rtems_id p;</div><div>   char* p_msg = (char *)msg;</div><div><br></div><div>   rc = rtems_rate_monotonic_create(rtems_build_name('r','m','0','1'), &p);</div><div><br></div><div>
   if (rc != RTEMS_SUCCESSFUL)</div><div>   {</div><div>      printk("error: unable to create RM period: %d\n", rc);</div><div>      rtems_task_delete(rtems_task_self());</div><div>   }</div><div><br></div><div>
   while(true)</div><div>   {</div><div>      volatile uint32_t c;</div><div><br></div><div>      rc = rtems_rate_monotonic_period(p, 5);</div><div>      if (rc != RTEMS_SUCCESSFUL) { printk("deadline missed!\n"); for(;;); }</div>
<div>      for (c = 0; c < 1000000; c++);</div><div>      printk(p_msg);</div><div>   }</div><div>}</div><div><br></div><div>static void halt_if_error(const char* p_msg, rtems_status_code s)</div><div>{</div><div>   if (s != RTEMS_SUCCESSFUL)</div>
<div>   {</div><div>      printk(p_msg);</div><div>      printk("%d\n", s);</div><div><br></div><div>      for(;;);</div><div>   }</div><div>}</div><div><br></div><div>#define CONFIGURE_INIT</div><div><br></div>
<div>#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER</div><div>#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER</div><div>#define CONFIGURE_MICROSECONDS_PER_TICK RTEMS_MILLISECONDS_TO_MICROSECONDS(5)</div><div><br></div>
<div>#define CONFIGURE_TICKS_PER_TIMESLICE           5</div><div>#define CONFIGURE_MAXIMUM_PERIODS               1</div><div>#define CONFIGURE_MAXIMUM_TASKS                 5</div><div>#define CONFIGURE_USE_DEVFS_AS_BASE_FILESYSTEM</div>
<div><br></div><div>#define CONFIGURE_RTEMS_INIT_TASKS_TABLE</div><div><br></div><div>#include <rtems/confdefs.h></div><div><br></div></font></div><div><font face="courier new, monospace"><br></font></div><br></div>
<div class="gmail_quote">2012/6/20 Joel Sherrill <span dir="ltr"><<a href="mailto:joel.sherrill@oarcorp.com" target="_blank">joel.sherrill@oarcorp.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="HOEnZb"><div class="h5">On 06/19/2012 04:02 PM, Gedare Bloom wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
On Tue, Jun 19, 2012 at 4:08 PM, Wendell Silva<<a href="mailto:silvawp@gmail.com" target="_blank">silvawp@gmail.com</a>>  wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hello RTEMS Gurus!<br>
<br>
Environment:<br>
   - RTEMS 4.10.2<br>
   - BSP i386/pc386<br>
<br>
Summary:<br>
   - ticks per timeslice = 5<br>
   - milliseconds per tick = 5<br>
   - Task A, PREEMPT | TIMESLICE, priority = 10, "number crusher" never yield<br>
CPU voluntarily.<br>
   - Task B, PREEMPT | TIMESLICE, priority = 10, "number crusher" never yield<br>
CPU voluntarily.<br>
   - Task C, PREEMPT | NO_TIMESLECE, priority = 5, periodic (rate-monotonic),<br>
period = 5 ticks (25ms), CPU usage = ~50%<br>
<br>
What was expected:<br>
   - Task C running periodically, as programmed.<br>
   - Tasks A and A, using the remaining CPU budget, (~25% each one, in this<br>
configuration).<br>
<br>
What was observed:<br>
   - Task C running periodically, as programmed (passed).<br>
   - Only task A is running.<br>
   - Task B never runs.<br>
<br>
"Workarounds" applied to achieve the expected behavior:<br>
    - 1: decrease ticks per timeslice; or,<br>
    - 2: decrease task C CPU budget (larger period or less computations).<br>
<br>
I believe the general form of the problem is equivalent to answer:<br>
   - Why timesliced tasks gets starved, when:<br>
        * ticks per timeslice is equals to a period of a RM task, or<br>
        * when the CPU use of RM task is greater than or equals to 50%.<br>
<br>
Is the RM scheduling police interfering in timeslice accounting?<br>
<br>
</blockquote>
Yes. I have some idea of what is happening.<br>
1. C executes for ~3 ticks.<br>
2. A executes for 2 ticks, has budget=3 remaining when C fires.<br>
3. C executes for 3 ticks; then _Thread_Dispatch sees A as heir and<br>
replenishes A's timeslice<br>
4. A executes for 2 ticks, has budget=3 remaining when C fires<br>
5. goto 3<br>
<br>
The RM task is scheduled by a watchdog timer that fires during the<br>
rtems clock_tick, but has no particular knowledge about the tasks that<br>
are time-sliced. So when the RM task finishes its period, it<br>
dispatches back to the thread it interrupted and replenishes that<br>
task's budget without making any other checks.<br>
<br>
I don't know if this behavior is a bug. To obtain the behavior you<br>
desire you could augment _Thread_Dispatch to check if the<br>
heir->cpu_time_budget == 0 before replenishing it if changing RTEMS<br>
internally is an option for you. If not then you have to do some<br>
finagling with the task parameters as you indicated, or submit a bug<br>
report and convince someone that the behavior described here is a bug<br>
and should be fixed and back-ported. :)<br>
<br>
If you can hook up to a debugger you can 'break' at _Thread_Dispatch<br>
(or rtems_clock_tick) and check what the values are for<br>
_Thread_Executing and _Thread_Heir and their cpu_time_budget (if<br>
either is timeslicing) to verify the behavior I described.<br>
</blockquote>
<br>
<br></div></div>
I think you are pushing the edge of the granularity of the math<br>
on the clock tick rate, ticks per timeslice and the time required<br>
by A.<br>
<br>
I think you might have a CPU execution budget problem<br>
where there is not enough slack time to really perform the<br>
cruncher operations in the way you think given the 5 millisecond<br>
clock tick. I think you logically want this.<br>
<br>
A 25 msecs<br>
B 25 msecs<br>
A 25 msecs<br>
C 25 msecs<br>
<br>
But when B or C get interrupted, they have time left on their<br>
timeslice - due to rounding - and the task order doesn't match<br>
what one would draw. Your timeline is based on 100% CPU utilization,<br>
no rounding, etc.  When A preempts, you are almost guaranteed<br>
it does so with a partial timeslice.  The Classic API (by design)<br>
awards a full quantum when the task is switched back in so<br>
you will never switch to C.<br>
<br>
Note that even if the time quantum is not replenished, the same<br>
task would most likely run before and after A every time. It has<br>
to run a full 25 msecs and if the planets do not align, this will<br>
always be off in the real timeline on HW.<br>
<br>
As one experiment, change the clock tick rate to 1 millisecond<br>
and adjust the time slice quantum to 25. That may help<br>
some. But I doubt it will fix it.<br>
<br>
I think a simple solution is to make the timeslice quantum less than<br>
the period of A. Say 5 or 10 milliseconds with a tick of 1 milliseconds.<br>
<br>
If the task never consumes its entire quantum, then it can never<br>
yield the CPU. And this sounds like what you see.<br>
<br>
Remember me saying that you average a 1/2 tick quantum error<br>
for all tick based operations? You have created a task and timing<br>
combination that really highlights that. :)<br>
<br>
FWIW the POSIX API defines that the thread's timeslice quantum is<br>
replenished when it expires (not when switched back in). If you used<br>
pthread's, you likely would see more of what you expect.  There<br>
was talk of adding an attribute to use this algorithm on Classic API<br>
tasks but no one ever stepped up to implement, document, and<br>
test it.  This is using the TCB field "budget_algorithm". This is another<br>
option and one that would certainly be acceptable for submission.<br>
If you like OAR to implement this, just ask offline.<br>
<br>
--joel<div class="HOEnZb"><div class="h5"><br>
<br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
-Gedare<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Test program attached.<br>
<br>
Run with:<br>
   - qemu-system-i386 -kernel Debug/exer_rm<br>
<br>
(it what tested in a real hardware and the same behavior was observed).<br>
<br>
Change system.h and/or task_four to "fix".<br>
<br>
Best regards,<br>
<br>
--Wendell.<br>
<br>
<br>
______________________________<u></u>_________________<br>
rtems-users mailing list<br>
<a href="mailto:rtems-users@rtems.org" target="_blank">rtems-users@rtems.org</a><br>
<a href="http://www.rtems.org/mailman/listinfo/rtems-users" target="_blank">http://www.rtems.org/mailman/<u></u>listinfo/rtems-users</a><br>
<br>
</blockquote>
______________________________<u></u>_________________<br>
rtems-users mailing list<br>
<a href="mailto:rtems-users@rtems.org" target="_blank">rtems-users@rtems.org</a><br>
<a href="http://www.rtems.org/mailman/listinfo/rtems-users" target="_blank">http://www.rtems.org/mailman/<u></u>listinfo/rtems-users</a><br>
</blockquote>
<br>
<br></div></div><span class="HOEnZb"><font color="#888888">
-- <br>
Joel Sherrill, Ph.D.             Director of Research&   Development<br>
joel.sherrill@OARcorp.com        On-Line Applications Research<br>
Ask me about RTEMS: a free RTOS  Huntsville AL 35805<br>
    Support Available             <a href="tel:%28256%29%20722-9985" value="+12567229985" target="_blank">(256) 722-9985</a><br>
<br>
<br>
</font></span></blockquote></div><br></div></div>