在实时操作系统中,线程调度花费的时间是一个值得关注的影响系统实时性的因素,尤其是在系统需要处理紧急的任务时,线程调度的时间更是不能忽略。我采用了一种测量GPIO输出正脉冲宽度的方法,测量出了RT-Thread系统线程调度所需的时间。
实验中,我使用了GD32F103系列单片机,单片机的系统时钟为108MHz,内核为Cortex-M3,实时操作系统采用了RT-Thread V3.1.5。实验的目的是测量了SysTick中断引起的线程调度所花费的时间。
实验设计
为了较准确地测量SysTick中断引起的线程调度所花费的时间,需要保证每次进入Systick中断都会引起线程调度。因此,我把代码中多于的线程都删掉,只保留了main_thread和rt_thread_idle两个线程。介绍一下这两个线程,它们是RT-Thread内核初始化时由系统创建的两个线程,main_thread用于跑main函数(RT-Thread中main函数也是一个线程),idle线程是当其他所有高优先级线程都被挂起时才会运行的线程。RT-Thread内核初始化时还会创建一个timer_thread,但是实验中我把它的创建函数注释掉了。将main_thread和rt_thread_idle两个线程设置成相同优先级,并且都只分配一个时间片,两个线程中的while(1)死循环中不做任何事情,即线程满负荷运行,这样,RT-Thread的时间片轮转机制会使每次SysTick中断都引起一次线程调度,而且只有SysTick中断会产生线程调度。
RT-Thread的上下文转换代码是用汇编语言写在PendSV中断里。PendSV中断的特点是能够延迟上下文切换的请求,直到其它的中断请求都完成了处理后才执行,处理流程如下图所示。 SysTick中的代码将悬挂一个PendSV中断请求,当SysTick中断返回后就开始执行PendSV中的上下文切换,实现任务调度。我将GPIO输出电平拉高的代码放在SysTick_Handler中断处理函数的最后一行,GPIO输出电平拉低的代码放在了PendSV_Handler中断处理函数返回前,然后用示波器测量正脉冲宽度就可以知道线程调度花费的时间。
void SysTick_Handler(void)
{
/*如果想测量执行SysTick中断和PendSV中断共需要多长时间, */
/*可以吧GPIOC->BOR = GPIO_PIN_11放在SysTick_Handler开头*/
/* enter interrupt */
rt_interrupt_enter();
run_freq++;
rt_tick_increase();
/* leave interrupt */
rt_interrupt_leave();
/*GPIO初始化代码可以写在main函数进入while(1)之前*/
/*为了减少IO口电平变化代码的执行时间,提高测量精度,这里直接操作寄存器拉高输出电平*/
GPIOC->BOR = GPIO_PIN_11;//拉高IO输出电平
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
;PendSV是用汇编写的,这里只贴出一部分
GPIOC_BASE EQU 0x40011000 ;GPIOC寄存器基地址,EQU类似C语言的#define
GPIOC_BCR EQU GPIOC_BASE+0x14 ;GPIOC的BCR寄存器地址
GPIOC_BOR EQU GPIOC_BASE+0x10
SET_BIT EQU 0x0800 ;用于寄存器第11位置1
pendsv_exit
; restore interrupt
MSR PRIMASK, r2
ORR lr, lr, #0x04
LDR r4, = GPIOC_BCR
LDR r5, = SET_BIT
STR r5, [r4] ;这句等价于C语言的 *r4 = r5,拉低IO输出电平
BX lr
ENDP
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
(关于C语言调用汇编函数的方法可以参考我的另一篇博文
Cortex-M3寄存器组、汇编语言与C语言的接口介绍
)
实验结果
上图测量的是PendSV_Handler执行上下文切换所需要的时间,即前面贴出的代码那种写法所产生的正脉冲宽度。图中,示波器水平方向一格为1μs,正脉冲宽度是0.7μs。
上图测量的是SysTick_Handler和PendSV_Handler执行上下文切换总共需要的时间,图中,示波器水平方向一格为10μs,正脉冲宽度是7.5μs。
线程调度时间按0.7μs算,SysTick中断频率为1KHz,1s内产生1000次线程调度,共用时0.7ms,CPU有0.07%的时间在进行线程调度。只要合理设计实验,用这种方法还可以测量实时操作系统中各种内核对象运行的时间,比如信号量release到线程恢复运行的时间,阻塞延时的准确性等。