本页内容发表于MCUZone,但不代表MCUZone的观点。
如果你对本页的技术内容有疑问,请到 MCUZone技术论坛 发帖。
如果你认为本页的内容侵害了你的权益,请与hotislandn@hotmail.com;hdapple_2000@hotmail.com 联系,我们会在确认后移除。

uC/OS-II 代码在sam9261上运行的速度对比

本文通过将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)实现。

测试系统配置

  • 处理器配置
    1. pck = 198656000Hz
    2. mck = 99328000Hz
  • 代码优化: OPT = 3
  • uC/OS-II配置
    1. #define OS_TASK_STAT_EN 1 ←- 使能stat task
    2. #define OS_TMR_EN 0 ←- 避免timer task的影响
    3. #define OS_TICKS_PER_SEC 100
  • 用户任务
    • 系统中只建立一个用户任务MainTask(),该任务是系统中优先级最高的任务。在开始时初始化stat的任务,然后输出max的值,并利用该值来比较代码的运行速度。主任务只是延时,打印及使得led闪烁, 其代码如下:
    • :!:由于main task与idle task并无同步机制,因此输出的OSIdleCtr的值可能是计数中途的值。
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

:!:注意:

  • SDRAM 工作于 MCK
  • OSIdleCtrMax为CPU在100ms内将一个UINT32类型数据从0加到的最大值
  • D Cache 依赖于MMU的设置,具体可以参考 ARM926ej-s的技术参考手册
  • ITCM 设置为64KB
  • 测试ITCM时将os_core.c, os_cpu_a.S, os_cpu_c.c中的代码置于ITCM
  • 使能D Cache时,使能MMU,页表置于SDRAM。代码运行区域设置为cacheable,write buffer enable

测试结论

  1. 代码的优化方式对cache的效果有影响,优化级别为s(size)时,打开I Cache的提升有限,而优化等级为3时效果明显。
  2. :!:由于测试代码在空间上很集中,使得I Cache的效果极好,但是还是可以看出CPU访问SDRAM的速度慢。
  3. :!:使用TCM并不一定比Cache效果好,特别是在代码在时间和空间上都很集中时。例子中的task idle在测试时运行的时间和空间就很集中。关于这一点可以参考 ARM926ej-s的技术参考手册 P110,原文如下:
    • TCMs are intended for storing certain types of critical code or data, where low latency,deterministic access is required. TCMs are not necessarily the best choice for all types of such code or data, if code or data exhibit a high degree of spatial or temporal locality better performance may be obtained by using cache memory.
  4. 关闭I Cache, 仅使用ITCM,相对直接在SDRAM中运行性能提升也很明显,可见ITCM效能。
  5. :!:使能Cache,可能使得代码执行时间不确定,因为可能命中也可能未命中。

代码参考

  • OS_TaskStat()
/*
*********************************************************************************************************
*                                            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
  • OS_TaskIdle()
/*
*********************************************************************************************************
*                                              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                           */
    }
}
  • OS_TaskIdle()反汇编相关代码
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
 
user\mtdarm\speed_9261_usos2.txt · 最后更改: 2007/11/17 12:47 由 mtdarm
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki