The Statistic Task

µC/OS-III contains an internal task that provides such run-time statistics as overall CPU utilization (0.00 to 100.00%), per-task CPU utilization (0.00 to 100.00%), and per-task stack usage. As of V3.03.00, CPU utilization is represented as a integer from 0 to 10,000 (0.00% to 100.00%). Prior to V3.03.00, CPU utilization was represented an integer ranging from 0 to 100.

The statistic task is optional in a µC/OS-III application and its presence is controlled by a compile-time configuration constant OS_CFG_STAT_TASK_EN defined in os_cfg.h. Specifically, the code is included in the build when OS_CFG_STAT_TASK_EN is set to DEF_ENABLED.

Also, the priority of this task and the location and size of the statistic task’s stack is configurable via OS_CFG_STAT_TASK_PRIO declared in os_cfg_app.h ().

If the application uses the statistic task, it should call OSStatTaskCPUUsageInit() from the first, and only application task created in the main() function as shown in the listing below. The startup code should create only one task before calling OSStart(). The single task created is, of course, allowed to create other tasks, but only after calling OSStatTaskCPUUsageInit().

Listing - Proper startup for computing CPU utilization
void main (void)                      (1) 
{
    OS_ERR  err;
    :
    OSInit(&err);                     (2) 
    if (err != OS_ERR_NONE) {
        /* Something wasn't configured properly, µC/OS-III not properly initialized  */
        /* ... 'err' will tell you the cause (see os.h)                              */
    }
    /* (3) Create ONE task (we'll call it AppTaskStart() for sake of discussion)     */
    :
    OSStart(&err);                    (4) 
}
 
 
void AppTaskStart (void *p_arg)
{
    OS_ERR  err;
    :
    /* (5) Initialize the tick interrupt                                             */
#if OS_CFG_STAT_TASK_EN == DEF_ENABLED
    OSStatTaskCPUUsageInit(&err);     (6) 
    OSStatReset(&err)                 (7)
#endif
    :
    /* (8) Create other tasks                                                        */
    while (DEF_ON) {
        /* AppTaskStart() body                                                       */
    }
}

(1) The C compiler should start up the CPU and bring it to main() as is typical in most C applications.

(2) main() calls OSInit() to initialize µC/OS-III. It is assumed that the statistics task was enabled by setting OS_CFG_STAT_TASK_EN to DEF_ENABLED in os_cfg.h. You should always examine µC/OS-III’s returned error code to make sure the call was done properly. Refer to os.h for a list of possible errors, OS_ERR_???.

(3) As the comment indicates, you should create a single task called AppTaskStart() in the example (its name is left to the creator’s discretion). When creating this task, give it a fairly high priority (do not use priority 0 since it’s reserved for µC/OS-III).

Normally, µC/OS-III allows the user to create as many tasks as are necessary prior to calling OSStart(). However, when the statistic task is used to compute overall CPU utilization, it is necessary to create only one task.

(4) You need to call OSStart() to let µC/OS-III start the highest-priority task which, in our case is AppTaskStart(). At this point, there should be three (3) to five (5) tasks created depending on configuration options: OS_IdleTask(),  OS_StatTask()OS_TmrTask() (optional), OS_IntQTask() (optional) and now AppTaskStart().

(5) The start task should then configure and enable tick interrupts. This most likely requires that the user initialize the hardware timer used for the clock tick and have it interrupt at the rate specified by OS_CFG_TICK_RATE_HZ (see os_cfg_app.h). Additionally, Micriµm provides sample projects that include a basic board-support package (BSP). The BSP initializes many aspects of the CPU as well as the periodic time source required by µC/OS-III. If available, the user may utilize BSP services by calling BSP_Init() from the startup task. After this point, no further time source initialization is required by the user.

(6) OSStatTaskCPUUsageInit() is called to determine the maximum value that OSStatTaskCtr (see OS_IdleTask()) can count up to for 1/OS_CFG_STAT_TASK_RATE_HZ second when there are no other tasks running in the system (apart for the other µC/OS-III tasks). For example, if the system does not contain an application task and OSStatTaskCtr counts from 0 to 10,000,000 for 1/OS_CFG_STAT_TASK_RATE_HZ second, when adding tasks, and the test is redone every 1/OS_CFG_STAT_TASK_RATE_HZ second, the OSStatTaskCtr will not reach 10,000,000 and actual CPU utilization is determined as follows:

For example, if when redoing the test, OSStatTaskCtr reaches 7,500,000 the CPU is busy 25% of its time running application tasks:

(7) You should call this function to reset the statistics counter so that you are not getting incorrect values from the startup code.

(8) AppTaskStart() can then create other application tasks as needed.

As previously described, µC/OS-III stores run-time statistics for each task in each task’s OS_TCB.

OS_StatTask() also computes stack usage of all created tasks by calling OSTaskStkChk() (see os_task.c) and stores the return values of this function (free and used stack space) in the .StkFree and .StkUsed field of the task’s OS_TCB, respectively.