uc/os-ii统计任务
uC/OS-II定义了两个系统任务,空闲任务与统计任务。
空闲任务OSTaskIdle()是μC/OS-Ⅱ必不可少的系统函数,当没有其它任务进入就绪态时,该任务立即转入运行态。空闲任务的优先级永远设为最低,即
OS_LOWEST_PRIO
,永远不被挂起,也不能被删除。空闲任务什么都不做,只是在不停地给一个32位计数器
OSIdleCtr
加1,统计任务使用这个计数器以确定当前应用程序实际消耗的CPU时间。计数器是一个全局变量,大多数8位或16位CPU对32位变量加1需要多条指令,所以在访问前必须先关中断,然后再开启,以防高优先级任务或中断打入。
void OS_TaskIdle (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" */
for (;;) {
OS_ENTER_CRITICAL();
OSIdleCtr++;
OS_EXIT_CRITICAL();
OSTaskIdleHook(); /* Call user definable HOOK */
}
}
- 统计任务
OSTaskStat()
也是μC/OS-Ⅱ的系统函数之一,其功能是计算当前CPU的利用率,告诉用户应用程序使用了多少CPU时间。一旦将文件OS_CFG.H
中的配置常数OS_ TASK_STAT_EN
置1,这个任务就自动建立。它每秒钟运行一次,计算结果放在一个有符号的8位整数OSCPUsage
中,表示格式是百分数,精确到1%。
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 */
}
}
- 下面重点分析一下如何计算CPU利用率。
使用统计任务时,初始化时只能建立唯一的一个任务,其它任务的建立只能在多任务启动后建立。值得注意的是:时钟节拍的初始化和启动工作也可以放在OSStart()函数中完成。一般不要在多任务启动之前启动时钟节拍器,因为这样做可能导致任务开始前应用程序就收到时钟节拍中断,以至系统崩溃。
void main (void)
{
OSInit(); /*初始化ucosii */
OSTaskCreate(TaskStart,(void *)0,
&startup_task_stk[STARTUP_TASK_STK_SIZE-1], STARTUP_TASK_PRIO);/*创建唯一任务 */
OSStart();
}
void TaskStart(void *p_arg)
{
SysTick_init();/*安装并启动始终节拍 */
OSStatInit(); /*调用系统函数,初始化统计任务 */
while(1)
{
/*TaskStart代码 */
}
}
- 统计任务的使用方法是:首先用户在初始化时建立一个也只能是一个任务,其次在这个唯一的任务中调用
OSStatInit()
函数。
void OSStatInit (void)
{
#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();
}
进入多任务的条件准备好了以后,调用系统启动函数
OSStart()
。这个函数将使TaskStart()
开始执行,因为TaskStart()
是优先级最高的任务。TaskStart()
负责初始化和启动时钟节拍。在这里启动时钟节拍是必要的,因为用户不会希望在多任务还没有开始时就接收到时钟节拍中断。接下去TaskStart()
调用统计初始化函数OSStatInit()
。
统计初始化函数OSStatInit()
决定在没有其它应用任务运行时,空闲计数器OSIdleCtr
的计数有多快。这里取0.1秒(OS_TICKS_PER_SEC / 10
)内OSIdleCtr的计数值OSIdleCtrMax
为计算CPU利用率的基准。- 系统统计初始化任务函数
OSStatInit()
调用延迟函数OSTimeDly(2)
将自身延时2个时钟节拍以停止自身的运行。这是为了使OSStatInit()
与时钟节拍同步。 - μC/OS-Ⅱ然后选下一个优先级最高的进入就绪态的任务运行,这恰好是统计任务
OSTaskStat()
。OSTaskStat()
所要做的第一件事就是查看统计任务就绪标志是否为“假”,如果是的话,要延时0.2秒(2 * OS_TICKS_PER_SEC / 10
)。一定会是这样,因为标志OSStatRdy
已被OSInit()
函数初始化为“假”,所以实际上OSTaskStat
也将自己推入休眠态0.2秒。 - 于是任务切换到空闲任务,
OSTaskIdle()
开始运行,这是唯一一个就绪态任务了。CPU处在空闲任务OSTaskIdle
中,直到TaskStart()
的延迟两个时钟节拍完成。 - 两个时钟节拍之后,
TaskStart()
恢复运行。 在执行OSStartInit()
时,空闲计数器OSIdleCtr被清零。然后,OSStatInit()
将自身延时0.1秒。 - 因为没有其它进入就绪态的任务,
OSTaskIdle()
又获得了CPU的控制权。0.1秒钟以后,TaskStart()
继续运行,还是在OSStatInit()
中,空闲计数器将0.1秒钟内计数的值存入空闲计数器最大值OSIdleCtrMax
。 OSStarInit()
将统计任务就绪标志OSStatRdy
设为“真”,以此来允许OSTaskStat()
开始计算CPU的利用率。
- 系统统计初始化任务函数
统计任务每0.1秒执行一次,以确定所有应用程序中的任务消耗了多少CPU时间。当用户的应用程序代码加入以后,运行空闲任务的CPU时间就少了,
OSIdleCtr
就不会像原来什么任务都不运行时有那么多计数。要知道,OSIdleCtr
的最大计数值是OSStatInit()
在初始化时保存在计数器最大值OSIdleCtrMax
中的。CPU利用率是保存在变量OSCPUsage中的,根据公式计算OSIdleCtr=OSIdleCtrMax
时CPU利用率最低为0,OSIdleCtr=0
时CPU利用率最高为100%。
===========以上为统计任务的分析===============关于统计任务运行频率的补充
统计任务执行到最后时是OSTimeDly(OS_TICKS_PER_SEC/10);
这样一个函数。表示延迟一分钟。而只有统计任务延时时空闲任务才有可能运行,所以每当统计任务运行时OSIdleCtr的值都是在可能的1s内记的数。因为在统计任务在赋完值之后清零了。所以说,统计任务不是1s运行一次,只不过统计任务运行时用到的变量都是在1s内的数据。
参考:http://gha20028.blog.163.com/blog/static/13481666201363021616344/