μC/OS-II系统下的代码执行时间测量方法

2013-08-24 00:43雷金奎邵元元
计算机工程与应用 2013年5期
关键词:调用中断代码

雷金奎 ,邵元元 ,田 力

1.西北工业大学 第365研究所,西安 710065

2.西北工业大学 电子信息学院,西安 710072

3.西安爱生技术集团公司,西安 710065

1 引言

实时系统是能够在指定的时间内完成系统功能和外部或内部、同步或异步事件做出响应的系统[1]。实时系统中,计算的正确性不仅取决于程序的逻辑正确性,也取决于结果产生的时间。如果系统的时间约束条件得不到满足,将会发生错误,造成重大的生命财产损失和生态破坏。因此,实时系统应该具备在事先定义的时间范围内识别和处理离散事件的能力;能够处理和存储控制系统所需要的大量数据。

提出了一种基于μC/OS-II实时操作系统的代码执行时间测量方法,并使用Microsemi SoftConsole IDE v3.3开发环境,在基于Cortex-M3核的SmartFusion主控芯片上实现了相关的代码。本文测量了μC/OS-II在SmartFusion平台下的一些实时性指标,为代码的实时性提供了一个时间上的参考,为提高系统的实时性提供了保障[2-3]。

2 μC/OS-II多任务环境下的时间测量方法

在微机系统中,往往可以处理多个中断和多个任务。代码在执行过程中,随时可能被中断,然后CPU将控制权转移给中断服务例程;也可能将控制权转移给其他任务。这些原因,导致在μC/OS-II多任务环境下,测到的代码执行时间的不确定性[4]。

2.1 测量代码执行时间的原理

测量一段代码C的执行时间,一种比较直观的想法是这样的:先读取系统时钟值TS,然后执行待测代码段C,最后再读取时钟值TE,得出待测代码段的执行时间TC=TE-TS。将在这个基本想法上进行改进和扩充,使最终得到的时间TC中,去除时间测量函数自身、中断和任务切换的影响。由于执行代码前后各有一次读取当前时刻值的操作,因此可以把前后两次时刻读取过程及相关的操作封装为一对时间测量函数对。然后,可以把函数对中的两个函数分别放到代码段C之前和之后,执行完代码段C和时间测量函数对之后就能得出代码段C的执行时间。

考虑到时间测量函数自身、中断和任务切换的影响,待测代码段C的实际执行时间(占有CPU的时间),可以表示如下:

其中,TE为代码C结束执行的时刻,TS为开始执行代码C的时刻,Tint为代码C被中断服务例程中断的总时间,Tprof为测量代码本身引入的测量总偏差。Tenter_exit为进入中断和退出中断所需的时间,Toffset_int是执行一次中断时间测量函数对所需要的时间,Tint_exec为中断服务代码的执行时间。Toffset为执行一次时间测量代码对所需的时间;Tin_offset是执行时间测量函数对的过程中,两次时刻读取之间的代码的执行时间;Tin_offset_int是执行中断时间测量函数对的过程中,两次时刻读取之间的代码的执行时间。因为两个函数对中代码不完全相同,所以两次时刻读取之间的代码执行时间就不同。

为了消除中断的影响,本文对所有的中断服务历程的执行时间进行了测量,以便扣除中断服务例程的执行时间,得到代码段的准确执行时间。

2.2 栈空间与多任务环境下的时间测量

在多任务环境下,任务都有自己的栈空间和上下文环境。当进行任务切换的时候,把当前任务的上下文环境保存到自己的栈空间,然后把下一个任务的上下文环境从它的栈空间中恢复到寄存器中,CPU的控制权就从一个任务转移到了另一个任务。

考虑到测量时间的过程中,可能会发生任务切换、中断等,给每个任务分配一个时间测量栈。用随着任务的切换而切换栈,来处理多任务下的时间测量问题。如图1所示,任务task0、task1、…、task N的时间测量栈分别是task0_stack、task1_stack、…、task N_stack,指针数组task_stk_top[]保存着未处于运行状态的任务的时间测量栈栈顶,指针cur_stk_top跟踪着当前运行的那个任务的时间测量栈栈顶。

当任务切换的时候,比如从task1切换到task0,把cur_stk_top保存到task_stk_top[1],然后将task_stk_top[0]赋给cur_stk_top。这样,当前活跃的就是task0的栈了。

任务的时间测量栈如图2所示,它的栈元素是结构体struct cp_time_prof_node_t,定义如下:

图1 多任务环境下的时间测量栈

图2 每个任务的栈空间

其中,成员变量Ts是待测代码段的开始时刻;Terr是中断、任务切换和时间测量代码引入的时间测量偏差,即式(1)中的Tint+Tprof;pnode是前一个栈元素的指针。

待测量代码执行完毕后,读取当前时刻Te,并根据式(1)、式(2)和式(3)算出它的执行时间,并把执行时间等信息保存到数组struct cp_cp_time_prof_t cp_time_prof[],对最终结果进行保存。它的定义如下所示,其中,成员变量nb_of_states是待测代码段总共测量的次数,total_exec_time是总共执行时间,max_time、min_time分别是最大执行时间和最小执行时间。

2.3 函数及其流程

本文定义了五个函数,定义及功能:

函数time_init()用于初始化与时间测量相关的数据。

这一对函数,构成测量代码执行时间的函数对,用于测量代码的执行时间。

这一对函数,构成测量中断服务代码执行时间的函数对,用于测量中断服务代码的执行时间,并把对被中断的代码的执行时间上的影响记录下来,方便被中断的代码计算自身的执行时间。

μC/OS-II中,每次切换任务上下文的时候要调用这个函数。这个钩子函数在任务切换时,切换任务所使用的时间测量栈。

测量代码执行时间的流程:

(1)调用cp_time_init()进行时间测量相关代码初始化;

(2)调用cp_time_prof_start(cp_time_prof_id_t id)开始测量,参数id是以后测量结果在数组cp_time_prof[]中的存储位置的索引;

(3)执行待测代码段;

(4)调用 cp_time_prof_end(cp_time_prof_id_t id)结束测量;

(5)转步骤(2),开始测量下一段代码的执行时间。

函数void cp_time_init()对时间测量相关数据的初始化流程:

(1)初始化系统时钟;

(2)屏蔽所有中断;

(3)初始化所有任务的时间测量栈、栈顶指针task_stk_top[]和当前活跃任务的栈顶cur_stk_top;

(4)初始化存储测量结果的数组cp_time_prof[],令其所有成员存储的最大执行时间为0,最小执行时间为(unsigned)-1,总执行时间为0,统计次数为0;

(5)计算 Toffset、Tin_offset、Toffset_int和 Tin_offset_int的值;

(6)除屏蔽所有中断。

函数void cp_time_prof_start(cp_time_prof_id_t id)的流程:

(1)屏蔽所有中断;

(2)读取当前系统时刻;

(3)入栈,用新的栈顶元素的成员变量Ts保存当前时刻,新栈顶元素的成员Terr赋Tin_offset,pnode赋上一个元素的地址形成链表,把输入参数赋给id;

(4)除屏蔽所有中断。

函数 void cp_time_prof_end(cp_time_prof_id_t id)的流程:

(1)屏蔽所有中断;

(2)读取当前系统时刻,记为Te;

(3)设待测代码执行时间为Tc,则Tc=Te-Ts-Terr,把结果记录到cp_time_prof[id]中;

(4)出栈,把原栈顶的处理过程对新栈顶的影响时间加到新栈顶的Terr上;即把原栈顶的成员变量Terr加到新栈顶的Terr上,时间测量函数对执行一次引入的偏差Toffset也要加到新栈顶的Terr上;

(5)除屏蔽所有中断。

void cp_time_prof_start_int(cp_time_prof_id_t id)和void cp_time_prof_start(cp_time_prof_id_t id)函数的流程很相似,仅仅是给Terr赋的初值不同:

(1)屏蔽所有中断;

(2)读取当前系统时刻;

(3)入栈,用新的栈顶元素的成员变量Ts保存当前时刻,新栈顶元素的成员Terr赋Tin_offset_int,pnode赋上一个元素的地址形成链表,把输入参数赋给id;

(4)除屏蔽所有中断。

函数void cp_time_prof_end_int(cp_time_prof_id_t id)的流程:

(1)屏蔽所有中断;

(2)读取当前系统时刻,记为Te;

(3)设待测代码执行时间为Tc,则Tc=Te-Ts-Terr,把结果记录到cp_time_prof[id]中;

(4)出栈,把中断处理过程对新栈顶的影响时间加到新栈顶的Terr上;即把中断服务例程的执行时间Tc加到新栈顶的Terr上,中断时间测量函数对执行一次引入的偏差Toffset_int和进入退出中断所需的时间Tenter_exit也要加到新栈顶的Terr上;

(5)除屏蔽所有中断。

函 数 void cp_time_prof_CtxSw_hook(uint32_t cur,uint32_t next)是μC/OS-II的任务切换函数void OS_TASK_SW()调用的钩子函数,它完成的操作就是当任务切换的时候,比如从task1切换到task0,把cur_stk_top保存到task_stk_top[1],然后将 task_stk_top[0]赋给 cur_stk_top。这样,当前活跃的就是task0的栈了。

另外,在系统时钟中断服务例程中,需要维护系统时间供时间测量函数使用。

3 μC/OS-II多任务环境下实时时间参数的测量实例

使用SoftConsole IDE v3.3集成开发环境,使Smart-Fusion主控芯片工作在100 MHz,片内RAM 20 kB,对代码最大优化条件下,测量了μC/OS-II的任务切换时间、抢占时间和信号洗牌时间[5-6]。

(1)上下文切换时间(任务切换时间)[7]:μC/OS-II会调用OS_TASK_SW()进行实际的上下文切换。OS_TASK_SW()是宏调用,含有微处理器的软中断指令,利用此中断来实现任务之间的上下文切换。在移植μC/OS-II的时候,使用了PendSV软中断来实现任务切换,因此任务切换时间其实就是PendSV中断服务例程的执行时间。在中断服务函数代码调用void cp_time_prof_start_int()之后,紧接着调用void cp_time_prof_start(),在调用void cp_time_prof_CtxSw_hook()之前,调用 void cp_time_prof_end(),得出PendSV中断前半部分的执行时间t1。在调用void cp_time_prof_CtxSw_hook()之后,紧接着调用void cp_time_prof_start(),并在中断服务函数代码调用void cp_time_prof_end_int()之前,调用void cp_time_prof_end(),得到PendSV中断后半部分的执行时间t2。最后算出任务切换时间t1加t2再加上进入和退出中断的时间得到总时间0.75μs。

(2)抢占时间[8]:抢占时间即系统将控制权从低优先级的任务转移到高优先级任务所花费的时间。在μC/OS-II中,调用函数void OS_Sched()来寻找当前就绪的最高优先级任务,并移交CPU控制权给这个任务。因此,只需测量函数void OS_Sched()的执行时间,再加上上下文切换时间就是抢占时间。在void OS_Sched()的开始和结束处,分别调用void cp_time_prof_start()和void cp_time_prof_end(),得到void OS_Sched()的执行时间0.91μs,加上任务切换时间得到抢占时间1.66μs。

(3)信号洗牌时间:指从一个任务释放信号量到另一个等待该信号的任务被激活的时间延迟。μC/OS-II是通过INT8U OSMutexPost()来释放信号量的。在 INT8U OSMutexPost()的开始和结束处,分别调用void cp_time_prof_start()和 void cp_time_prof_end()。编写两个任务,高优先级的那个任务等待低优先级任务释放信号量。INT8U OSMutexPost()的执行时间是2.38μs,加上任务切换时间,得出信号洗牌时间是3.13μs。

4 结束语

提出了一种基于μC/OS-II实时操作系统的代码执行时间测量方法,并用它测量了μC/OS-II实时操作系统在SmartFusion+SoftConsole平台上的一些时间指标。用这个方法,可以比较准确地测量代码执行的时间,在代码优化阶段可以用它来评估代码优化的实际效果,具有很强的实用意义。

[1]魏忠.嵌入式开发详解[M].北京:电子工业出版,2003.

[2]Labrosse J J.μC/OS-II——源码公开的实时嵌入式操作系统[M].邵贝贝,译.北京:中国电力出版社,2001.

[3]Yiu J.ARM Cortex-M3权威指南[M].宋岩,译.北京:北京航空航天大学出版社,2009.

[4]中兴通讯股份有限公司.程序片断执行时间的测量方法及装置:中国,200910167583.6[P].2010-01-27.

[5]李江,戴胜华.Linux操作系统实时性测试及分析[J].计算机应用,2005,25(7):1679-1681.

[6]唐建国,张钟澍,吴钦章.Linux下代码运行时间的高精度测量[J].计算机工程与应用,2005,41(18):103-105.

[7]江建慧,唐智杰.测量嵌入式操作系统实时性能参数的新方法[J].同济大学学报,2008,36(9):1260-1266.

[8]王挺,丁志刚,阎梦天,等.实时操作系统内核时间参数的测量[J].计算机应用与软件,2009,26(7):59-61.

猜你喜欢
调用中断代码
核电项目物项调用管理的应用研究
LabWindows/CVI下基于ActiveX技术的Excel调用
创世代码
创世代码
创世代码
创世代码
跟踪导练(二)(5)
千里移防,卫勤保障不中断
基于系统调用的恶意软件检测技术研究
利用RFC技术实现SAP系统接口通信