OS_CPU_C.C中未定义,此函数为用户定义。其用法请参考例程3。
9.05.06 OSTimeTickHook()
OS_CPU_C.C中未定义,此函数为用户定义。
9.06 内存占用
表9.1列出了指定初始化常量的情况下,μC/OS-II占用内存的情况,包括数据和程序代码。如果μC/OS-II用于嵌入式系统,则数据指RAM的占用,程序代码指ROM的占用。内存占用的说明清单随磁盘一起提供给用户,在安装μC/OS-II后,查看\SOFTWARE\uCOS-
II\Ix836L\DOC\目录下的ROM-RAM.XLS文件。 该文件为MicrosoftExcel文件, 需要Office97
或更高版本的Excel打开。
表9.1中所列出的内存占用大小都近似为25字节的倍数。笔者所用的BorlandC/C++V3.1设定为编译产生运行速度最快的目标代码,所以表中所列的数字并不是绝对的,但可以给读者一个总的概念。例如,如果不使用消息队列机制,在编译前将OS_Q_EN设为0,则编译后的目标代码长度6,875字节,可减小大约1,475字节。
此外,空闲任务(idle)和统计任务(statistics)的堆栈都设为1,024字节(1Kb)。根据您自己的要求可以增减。μC/OS-II的数据结构最少需要35字节的RAM。
表9.2说明了如何裁减μC/OS-II,应用在更小规模的系统上。此处的小系统有16个任务。
并且不采用如下功能:
?邮箱功能(OS_MBOX_EN设为0)
?内存管理机制(OS_MEM_EN设为0)
?动态改变任务优先级(OS_TASK_CHANGE_PRIO_EN设为0)
?旧版本的任务创建函数OSTaskCreate()(OS_TASK_CREATE_EN设为0)
?任务删除(OS_TASK_DEL_EN设为0)
?挂起和唤醒任务(OS_TASK_SUSPEND_EN设为0)
采取上述措施后, 程序代码空间可以减小3Kb, 数据空间可以减小2,200字节。 由于只有16个任务运行,节省了大量用于任务控制块OS_TCB的空间。在80x86的大模式编译条件下,每一个OS_TCB将占用45字节的RAM。
9.07 运行时间
表9.3到9.5列出了大部分μC/OS-II函数在80186处理器上的运行时间。 统计的方法是将C原程序编译为汇编代码,然后计算每条汇编指令所需的时钟周期,根据处理器的时钟频率,最后算出运行时间。表中的I 栏为函数包含有多少条指令,C 栏为函数运行需要多少时钟周期,μs为运行所需的以微秒为单位的时间。表中有3类时间,分别是在函数中关闭中断的时间、函数运行的最小时间和最大时间。如果您不使用80186处理器,表中的数据就没有什么实际意义,但可以使您理解每个函数运行时间的相对大小。
表 9.1μC/OS-II 内存占用( 80186).
表 9.2 压缩后的μC/OS-II配置.
以上各表中的时间数据都是假设函数成功运行,正常返回;同时假定处理器工作在最大总线速度。平均来说,80186处理器的每条指令需要10个时钟周期。
对于80186处理器,μC/OS-II中的函数最大的关闭中断时间是33.3μs,约1,100个时钟周期。
N/A是指该函数的运行时间长短并不重要,例如一些只执行一次初始化函数。
如果您用的是x86系列的其他CPU,您可以根据表中每个函数的运行时钟周期项估计当前CPU的执行时间。例如,如果用80486,且知80486的指令平均用2个时钟周期;或者知道80486总线频率为66MHz(比80186的33MHz快2倍),都可以估计出函数在80486上的执行时间。
表 9.3μC/OS-II函数在33MHz80186上的执行时间.
表9.3μC/OS-II函数在33MHz80186上的执行时间.(续表)内存管理
表9.3μC/OS-II函数在33MHz80186上的执行时间.(续表)
下面我们将讨论每个函数的关闭中断时间,最大、最小运行时间是如何计算的,以及这样计算的先决条件。
OSSchedUnlock()
最小运行时间是当变量OSLockNesting减为0,且系统中没有更高优先级的任务就绪,SSchedUnlock()正常结束返回调用者。
最大运行时间是也是当变量OSLockNesting减为0,但有更高优先级的任务就绪,函数中需要进行任务切换。
OSIntExit()
最小运行时间是当变量OSLockNesting减为0,且系统中没有更高优先级的任务就绪,OSIntExit()正常结束返回被中断任务。
最大运行时间是也是当变量OSLockNesting减为0,但有更高优先级的任务就绪,OSIntExit()将不返回调用者,经过任务切换操作后,将直接返回就绪的任务。
OSTickISR()
此函数假定在当前μC/OS-II中运行有最大数目的任务(64个)。
最小运行时间是当64个任务都不在等待延时状态。也就是说,所有的任务都不需要OSTickISR()处理。
最大运行时间是当63个任务(空闲进程不会延时等待)都处于延时状态,此时OSTickISR()需要逐个检查等待中的任务,将计数器减1,并判断是否延时结束。这种情况对于系统是一个很重的负荷。例如在最坏的情况,设时钟节拍间隔10ms,OSTickISR()需要625μs,占了约6%的CPU利用率。但请注意,此时所有的任务都没有执行,只是内核的开销。
OSMboxPend()
最小运行时间是当邮箱中有消息需要处理的时候。
最大运行时间是当邮箱中没有消息,任务需要等待的时候。此时调用OSMboxPend()的任务将被挂起,进行任务切换。最大运行时间是同一任务执行OSMboxPend()的累计时间,这个过程包括OSMboxPend()查看邮箱,发现没有消息,再调用任务切换函数OSSched(),切换到新任务。当由于某种原因调用OSMboxPend()的任务又被唤醒执行,从OSSched()中返回,发现返回的原因是由于延时结束(处理延时结束情况的代码最长—译者注),最后返回调用任务。OSMboxPend()的最大运行时间是上述时间的总和。
OSMboxPost()
最小运行时间是当邮箱是空的,没有任务等待消息的时候。
最大运行时间是当消息邮箱中有一个或多个任务在等待消息。此时,消息将发往等待队列中优先级最高的任务,将此任务唤醒执行。最大运行时间是同一任务执行OSMboxPost()的累计时间,这个过程包括任务唤醒等待任务,发送消息,调用任务切换函数OSSched(),切换到新任务。当由于某种原因调用OSMboxPost()的任务又被唤醒执行,从OSSched()中返回,发现返回的原因是由于延时结束(处理延时结束情况的代码最长—译者注),最后返回调用任务。OSMboxPost()的最大运行时间是上述时间的总和。
OSMemGet()
最小运行时间是当系统中已经没有内存块,OSMemGet()返回错误码。
最大运行时间是OSMemGet()获得了内存块,返回调用者。
OSMemPut()
最小运行时间是当向一个已经排满的内存分区中返回内存块。
最大运行时间是当向一个未排满的内存分区中返回内存块
OSQPend()
最小运行时间是当消息队列中有消息需要处理的时候。
最大运行时间是当消息队列中没有消息,任务需要等待的时候。此时调用OSQPend()的任务将被挂起,进行任务切换。最大运行时间是同一任务执行OSQPend()的累计时间,这个过程包括OSQPend()查看消息队列,发现没有消息,再调用任务切换函数OSSched(),切换到新任务。当由于某种原因调用OSQPend()的任务又被唤醒执行,从OSSched()中返回,发现返回的原因是由于延时结束(处理延时结束情况的代码最长—译者注),最后返回调用任务。OSQ`Pend()的最大运行时间是上述时间的总和。
OSQPost()
最小运行时间是当消息队列是空的,没有任务等待消息的时候。
最大运行时间是当消息队列中有一个或多个任务在等待消息。此时,消息将发往等待队列中优先级最高的任务,将此任务唤醒执行。最大运行时间是同一任务执行OSQPost()的累计时间,这个过程包括任务唤醒等待任务,发送消息,调用任务切换函数OSSched(),切换到新任务。当由于某种原因调用OSQPost()的任务又被唤醒执行,从OSSched()中返回,发现返回的原因是由于延时结束(处理延时结束情况的代码最长—译者注),最后返回调用任务。OSQPost()的最大运行时间是上述时间的总和。
OSQPostFront()
此函数与OSQPost()的过程相同。
OSSemPend()
最小运行时间是当信号量可获取的时候(信号量计数器大于0)。
最大运行时间是当信号量不可得,任务需要等待的时候。此时调用OSSemPend()的任务将被挂起,进行任务切换。最大运行时间是同一任务执行OSQPend()的累计时间,这个过程包括OSSemPend()查看信号量计数器,发现是0,再调用任务切换函数OSSched(),切换到新任务。当由于某种原因调用OSSemPend()的任务又被唤醒执行,从OSSched()中返回,发现返回的原因是由于延时结束(处理延时结束情况的代码最长—译者注),最后返回调用任务。OSSemPend()的最大运行时间是上述时间的总和。
OSSemPost()
最小运行时间是当没有任务在等待信号量的时候。
最大运行时间是当有一个或多个任务在等待信号量。此时,等待队列中优先级最高的任务将被唤醒执行。最大运行时间是同一任务执行OSSemPost()的累计时间,这个过程包括任务唤醒等待任务,调用任务切换函数OSSched(),切换到新任务。当由于某种原因调用OSSemPost()的任务又被唤醒执行,从OSSched()中返回,发现返回的原因是由于延时结束(处理延时结束情况的代码最长—译者注),最后返回调用任务。OSSemPost()的最大运行时间是上述时间的总和。
OSTaskChangePrio()
最小运行时间是当任务被改变的优先级比当前运行任务的低,此时不进行任务切换,直接返回调用任务。
最大运行时间是当任务被改变的优先级比当前运行任务的高,此时将进行任务切换。
OSTaskCreate()
最小运行时间是当调用OSTaskCreate()的任务创建了一个比自己优先级低的任务, 此时不进行任务切换。
最大运行时间是当调用OSTaskCreate()的任务创建了一个比自己优先级高的任务, 此时将进行任务切换。
上述两种情况都是假定OSTaskCreateHook()不进行任何操作。
OSTaskCreateExt()
最小运行时间是当OSTaskCreateExt()不对堆栈进行清零操作(此项操作是为堆栈检查函数做准备的)。
最大运行时间是当OSTaskCreateExt()需要进行堆栈清零操作。但此项操作的时间取决于堆栈的大小。如果设清除每个堆栈单元(堆栈操作以字为单位—译者注)需要100个时钟周期(3μs),1000字节的堆栈将需要1,500μs(1000字节除以2再乘以3μs/每字)。在清除堆栈过程中中断是打开的,可以响应中断请求。
上述两种情况都是假定OSTaskCreateHook()不进行任何操作。
OSTaskDel()
最小运行时间是当被删除的任务不是当前任务,此时不进行任务切换。
最大运行时间是当被删除的任务是当前任务,此时将进行任务切换。
OSTaskDelReq()
该函数很短,几乎没有最小和最大运行时间之分。
OSTaskResume()
最小运行时间是当OSTaskResume()唤醒了一个任务,但该任务的优先级比当前任务低,此时不进行任务切换。
最大运行时间是OSTaskResume()唤醒了一个优先级更高的任务,此时将进行任务切换。
OSTaskStkChk()
OSTaskStkChk()的执行过程是从堆栈的底端开始检查0的个数,估计堆栈所剩的空间。
所以最小运行时间是当OSTaskStkChk()检查一个全部占满的堆栈。 但实际上这种情况是不允许发生的,这将使系统崩溃。
最大运行时间是当OSTaskStkChk()检查一个全空堆栈,执行时间取决于堆栈的大小。例如检查每个堆栈单元(堆栈操作以字为单位—译者注)需要80钟周期(2.4μs),1000字节的堆栈将需要1,200μs(1000字节除以2再乘以2.4μs/每字)。再加上其他的一些操作,总共需要大约1,218μs。在检查堆栈过程中中断是打开的,可以响中断请求。
OSTaskSuspend()
最小运行时间是当被挂起的任务不是当前任务,此时不进行任务切换。
最大运行时间是当前任务挂起自己,此时将进行任务切换。
OSTaskQuery()
该函数的运行时间总是一样的。OSTaskQuery()执行的操作是获取任务的任务控制块OS_TCB。如果OS_TCB中包含所有的操作项,需要占用45字节(大模式编译)。
OSTimeDly()
如果延时时间不为0,则OSTimeDly()运行时间总是相同的。此时将进行任务切换。
如果延时时间为0,OSTimeDly()不清除OSRdyGrp中的任务就绪位,不进行延时操作,直接返回。
OSTimeDlyHMSM()
如果延时时间不为0,则OSTimeDlyHMSM()运行时间总是相同的。此时将进行任务切换。
此外,OSTimeDlyHMSM()延时时间最好不要超过65,536个时钟节拍。也就是说,如果时钟节拍发生的间隔为10ms(频率100Hz),延时时间应该限定在10分55秒350毫秒内。如果超过了上述数值,该任务就不能用OSTimeDlyResume()函数唤醒。
OSTimeDlyResume()
最小运行时间是当被唤醒的任务优先级低于当前任务,此时不进行任务切换。
最大运行时间是当唤醒了一个优先级更高的任务,此时将进行任务切换。
OSTimeTick()
前面我们讨论的OSTickISR()函数其实就是OSTimeTick()与OSIntEnter()、 OSIntExit()
的组合。OSTickISR()的时间占用情况就是OSTimeTick()的占用情况。以下讨论假定系统中有μC/OS-II允许的最大数量的任务(64个)。
最小运行时间是当64个任务都不在等待延时状态。也就是说,所有的任务都不需要OSTimeTick()处理。
最大运行时间是当63个任务 (空闲进程不会延时等待) 都处于延时状态, 此时OSTimeTick()
需要逐个检查等待中的任务,将计数器减1,并判断是否延时结束。例如在最坏的情况,设时钟节拍间隔10ms,OSTimeTick()需要约600μs,占了6%的CPU利用率
表 9.4 各函数的执行时间(按关闭中断时间排序).
表9.5 各函数的执行时间(按最大运行时间排序).