
本页内容发表于MCUZone,但不代表MCUZone的观点。
如果你对本页的技术内容有疑问,请到 MCUZone技术论坛 发帖。
如果你认为本页的内容侵害了你的权益,请与hotislandn@hotmail.com;hdapple_2000@hotmail.com 联系,我们会在确认后移除。
本文通过将uC/OS-II的代码分别置于内部RAM,外部SDRAM,并结合cache及TCM的技术,对比不同情况下的代码运行速度,可以作为编程的参考。
在uC/OS-II的代码中有一个统计任务: OS_TaskStat() (文件:os_core.c), 该任务如果使能,将每100ms(1/10 sec)运行一次,将IDLE任务中的计数器变量的值获得,并将其清零。这个计数的值将和一个计数最大值比较,计算系统CPU的占用率。
计算原理在于,在系统开始运行的时候,使得Idle task有100ms的独占时间,在这100ms的时间片内,Idle task一直在运行,那么那个计数器变量将计数到一个最大值,记做max。当多任务运行起来后,由于Idle task是优先级最低的任务,它不可能独占处理器时间,那么那个计数器变量在100ms内所能到达的值将比max小,这个差别也就是用户任务占用的处理器时间,可据此计算CPU的利用率。
100ms的时间并非都由Idle task独占,定时器中断会产生,并会运行相关的OS服务。
max的获得通过在用户task中调用OSStatInit() (文件:os_core.c)来获得,后面的每100ms的采样由OS_TaskStat()来实现。变量计数由OS_TaskIdle() (文件:os_core.c)实现。
static void MainTask(void *p_arg) { INT32U clk = 0; clk = BSP_PCK_Frq(); printf("pck = %10dHz\n\r", clk); clk = BSP_MCK_Frq(); printf("mck = %10dHz\n\r", clk); #if OS_TASK_STAT_EN > 0 OSStatInit(); #endif printf("OSIdleCtrMax = %10d\r\n", OSIdleCtrMax); while(1) { OSTimeDly(OS_TICKS_PER_SEC); printf("OSIdleCtr = %10d\r\n", OSIdleCtr); LED_Toggle(BSP_LED1); } }
| 代码运行模式 | I Cache | D Cache | ITCM | DTCM | OSIdleCtrMax | OSIdleCtr |
|---|---|---|---|---|---|---|
| ARM in RAM | disable | disable | disable | disable | 137828 | |
| ARM in RAM | enable | disable | disable | disable | 367652 | |
| ARM in SDRAM | disable | disable | disable | disable | 63892 | 44533 |
| ARM in SDRAM | enable | disable | disable | disable | 325543 | 219675 |
| ARM in SDRAM | enable | enable | disable | disable | 536740 | 107153 |
| ARM in SDRAM | enable | disable | enable | disable | 314433 | 219745 |
| ARM in SDRAM | disable | disable | enable | disable | 314418 | 219375 |
注意:
/* ********************************************************************************************************* * STATISTICS TASK * * Description: This task is internal to uC/OS-II and is used to compute some statistics about the * multitasking environment. Specifically, OS_TaskStat() computes the CPU usage. * CPU usage is determined by: * * OSIdleCtr * OSCPUUsage = 100 * (1 - ------------) (units are in %) * OSIdleCtrMax * * Arguments : parg this pointer is not used at this time. * * Returns : none * * Notes : 1) This task runs at a priority level higher than the idle task. In fact, it runs at the * next higher priority, OS_TASK_IDLE_PRIO-1. * 2) You can disable this task by setting the configuration #define OS_TASK_STAT_EN to 0. * 3) You MUST have at least a delay of 2/10 seconds to allow for the system to establish the * maximum value for the idle counter. ********************************************************************************************************* */ #if OS_TASK_STAT_EN > 0 void OS_TaskStat (void *p_arg) { INT32U run; INT32U max; INT8S usage; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif p_arg = p_arg; /* Prevent compiler warning for not using 'parg' */ while (OSStatRdy == OS_FALSE) { OSTimeDly(2 * OS_TICKS_PER_SEC / 10); /* Wait until statistic task is ready */ } max = OSIdleCtrMax / 100L; for (;;) { OS_ENTER_CRITICAL(); OSIdleCtrRun = OSIdleCtr; /* Obtain the of the idle counter for the past second */ run = OSIdleCtr; OSIdleCtr = 0L; /* Reset the idle counter for the next second */ OS_EXIT_CRITICAL(); if (max > 0L) { usage = (INT8S)(100L - run / max); if (usage >= 0) { /* Make sure we don't have a negative percentage */ OSCPUUsage = usage; } else { OSCPUUsage = 0; } } else { OSCPUUsage = 0; max = OSIdleCtrMax / 100L; } 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 */ } } #endif
/* ********************************************************************************************************* * IDLE TASK * * Description: This task is internal to uC/OS-II and executes whenever no other higher priority tasks * executes because they are ALL waiting for event(s) to occur. * * Arguments : none * * Returns : none * * Note(s) : 1) OSTaskIdleHook() is called after the critical section to ensure that interrupts will be * enabled for at least a few instructions. On some processors (ex. Philips XA), enabling * and then disabling interrupts didn't allow the processor enough time to have interrupts * enabled before they were disabled again. uC/OS-II would thus never recognize * interrupts. * 2) This hook has been added to allow you to do such things as STOP the CPU to conserve * power. ********************************************************************************************************* */ 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 'parg' */ for (;;) { OS_ENTER_CRITICAL(); OSIdleCtr++; OS_EXIT_CRITICAL(); OSTaskIdleHook(); /* Call user definable HOOK */ } }
21501d28 <OS_TaskIdle>: 21501d28: e92d4010 stmdb sp!, {r4, lr} 21501d2c: e59f4018 ldr r4, [pc, #24] ; 21501d4c <.text+0x1d4c> 21501d30: ebfff95e bl 215002b0 <OS_CPU_SR_Save> 21501d34: e5943000 ldr r3, [r4] 21501d38: e2833001 add r3, r3, #1 ; 0x1 21501d3c: e5843000 str r3, [r4] 21501d40: ebfff95e bl 215002c0 <OS_CPU_SR_Restore> 21501d44: ebfffe24 bl 215015dc <OSTaskIdleHook> 21501d48: eafffff8 b 21501d30 <OS_TaskIdle+0x8> 21501d4c: 216010dc ldrcsd r1, [r0, #-12]!
.align 4 OS_CPU_SR_Save: MRS R0, CPSR ORR R1, R0, #OS_CPU_ARM_CONTROL_INT_DIS // Set IRQ and FIQ bits in CPSR to disable all interrupts. MSR CPSR_c, R1 BX LR // Disabled, return the original CPSR contents in R0. .align 4 OS_CPU_SR_Restore: MSR CPSR_c, R0 BX LR
215015dc <OSTaskIdleHook>:
215015dc: e12fff1e bx lr