(转)为提高实时性能,设计和优化 Microsoft Windows CE .NET(中)

(转)为提高实时性能,设计和优化 Microsoft Windows CE .NET(中)
2007-03-13 07:34

内存和实时性能

内核支持几种类型的内核对象,例如,进程、线程、关键节、mutex、事件和信号量。因为 OS 使用虚拟内存,因此所有内核对象都会在虚拟内存中进行分配,因而这些对象的内存是按需分配的。因为按需分配内存可能影响性能,所以无论何时进程开始 OEM 就应当分配内核对象。注意,一旦内核已为内核对象分配了内存,它不会在该对象已被释放以后将内存释放回系统。内核保持该内存池可用;它在需要时重用池中的内存,并在内存池不足时分配更多内存。

可以影响实时性能的内存有三种类型:虚拟、堆和堆栈。

虚拟内存

Windows CE 是充分利用内存管理单元 (MMU) 的、基于虚拟内存的 OS。因为内存分配和解除分配是基于虚拟内存的,所以实时性能可能受到影响。最低级别的内存是虚拟内存,具体地说是虚拟内存 API,例如 VirtualAlloc。在分配虚拟内存的操作期间,内核会搜索可用的物理内存,然后将该内存与进程的虚拟地址空间关联在一起。因为虚拟内存是以 64 KB 为边界分配的,所以虚拟内存 API 不应当用于较小的分配。在处理虚拟内存分配请求期间,内核将从其物理内存池搜索物理内存。取决于正在使用的内存量和内存的碎片情况,搜索内存的时间将各不相同。在实际的托管系统中,所有进程都会从相同的物理内存池访问内存。

为了减少分配虚拟内存的影响,进程应当在继续执行正常处理之前分配和提交所有虚拟内存。

堆内存

虚拟内存之上的下一个级别是堆内存及其相关的 API。堆 API 依赖于虚拟内存 API 用于进行支持的低级别服务。堆中的内存分配不是以 64-KB 为边界的,而是专门用于分配小于 192 KB 的内存。任何超过 192 KB 的分配量都将导致堆管理系统直接使用虚拟内存为分配操作创建单独的堆。

默认堆是在进程被创建时为其创建的。应用程序可以将进程堆用于它的内存分配,并且该堆将相应地增大和缩小。但是,如果在默认堆中内存分配的数量和类型导致堆分成很多碎片,就会导致性能降低。堆分成很多碎片时,它会花费更多时间来尝试为新的内存分配找到空间,这就会影响性能。为了防止在进程中发生碎片,OEM 应当通过为类似的对象创建单独的堆,从而控制内存分配进程。如果存在一个包含大小相同的对象的堆,堆管理器将能够更容易地找到足够大、能够容纳新的分配的可用内存块。但是,即使碎片是可以通过单独的堆来进行管理的,只要在分配内存,仍然有与分配内存相关的开销。

为了降低分配堆内存的影响,在继续执行正常的处理之前,进程应当先分配堆内存。

堆栈内存

在系统中创建新线程时,内核会为堆栈保留内存。为堆栈保留的内存量由在生成模块时被传递给链接器的 /STACK 参数确定。Windows CE 组件的默认堆栈大小是 65 KB。第一次调度线程时,将提交线程的堆栈内存;堆栈内存一次提交一页,并且只在需要时提交。

为了防止初始堆栈内存提交影响性能,应当确保在执行实时处理之前线程被调度至少一次。在 IST 情况下,通常会发生这种情况,这是因为在进入 WaitForSingleObject 循环之前线程将执行几个操作。如果线程只是需要初始堆栈分配,则可以避免进一步的堆栈提交。因为通常在 Windows CE 环境中内存很少,所以,有时内核将从不再需要堆栈内存的线程那里收回堆栈内存。OEM 控制该过程的计时以及传递给 SetOomEvent 的参数。如果传递给 SetOomEvent 的值触发了对堆栈内存的搜寻,则从堆栈删除内存时,内核将挂起每个有可用堆栈的线程。要避免这种情况,请小心设置 SetOomEvent 的内存使用参数。

页面表池大小

在 Windows CE .NET 中,创建了一个新的 OEM 变量,称为 dwOEMPTPoolSize。在 x86 平台上,这个变量允许 OEM 定义被内核用来维护每个进程的内存页列表的虚拟内存页面表数据结构的大小。默认值是 16 页,最大值是 512 页。取决于系统,OEM 必须增加该值,直到找到正确的适当大小为止。页面表池结构的大小可能影响为了将内存映射到相同进程中的不同区域、或映射到不同进程而必须将页面池归零的频率。当页面表数据结构中没有可用的指针时,将发生页面归零。由于安全原因,页必须先归零然后才能被指派给新的进程。将几个页归零的动作可能对实时平台的 IST 滞后时间造成负面影响。但是,OEM 还必须通过使结构变得更大来平衡该问题,这将会增加平均进程切换时间,因为内核需要重置结构中每个页指针的权限。因为该变量只在 Windows CE .NET 和更高版本中可用,因此为使用 Windows CE 3.0 的开发人员创建了快速修复工程 (QFE) 主题,该主题将静态大小设置为页面表池大小。有关详细信息,请参阅 Microsoft Web site,打开 Readme.txt 文件,然后搜索 QFE 33。

实时测量工具

Windows CE 3.0内核的更新包括两个内核级别的工具:中断计时分析 (ILTiming) 和计划程序计时分析 (OSBench)。它们用来测试内核的实时性能,并测量具体的滞后时间。性能数字是特定于硬件的,这取决于 CPU 类型和速度、内存体系结构以及缓存组织和大小。

中断计时分析 (ILTiming)

对 ISR 和 IST 滞后时间的测量已经被结合在 ILTiming 测试工具(以前称为 IntrTime)中,它以源代码的形式提供,并且与 Microsoft Platform Builder 一起分发。进行测量时将使用系统时钟计时器,以便使 ILTiming 可用于运行 Windows CE 的所有硬件平台,因为某些平台不支持单独可用、而没用到的计时器。

在正常情况下,系统时钟会以固定间隔中断内核。然后,相关的系统计时器 ISR 将处理时钟并返回 SYSINTR_NOP 指导内核忽略时钟,或返回 SYSINTR_RESCHED 唤醒计划程序。

ILTiming 测试工具测量滞后时间的方法是:将系统时钟默认值的每隔 n 次时钟周期的 n 值取为 5,即每隔五次系统时钟周期,然后通知特殊的 SYSINTR_TIMING 中断标识符事件。ILTiming 应用程序的主线程等待 SYSINTR_TIMING 中断事件,因而变成 IST。ISR 和 IST 测量值是从时间戳派生的 £­ 即自从上次系统时钟周期后高分辨率计时器的计数器值。

因为 ILTiming 只需要对 OAL 进行特殊的修改,而不会修改内核,所以它可以很容易地改编,并可运行在任何 OEM 平台上。

ILTiming 命令提示符参数

ILTiming 命令提示符参数允许进行以下更改:

将 IST 设置为运行在各种优先级上

每个中断之后刷新或不刷新缓存

更改 ISR 速率和被捕获的中断数

将收集到的结果打印或输出到文件

可用以下 ILTiming 命令提示符参数:

Usage: iltiming [ options ]
Options:
   -p num           Priority of the IST (default 0 ; highest)
   -ni              no idle priority thread 
   -i0              no idle thread (same as -ni)
   -i1              Run idle thread type 1
   -i2              Run idle thread type 2
   -i3              Run idle thread type 3
   -i4              Run idle thread type 4
   -i5              Run idle thread type 5
   -t num           SYSINTR_TIMING interval (default 5)
   -n num           number of interrupts (default 10)
   -all             print all data (default: print summary only)
   -o file          output to file (default: output to debug)
   -h               Display the help screen

IST 可以运行在不同的优先级级别 (-p) 上。默认情况下,应用程序将在每次运行之前刷新缓存。选项 -ncs 禁用 CacheSync 调用。-t 选项设置 ISR 速率,每隔 t 次时钟周期,系统时钟 ISR 返回 SYSINTR_TIMING

ILTiming 还可以创建一个或多个运行在后台的空闲线程。通过允许内核处于必须在运行 IST 之前完成的非抢占内核调用中,这将影响 IST 滞后时间。可用以下五种类型的空闲线程:

空闲线程 1:一个只是运行的线程,不做任何事情

空闲线程 2:一个执行 SetThreadPriority(IDLE) 的线程

空闲线程 3:两个交替执行 SetEventWaitForSingleObject 函数的线程,超时时间为 10 秒。

空闲线程 4:两个交替执行 SetEventWaitForSingleObject 函数的线程,超时时间无限。

空闲线程 5:一个调用 VirtualAllocVirtualFree 的线程,超时时间无限。专门用于刷新缓存和 TLB。

外部中断响应测量

为了快速评估系统的日常实时性能,使用中断计时分析工具足以确定 ISR 和 IST 中断滞后时间。这个方便的方法对所有受支持的处理器有效,但它依靠设备本身的计时器,而这可能会影响测量。

因而,可以用一个更细致的设置来准确地测量 ISR 和 IST 滞后时间。可以设置以下两个机器:

工作站,用于生成外部中断,并测量从 ISR 和 IST 例程收到确认信号所花费的时间。

测试中的设备,用于接收外部中断,并在 ISR 和 IST 例程到达时切换输出行。

测试是在各种压力级别下执行的,测试运行在测试设备上不同优先级的从一到数百个线程的任何地方。

基于 Microsoft Windows NT 4.0 的工作站(配备了 National Instruments PC-TIO-10 数字 I/O 计时器/计数器卡)用来生成中断和时间响应,一个配备相同卡的 CEPC 目标平台用来响应这些中断。Windows NT 软件利用由 National Instruments 提供的驱动程序库,而 Windows CE 软件由 Microsoft 编写。

操作理论很简单:PC-TIO-10 卡有两组计时器,每组有五个计时器。每一组包含一个可提供 200 个十亿分之一秒分辨率的计时器,而其他计时器有一微秒的粒度。此外,该卡包含两组(每组八条)数字 I/O 线,每一组提供一条线可以用于边缘或层次触发的中断。基于 Windows NT 的机器的一条输出线被连接到 CEPC 目标平台的外部中断引脚,并接回基于 Windows NT 的工作站的卡上的计时器。

基于 Windows NT 的工作站声明一条输出线时,它将在 CEPC 目标平台上生成中断,并在 Windows NT 卡上启动 ISR 和 IST 计时器。CEPC 目标平台上的 ISR 通过声明一条该卡上的输出线来确认收到了中断,而这会在基于 Windows NT 的工作站上停止 ISR 计时器,并通知内核来调度 IST。IST 开始运行时,它将声明不同的输出线,从而在基于 Windows NT 的工作站上停止第二个计时器。这时,基于 Windows NT 的工作站可以读取计时器计数器上的值,以确定所生成的中断和 CEPC 目标平台的响应之间的间隔。一旦基于 Windows NT 的工作站已经读取计数器值,它就会立即发出另一个中断,CEPC 目标平台使用该中断将所有输出线设置为待机状态,从而为另一个循环做好准备。

使用上面的测量方法所收集的初步结果确认了 ILTiming 测试结果的准确性。

计划程序计时分析 (OSBench)

OSBench(以前称为 CEBench)是 Windows CE 3.0 和更高版本中附带的性能工具。它用于测试计划程序性能计时,重点测量执行基本内核操作(例如,以下的同步操作)所需要的时间:获得关键节需要多长时间、调度线程等待另一个线程刚刚设置的事件需要多长时间,等等。一旦合适,测试将运行两组指标:进程内的线程到线程,和跨越进程的线程到线程。如果合适,运行测试时可以应用压力套件。

在 Windows CE 中,OSBench 为以下性能指标收集计时示例:

获得/释放关键节(快速方式和传统方式)

等待/通知事件(单独等待并自动重置)

信号量

Mutex

使用 Sleep(0) 自动产生

与上述产生/运行情形不同的指标是对互锁 API 和系统调用开销的计时。这些指标是互锁递增/递减、互锁交换和系统 API 调用开销。

以下示例代码说明了 OSBench 命令提示符参数。

Usage: osbench [ options ]
Options:
   -all          Run all tests (default: run only those specified by -t option)
   -t num        ID of test to run (need separate -t for each test)
   -n num        Number of samples per test (default = 100)
   -m addr       Virtual address to write marker values to (default = )
   -list         List test IDs with descriptions
   -v            Verbose : show all measurements
   -o file       Output to CSV file (default: output only to debug)
   -h            Display the help screen
OSBench –list
TestId 0 : CriticalSections
TestId 1 : Event set-wakeup
TestId 2 : Semaphore release-acquire
TestId 3 : Mutex
TestId 4 : Voluntary yield
TestId 5 : PSL API call overhead

与 ILTiming 测量方法一样,QueryPerformanceCounter 函数调用被用于获得计时信息。此外,在调用 QueryPerformanceCounter 的每个计时点,用户可以指定将具体的标记值写入虚拟地址。通过在 OSBench 开始时在命令提示符中提供虚拟地址,可以启用该硬件验证功能。然后,在虚拟地址写入的标记可以用分析器(用外部设备单独计时)进行监视,并用结果仔细检查 QueryPerformanceCounter 计时准确性。类似中断滞后时间的外部测量的设置可以用于该目的。

使用 QueryPerformanceCounter 函数调用来获得时间戳时,在分析结果时必须考虑在特定平台上计数器的频率,以及调用该函数的开销。在最后的计时数字中正确排除测量开销时要小心进行。在每次测试之前,QueryPerformanceCounter 调用将循环进行很多次迭代,并从最后结果中减去平均值。

操作用非常短的时间即可完成时,QueryPerformanceCounter 函数调用的开销将变得很重要。在这些情况中,操作将循环进行固定的次数(即每个样本迭代 (IPS) 次),该次数由每个测试清楚地给出,然后对结果求平均值。如果启用了硬件验证,将为这些情况提供特殊的子标记值。该循环的副作用是无法在操作的每次迭代之间刷新缓存。对于 IPS 等于 1 的其他测试,测试将运行两次,一次有而一次没有对每次迭代的缓存刷新。

以下示例代码显示了 OSBench 测试输出。

==================================================
|   1.00   |   IP =   NO   |   CS =   NO   |        1 IPS
--------------------------------------------------
Event intraprocess :
Time from SetEvent in one thread to a blocked 
               WaitForSingleObject() 
waking in another thread in the same process.
--------------------------------------------------
|   Max Time =          10.057 us
|   Min Time =           5.867 us
|   Avg Time =           6.823 us
==================================================

在测试数字为 1.00 的示例中(其输出显示在上面),操作对进程内事件同步对象计时。IPS1 是 1;每次运行后没有执行 CacheSync (CS);进程间状态 (IP) 显示,第二个进程没有被使用 £­ 两个线程都在相同进程中。100 次操作的最大、最小和平均的结果是如果在命令提示符下没有指定任何内容时的默认值,它以微秒给出。测试的基本套件和 OSBench 程序的总体布局使得添加新的测试用例和测量方法很容易,而这补充了可能有特殊意义的特定内核函数的实现。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值