简介
对于高性能的嵌入式应用程序所需要的对时间要求严格的响应来说实时性能是不可缺少的例如电信交换设备工业自动化和控制系统医学监视设备和空间导航和制导系统这样的应用程序必须在指定的时间参数以内实时地传递它们的响应
实时性能是什么?对于 Microsoft Windows CE NET OS以下列表定义了实时性能
; 有关高优先级线程调度的担保的上限 — 只针对所有已调度线程中的最高优先级线程
; 调度高优先级中断服务例程 (ISR) 过程中有关延迟的担保上限抢占机制在一个短暂有限的时间内关闭后内核有很少的空间
; 对计划程序和它如何调度线程进行细致的控制
重要的是应当区分实时系统和实时 OS (RTOS)实时系统由满足系统要求所需的所有元素(硬件OS 和应用程序)组成RTOS 只是完整的实时系统的一个元素它必须提供足够的功能才能使全部实时系统能够满足它的要求
尽管以前的 Windows CE 版本提供了某些 RTOS 功能但自从 Windows CE 以后很多重要的内核更改极大地增强了实时性能Windows CE NET 内核包含了与 Windows CE 相同的实时增强功能除此之外还有某些额外的功能本文描述了作为 Windows CE NET 及其以前版本的组成部分的以下更改
Windows CE NET
对 x 平台添加了通过 OEM 定义的变量指定页面池大小的功能
Windows CE
; 增加了线程优先级级别的数目(从 到 )
; 更多地控制时间和调度应用程序可以控制提供给每个线程的时间并操纵对它们有好处的计划程序现在对于与休眠和等待相关的应用程序编程接口 (API)计时器精确到一毫秒
; 处理优先级倒置的方法得到改进
; 全面支持嵌套中断
; ISR 和中断服务线程 (IST) 滞后时间得到减少
; 更细粒度的内存管理控制
此外本文描述了用来测试内核实时性能的工具并提供了在三种不同 CPU 上的实时性能测试结果
返回页首
对内核的更改
内核是 Windows CE OS 的内部核心它负责调度和同步线程处理异常和中断加载应用程序和管理虚拟内存在 Windows CE 中为了提高性能和减少滞后时间内核经历了以下几个更改
; 将所有内核数据结构移动到物理内存从而当在内核中执行非抢占代码时极大地避免了转换后备缓沖区 (TLB) 损失
; 所有非抢占但可中断的内核部分(称为 KCALL)被分割成更小的非抢占节由于增加了节数这就引入了某些复杂性但现在抢占机制能够在更短的时间内关闭
这一节描述为了增强 Windows CE 的实时性能对内核的进一步更改
更多优先级级别
内核的计划程序首先使用较高的优先级级别运行某个线程然后使用相同的优先级以循环方式运行多个线程为线程指派优先级级别是管理执行速度的一种方式
Windows CE 将可用于线程的优先级级别数从 增加到 是最高的优先级 是最低的优先级Windows CE 的前一版本的优先级级别 到 对应于 Windows CE 中级别 到 更多的优先级级别允许开发人员更灵活地控制嵌入式系统的调度并防止由于限制优先级级别数使随机应用程序降低系统性能
要指派这些新的优先级Windows CE 引入了两个新函数CeSetThreadPriority 和 CeGetThreadPriority新函数与 Windows CE 中的 SetThreadPriority 和 GetThreadPriority 函数看起来完全相同不过新函数接受的数字范围是 到
更多地控制时间和调度
Windows CE 已经改进了计时器性能计时器和休眠函数调用的精度达到了一毫秒并且应用程序可以为每个线程设置时间片
计时器(或系统时钟)是一种速率由 OS 以此速率生成计时器中断并对其提供服务以前计时器也是线程时间片是线程没有被抢占的情况下可以在系统中运行的最长时间在 Windows CE 中计时器不再直接与线程时间片相关
以前OEM 将计时器和时间片作为 OEM 适配层 (OAL) 中的常量设置为大约 毫秒计时器触发时如果一个线程已做好准备内核会调度此新的线程在 Windows CE 中计时器总是设置为一毫秒并且可以对每个线程设置时间片
通过将计时器从 OEM 定义的数字更改为一毫秒可以让应用程序执行 Sleep() 函数并预计得到大约一毫秒的精度当然这取决于线程的优先级其他线程的优先级以及是否正在运行 ISR以前Sleep() 经过一个系统周期后返回这意味着如果计时器被设置为 毫秒则 Sleep() 实际上是 Sleep()
计时器中断
现在内核有几个新的变量开发人员可以使用它们确定系统时钟是否需要重新调度通过在适当的时候返回 SYSINTR_NOP 标志而不是 SYSINTR_RESCHED 标志完整实现的系统时钟 ISR 可以防止内核被重新调度Nklib 导出在 Timer ISR 中使用的以下变量
; dwPreempt 是线程被抢占之前的毫秒数
; dwSleepMin 是第一次超时(如果有)到期之前的毫秒数需要重新调度
; ticksleft 是已经过去但尚未被计划程序的休眠队列处理的系统时钟数因而非零值将导致重新调度
在 Timer ISR 中其他逻辑将优化计划程序并防止内核执行不必要的工作如以下代码示例所示
if (ticksleft || (dwSleepMin && (DiffMSec >= dwSleepMin)) || (dwPreempt &&
(DiffMSec >= dwPreempt))) return SYSINTR_RESCHED; return SYSINTR_NOP;
OEMIdle 函数
OEM 实现 OEMIdle 函数在没有要调度的线程时内核将调用该函数在以前的版本中计时器时钟会强制 OS 脱离空闲状态并返回到内核以确定是否线程已做好调度准备如果没有线程做好准备内核再次调用 OEMIdle该操作将导致内核每隔 毫秒(或 OEM 指定的其他时间片长度)被激活一次以确定是否仍然没有要调度的线程在电池供电的设备上这样的操作会耗尽宝贵的电池电量
在 Windows CE 中为了在时钟频率较高的情况下减少耗电量OEMIdle 函数可以让 CPU 进入待机模式一毫秒以上OEM 通过使用 dwSleepMin 和 DiffMSec 变量来编程设置系统时钟计时器以便在第一个可用的超时后唤醒DiffMSec 是自从通过 TimerCallBack 函数检索到最后一次间隔时间以来的当前毫秒值
硬件计时器的最大超时值可能小于 MAX_DWORD 毫秒值所以可以编程设置计时器的最大等待时间在所有情况下系统从空闲状态返回时OEMIdle 函数必须使用已经过去的实际毫秒数更新 CurMSec 和 DiffMSecCurMSec 是间隔时间的当前值 £ 即自从启动以来的毫秒数
线程时间片
在 Windows CE 中线程时间片很灵活足以使应用程序能够逐个线程地设置时间片这就让开发人员可以改编计划程序以满足应用程序的当前需要为了调整时间片已经添加了两个新函数CeGetThreadQuantum 和 CeSetThreadQuantum这项更改使应用程序能够基于线程完成任务所需要的时间量来设置线程的时间片通过将任何线程的线程时间片设置为零循环调度算法可以变为运行到完成算法只有较高优先级的线程或硬件中断才能先于设置为运行到完成的线程执行
默认时间片是 毫秒但在 OEM 初始化阶段OEM 可以通过将内核变量 dwDefaultThreadQuantum 设置为大于零的任何值从而重写系统的默认值
更改处理优先级倒置的方法
为了有助于缩短响应时间Windows CE 更改了它的优先级倒置方法当低优先级线程拥有一个较高优先级线程所需要的内核对象时就会发生优先级倒置Windows CE 使用优先级继承来处理优先级倒置这时被阻塞的拥有较高优先级线程所需要的内核对象的线程将继承更高的优先级优先级倒置使较低优先级线程能够运行并释放资源供较高优先级的线程使用以前内核处理整个倒置链从 Windows CE 开始内核保证只处理优先级倒置到一个级别的深度
优先级倒置有两个基本示例第一个是简单的情况这种情况下对优先级倒置的处理从 Windows CE 到 Windows CE 没有变化例如在有三个处于运行状态的线程时可以看见这种情况线程 A 的优先级是 线程 B 和 C 优先级较低如果线程 A 正在运行并且因为线程 B 拥有线程 A 需要的内核对象而使 A 被阻塞那么线程 B 的优先级会提高到 A 的优先级级别以便允许线程 B 运行然后如果因为线程 C 拥有线程 B 需要的内核对象而使线程 B 被阻塞则线程 C 的优先级会提高到 A 的优先级级别以便允许线程 C 也能运行
第二个并且是更有趣的情况是线程 A 可以以比 B 和 C 更高的优先级运行线程 B 拥有 A 需要的内核对象线程 B 被阻塞等待 C 释放它需要的内核对象而 C 正在运行在 Windows CE 中当 A 运行然后因为 B 而被阻塞时B 和 C 的优先级都会提高到 A 的优先级以便使它们能够运行在 Windows CE 中当 A 因为 B 而被阻塞时只有线程 B 的优先级被提高通过减少复杂性和更改算法极大地减少和限制了 Windows CE 中最大的 KCALL
中断处理和嵌套中断