PeekMessage: 优化应用以延长电池使用时间

提交新文章

2009年02月14日 07:00


介绍
作者:Dale Taylor

本文介绍了 PeekMessage 调用是否对电池使用时间产生影响,并列举替代代码样例,以及预计可在 Windows* 上做出的改进。

在探讨针对电池供电设备上运行的应用的优化技巧时,一些应用开发人员怀疑或者不了解关注这一问题的必要性。为更好地了解这一必要性,在具体实例上对某些指标进行详细研究将大有帮助。本文着重介绍了 PeekMessage 调用的使用及其对电池使用时间的影响(如果存在)。还解释了为什么存在这种可能性,并讨论原因,列举替代代码样例,以及在解决 PeekMessage 对 Windows* 的影响方面预计可以做出的改进。本文利用一个样例程序和英特尔移动软件计划技术开发员套件 (MSI TDK) 的电源评估工具,来衡量从 PeekMessage 调用切换到 GetMessage 调用时的实际变化。

PeekMessage
MSDN 文档包含有关 PeekMessage 的以下问题:
第一:一个应用应该在尽可能短的时间内使用 PeekMessage() 循环。为支持电池供电的计算机、并优化系统性能,基于 Windows 的所有应用都应尽快、频繁地通知 Windows 其处于闲置状态1

尽管 MSDN 的作者意识到 PeekMessage 可能引起与功耗相关的问题,但要了解如何以及为何,需要进一步研究。为进一步说明使用 PeekMessage 的副作用,我们引述了其它 MSDN 文章中的内容:
第二:PeekMessage() 循环功耗较低,在后台处理完成后即退出,因为如果 PeekMessage() 循环中存在应用,则 Windows 无法处于闲置状态2

PeekMessage 多年来作为消息循环的主要组成部分,广泛用于许多传统应用,因此解决应用的功耗问题就至关重要。基本上,PeekMessage 调用使系统频繁地检查消息,因此系统始终被占用。此处讨论 PeekMessage 时,可以使用“与孩子出行的例子”作类比。他们总是不停地问你:“我们到了吗?”你会匆匆看一眼信息,然后不断问 Windows 是否有你的信息。你仍然可以使用 PeekMessage,但是需要注意隐藏的功耗问题,并在程序真正处于闲置状态时启用相应的闲置状态。一个应用的编写可以降低功耗,允许 windows 处于闲置状态,还可以监控应用处于闲置状态(不处理消息)的大致时间。由于很难正确使用 PeekMessage,因此设计人员设计出了处理 PeekMessage 潜在问题的替代方法。

有一种方法,可以直接控制在您的应用中如何使用 PeekMessage,就是建立您自己的消息循环。确保您包含微软基础类库*(MFC)主消息循环中的必要元素,这样你的应用就可以直接控制消息泵。以下列出了与微软基础类库兼容的一个简短的伪代码示例。

while ( bDoingBackgroundProcessing ) 
{
MSG msg;
while ( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
if ( !PumpMessage( ) )
{
bDoingBackgroundProcessing = FALSE;
::PostQuitMessage( );
break;
}
}
// let MFC do its idle processing
LONG lIdle = 0;
while ( AfxGetApp()->OnIdle(lIdle++ ) )
;
// Perform some background processing here
// using another call to OnIdle
}


仔细分析该代码,你会发现只要存在闲置处理,就将调用 PeekMessage。PumpMessage 用于执行正常的消息转换和调度。在使用该代码时的问题在于 PumpMessage 调用。该源代码可以在 ThrdCore.cpp 中找到,但未正式公开,因此在将来的版本中可能随时做出更改(但现在做不到)。

现在,有一种方法可以管理较短时间和较少工作的方法,与帮助 Windows 了解何时休眠和保存电量的方法一致。如果你想要确定应用应何时休眠并直接保存电量,应使用 WaitMessage 调用。WaitMessage 能够直接控制您的应用何时进入休眠状态。回到“与孩子出行”这个类比,当您让孩子使用 PeekMessage 方法时,他们会不停地问你“我们到了吗”。使用 WaitMessage 就好比告诉孩子们:“我们正在前进,你们睡一会,等我叫醒你们的时候就到了。”利用 WaitMessage 可以释放系统资源,使其用于其它任务,正如您可以在开车时让孩子们睡觉一样。以下介绍了一些简单的伪代码,明确说明了如何实现这一点。

if (PeekMessage(...) != NULL)
// IF there is a message, translate & dispatch it
else if (there is background processing to do)
// do your background processing
else
// No background processing, no messages waiting - go to sleep
WaitMessage();

按照上述伪代码,编写可以自我管理的应用,将帮助改进电池供电的系统的耗电情况。

利用英特尔的电池监视工具评估样本应用
根据 MSDN 文档和上述举例,很明显 Windows 在进行 PeekMessage 调用时,本身不允许应用进入休眠状态。为验证这一研究成果,研究人员获得了一些实际指标来支持这一点。研究人员开发了一个小应用,以模拟这些调用可能造成的影响。该应用在一定时间内利用 PeekMessage 或 GetMessage 调用,以监视输入窗口。系统会建立多个不同版本的样本应用,进行不同调用,运行时间也不同。为监视该程序对系统耗电情况的影响,英特尔移动支持团队内部开发了电源评估工具。该工具被用于运行不同程序并确定不同测试的电池使用情况。

这些测试经过精心设计,使一个程序只进行 PeekMessage 调用,而另一程序只进行 GetMessage 调用。在实际应用中,这些情形会混合出现。这种极端的测试情形有助于使我们更清楚地看到 message 调用的不同之处。为更好地了解下述成果,你需要对电源评估工具有所了解。下表中的模式设置是指电源评估工具所支持的两种模式。模式 1 只运行应用,直到其自动终止(应用具有一个计时外观)。模式 2 在运行应用的同时,监视后台,以对后台资源使用情况和后台及应用结合使用情况进行对比。因此模式 2 测试可以提供关于耗电情况的一些额外信息。这些测试利用一块新电池在 IBM T41* 上运行。每项测试开始时,电池被充至 96-98%。T41 安装了英特尔 IT 架构。参见附录,了解关于 IT 架构的更多详情,其中包括监视软件、支持工具、病毒扫描程序等。



表 1 Peek 与 Get 的结果 #1 (Click image for larger version)

当观察上述数据时,你会发现 Peek 测试中的进程耗电量比 Get 测试中高得多(务必对比类似的测试)。进程耗电量大约高出 7 倍。这一点可以通过最右边一栏看出来,其中只显示了该进程单独的耗电量。这表明,在 peek 测试中的进程耗电需求高得多。

这使我们关注下一组数据,并注意到平均耗电量和纯耗电量包含更有用的数据,因为耗电量被平均分布在测试的过程中,实际上提供了一种电源“耗尽”速度。



表 2 Peek 与 Get 的结果 #2

观察以上数据,你会发现尽管后台平均耗电量始终保持相同,但 Peek 测试的进程耗电量大约高出了 15 倍。显然,Peek 测试的总耗电量比 Get 测试要高。



表 3 Peek 与 Get 的结果 #3

上述数据证明在运行 Peek 测试时,系统无法进入休眠状态。在运行 Get 测试时,系统的全部时间几乎都处于休眠状态。

所有上述测试均在英特尔的 IT 默认电池模式(SLOW)下,在笔记本电脑上进行。为获得更实际的测试结果,在高速模式或适应性(adaptive)模式下进行以下测试。只使用较长的测试。因为 5 分钟的小测试看看是挺有意思,但与较长的测试相比,它们提供不了什么其它有用的数据。而且较长的测试由于电源评估工具的设计,运行的效果更好。较短测试的结果表作为附加的备用材料,在本文最后提供。





这些测试对结果进行了进一步补充说明。在这些测试中,运行 Peek 测试的系统的总耗电量大约高出 2 倍或者更高。这明确表明,调整你的移动应用,以解决 PeekMessage 问题,可能会给应用耗电量造成很大不同。

结论
应用代码需要体现出,设计者必须意识到设计对系统耗电量产生的影响。过度使用 PeekMessage 会使系统始终无法休眠。应正确使用 PeekMessage,以便系统能够最好地管理电源资源。利用以上 GetMessage 和 WaitMessage 方法会使你的应用耗电量更低,并帮助实现我们的节电和高性能目标。

其它资源

作者简介
Dale Taylor 是一名致力于移动软件的应用工程师。1999 年加入英特尔公司,致力于 LanDesk 管理软件项目,后任软件解决方案集团的性能调试工程师。Dale 利用 22 年的编程和开发经验,帮助客户进行调试和优化,以便其产品充分利用英特尔最新移动特性。他最初为一家政府承包商编程,在随后 12 年中作为 WordPerfect 的开发人员从事汇编语言和 C 语言编程;随后四年,在一家独立起家的公司就职。


附录 A
英特尔 IT 系统的 IT 架构信息预装了一套软件工具,英特尔 IT 部门认为这些工具对于确保企业安全性和遵守各种许可协议十分必要。该软件包含病毒扫描程序和一个 Terminus Security 代理。扫描程序和监控软件始终在系统上运行,给系统增加了额外负载。

Peek 与 Get 结果 #1 — 附加结果



上述测试还显示出另一个有趣的结果。在 Process + Background 列中,较短的 Get 测试似乎比相同的 Peek 测试消耗的电量更多。这是由于 Get 测试比预期运行了更长时间而导致的。例如,3 分钟的测试运行了 4 分多钟。这是由于应用处于休眠状态,直到一段时间之后,它才唤醒,发现应该关闭。因此,应用运行的时间较长,总耗电量较大。要消除这一反常现象,进行了较长时间的全面测试,如下所示:

Peek 与 Get 结果 #2 — 附加结果



这些数据本身已经消除了先前的运行时间问题;很明显, Peek 测试的总耗电量高于 Get 测试的总耗电量。

Peek 与 Get 结果 #3 — 附加结果

参考和注释