搜索
 找回密码
 立即注册

简单一步 , 微信登陆

uCOS2_CPU利用率的实现

作者:chenfangyu | 时间:2016-12-16 16:20:43 | 阅读:3932| 只看该作者

        在uCOS2操作系统当中可以得到CPU的利用率,计算利用率是通过一个任务来计算的,任务的名字叫“OSTaskStat()”.如果要使用任务需要将OS_CFG.H头文件中的OS_TASK_STAT_EN宏定义为真。这样你就可以在程序中使用任务统计功能了。
如果应用程序打算使用统计任务,那么你必须在主函数当中只建立一开始任务,然后在开始任务中调用OSStatInit(),之后你就可以建立其他任务了。
我们知道如果要使用uCOS2操作系统需要在main()函数中调用OSInit()函数,先把此函数的代码复制如下:
void  OSInit (void)
{
    OSInitHookBegin();                                           /* Call port specific initialization code   */

    OS_InitMisc();                                               /* Initialize miscellaneous variables       */

    OS_InitRdyList();                                            /* Initialize the Ready List                */

    OS_InitTCBList();                                            /* Initialize the free list of OS_TCBs      */

    OS_InitEventList();                                          /* Initialize the free list of OS_EVENTs    */

#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
    OS_FlagInit();                                               /* Initialize the event flag structures     */
#endif

#if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)
    OS_MemInit();                                                /* Initialize the memory manager            */
#endif

#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
    OS_QInit();                                                  /* Initialize the message queue structures  */
#endif

    OS_InitTaskIdle();                                           /* Create the Idle Task                     */
#if OS_TASK_STAT_EN > 0
    OS_InitTaskStat();                                           /* Create the Statistic Task                */
#endif

#if OS_TMR_EN > 0
    OSTmr_Init();                                                /* Initialize the Timer Manager             */
#endif

    OSInitHookEnd();                                             /* Call port specific init. code            */

#if OS_DEBUG_EN > 0
    OSDebugInit();
#endif
}
在函数中会看到如下代码:
    OS_InitTaskIdle();                                           /* Create the Idle Task                     */
#if OS_TASK_STAT_EN > 0
    OS_InitTaskStat();                                           /* Create the Statistic Task                */
这两个函数其实就是建立两个任务,一个是空闲任务,一个是任务统计任务。空闲任务是每一个uCOS2应用程序中必须要使用的,但是统计任务可以不用。
在InitTaskIdle()函数中的关键代码如下:
    (void)OSTaskCreateExt(OS_TaskIdle,
                          (void *)0,                                 /* No arguments passed to OS_TaskIdle() */
                          &OSTaskIdleStk[OS_TASK_IDLE_STK_SIZE - 1], /* Set Top-Of-Stack                     */
                          OS_TASK_IDLE_PRIO,                         /* Lowest priority level                */
                          OS_TASK_IDLE_ID,
                          &OSTaskIdleStk[0],                         /* Set Bottom-Of-Stack                  */
                          OS_TASK_IDLE_STK_SIZE,
                          (void *)0,                                 /* No TCB extension                     */
                          OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);/* Enable stack checking + clear stack  */
在InitTaskStat()函数中的关键代码如下:
    (void)OSTaskCreateExt(OS_TaskStat,
                          (void *)0,                                   /* No args passed to OS_TaskStat()*/
                          &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1],   /* Set Top-Of-Stack               */
                          OS_TASK_STAT_PRIO,                           /* One higher than the idle task  */
                          OS_TASK_STAT_ID,
                          &OSTaskStatStk[0],                           /* Set Bottom-Of-Stack            */
                          OS_TASK_STAT_STK_SIZE,
                          (void *)0,                                   /* No TCB extension               */
                          OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);  /* Enable stack checking + clear  */
从函数的调用参数可以知道统计任务的优先级为OS_TASK_STAT_PRIO,而空闲任务的优先级为OS_TASK_IDLE_PRIO。在Ucos_ii.h中有以下宏定义:
#define  OS_TASK_STAT_PRIO  (OS_LOWEST_PRIO - 1)        /* Statistic task priority                     */
#define  OS_TASK_IDLE_PRIO  (OS_LOWEST_PRIO)            /* IDLE      task priority                     */
可以看到空闲任务的优先级最低,任务统计的优先级次低。在应用程序中建立的任何其他任务都会比这两个任务的优先级高。

在main函数中只要调用OSStart()函数后,程序就会执行最高优先级的任务,就是在main()函数中建立的开始任务。在此任务中回调用统计任务初始化函数OSStatInit()。这个函数的源码如下:
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr = 0;
#endif



    OSTimeDly(2);                                /* Synchronize with clock tick                        */
    OS_ENTER_CRITICAL();
    OSIdleCtr    = 0L;                           /* Clear idle counter                                 */
    OS_EXIT_CRITICAL();
    OSTimeDly(OS_TICKS_PER_SEC / 10);            /* Determine MAX. idle counter value for 1/10 second  */
    OS_ENTER_CRITICAL();
    OSIdleCtrMax = OSIdleCtr;                    /* Store maximum idle counter count in 1/10 second    */
    OSStatRdy    = OS_TRUE;
    OS_EXIT_CRITICAL();
在函数中的OSTimeDly(2);系统调用是为了,同步时钟滴答。因为在开始计算空闲计数器时,产生系统滴答的定时器计数器可能会偏离计数器设定的最大值很多。这样会造成计算出来的空闲计数器最大值误差较大。加上了此函数后,就会减小误差,因为一次滴答结束之后,只需要执行一小段的程序就要执行 OSTimeDly(OS_TICKS_PER_SEC / 10)函数了。这一段小段程序只花费了定时器计数器很少的时间,这要计算出来的空闲计数器的最大值会有很少的偏差,可以忽略不计。
OSTimeDly(OS_TICKS_PER_SEC / 10); 此函数被调用之后开始任务就会处于挂起状态。这样就会执行任务统计这个任务了,在看统计任务之前先看一下空闲任务,空闲任务的源码如下:
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr = 0;
#endif



    (void)p_arg;                                 /* Prevent compiler warning for not using 'p_arg'     */
    for (;;) {
        OS_ENTER_CRITICAL();
        OSIdleCtr++;
        OS_EXIT_CRITICAL();
        OSTaskIdleHook();                        /* Call user definable HOOK                           */
    }
空闲任务其实执行的就是红色部分的区域,就是对全局变量OSIdleCtr不停的递增。而OSTaskIdleHook函数中是空函数。是为了防止OSIdleCtr可能会溢出,由用户程序在此函数中添加必要的延时。OSIdleCtr在此任务中更新,会在任务统计这任务使用。
任务统计这任务源代如下:
void  OS_TaskStat (void *p_arg)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr = 0;
#endif



    (void)p_arg;                                 /* Prevent compiler warning for not using 'p_arg'     */
    while (OSStatRdy == OS_FALSE) {
        OSTimeDly(2 * OS_TICKS_PER_SEC / 10);    /* Wait until statistic task is ready                 */
    }
    OSIdleCtrMax /= 100L;
    if (OSIdleCtrMax == 0L) {
        OSCPUUsage = 0;
        (void)OSTaskSuspend(OS_PRIO_SELF);
    }
    for (;;) {
        OS_ENTER_CRITICAL();
        OSIdleCtrRun = OSIdleCtr;                /* Obtain the of the idle counter for the past second */
        OSIdleCtr    = 0L;                       /* Reset the idle counter for the next second         */
        OS_EXIT_CRITICAL();
        OSCPUUsage   = (INT8U)(100L - OSIdleCtrRun / OSIdleCtrMax);
        OSTaskStatHook();                        /* Invoke user definable hook                         */
#if (OS_TASK_STAT_STK_CHK_EN > 0) && (OS_TASK_CREATE_EXT_EN > 0)
        OS_TaskStatStkChk();                     /* Check the stacks for each task                     */
#endif
        OSTimeDly(OS_TICKS_PER_SEC / 10);        /* Accumulate OSIdleCtr for the next 1/10 second      */
    }
}

该任务基本上一直会处在挂起状态,因为它一直在对统计就绪这个全局变量OSStatRdy进行遍历,等待其为真才回执行下面的语句。它什么时候为真呐?在OSStatInit函数中有一个语句OSStatRdy    = OS_TRUE;。可以看出当计算出100个滴答空闲计数器的值后并赋值给OSIdleCtrMax 变量。之后就可以执行OSIdleCtrMax /= 100L;了。这个语句是为了得到1个时钟滴答的空闲计数器最大值。然后进入任务死循环for( ; ; ),在此循环中就是一直在延时100个是时钟滴答,然后取出OSIdleCtr值,放在OSIdleCtrRun 变量中,通过OSCPUUsage   = (INT8U)(100L - OSIdleCtrRun / OSIdleCtrMax);得出CPU的利用率。


在此要说明的是 OSIdleCtrMax为一个时钟滴答的空闲计数器最大值,而OSIdleCtrRun 为100个时钟滴答的空闲计数器值。 OSIdleCtrRun / OSIdleCtrMax等价于100*(一个时钟滴答的空闲计数器值/(一个时钟滴答空闲计数器的最大值)。(INT8U)(100L - OSIdleCtrRun / OSIdleCtrMax)就是CPU的利用率了。
收藏
收藏0
分享
分享
点赞
点赞0
反对
反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册
手机版