实时嵌入系统的商用系统行为视图工具主要用来查找那些以通常的“查找断点和分析断点”的调试难以发现的问题,这些工具对于查找“Heisenberg 问题”尤其奏效,因为当我们运用普通工具开始查找时,这样的问题难以发现。

记录工具较之于其它的调试工具对系统的影响较小,因其不太可能严重扰乱系统以至于难以查找问题,但这一记录工具会冻结在记录文件中的错误记录,并在以后空闲时间对其进行检查。你可以指定一个用于记录组件的触发点,这一触发点也许是一个总线故障或者是某些系统服务的第N次故障。记录后台程序会截取触发事件附近的事件的记录,并将它们传送到将其形成图形以便分析的工具中去。

运用视图工具的正常周期是从某一问题开始的,假设系统被冻结,标准的调试实用程序会显示出两个任务没有任何运行,它们后的行为都是等待锁死。但是,如果存在问题,代码检查会显示两个任务都在等待锁死,只是等待的时间不同。实际上,该设计要专门调用那两个任务,将这个锁死在两个任务之间来回传递,视图工具是利用这个javascript:;" onClick="javascript:tagshow(event, '%B9%A4%D7%F7');" target="_self">工作原理来发现软件设计错误的。

视图周期在微调触发点指标和检查记录之间反复,直至问题很清晰地出现在视图中并有充分的行为来表明问题的根本原因。在这个例子当中,视图周期显示某一任务想尽力在某一程序段内获得两次死锁,同时不允许其它任务运行。这时,程序员能够找到问题所在。

几年前我设计了一种叫做HawkEye的视图工具,其主要两种用途是:(1) 查找在两个任务间的通信过程中由竞争条件所造成的问题;(2) 在短时间间隔上,调整性能。

当我设计Hawkeye的时候,脑海中浮现出了即时重放的图,这一点也得益于同惠普(HP)逻辑分析仪共事数百个小时得出的灵感。大体上讲,Hawkeye是一个逻辑分析软件。你选择某一个触发点并开始运行它,当触发点事件出现时,Hawkeye会给出一个包含触发点附近信息的时线图。你选择这个触发点,所以线径包含有问题的时间间隔或需要进行优化的时间段。Hawkeye将它所收集的数据以图形表示出来,并使竞争条件和性能问题易于观察。

基于Hawkeye测试版完成测试的基础上,我们决定收集几个实例,目的是进一步完善Hawkeye。

事例1

我曾记录了用以测量上下软件间的切换时间的基准程序,但它在完成几次上下软件间切换后会闭锁起来。分析表明:系统调用本来只需要几毫秒,实际上却花了几秒时间。基准程序在它启动后不久会死锁,因此我选择基准程序起始分支来触发。

如图1所示,黄线表示正在等待旗语的线,浅黄色的箭头表示未锁的系统调用,黄色的三角形表示锁死的系统调用,黑边框线的图标表示进入系统调用,淡色边框线的图标表示从系统呼叫中退出。在屏幕中间有正在锁死某个旗语并等待的线程11和线程12,这即是死锁现象,从在死锁的线程12的左边你可看到原因。有某一个释放线程11的未锁系统(见交互作用线),然后线程12再次释放旗语。

释放二进制旗语两次与释放一次无异。不知何故,我想到当线程12释放锁的时候,线程11会立刻醒来,并且直到线程11已醒来并重锁旗语,第二个未锁系统调用才会发生。或许这些在线程12的未锁系统间的紫色的图标(表示一套优先系统调用)尚可资研究。我没有记录排除这些死锁的过程,但我做到了。基准程序现在运行很正常。

这是视图工具设计的目的所在,我知道存在某个与系统的多组件的交互作用相关的问题,该工具给出了问题附近的系统行为的抓取记录,这些记录使我找到了问题所在。

事例2

John正在测试一个作为销售工具的产品机顶盒。它不会运行图形Java,如Java无图运行,它会运行得更好,而且不会因脚本或环境变化的干扰而致Java打开一个视窗。用在机顶盒上的软件运行很好,John添加上去的软件在其它平台上也同样运行良好,但当把该软件与机顶盒混合在一起的时候,似乎出问题了。

John是一个很好的技师,但不是一个好的程序员,但即使是一个好的程序员也会遇到困难。机顶盒中的大部分软件已在工厂中由闪存固化而完成的,因而找不到符号调试所需的信息。John找到的线索是:应当运行window管理器的某个步骤不正常,尽管看起来这个步骤好像启动了,但实际并没有。他将记录后台程序添加到系统中并启动了它们。在与程序员一起检查后,他把触发点设置在记录中间某个特殊系统调用的第一个位置。

问题恰好在触发点之前。某个低位图形组件正在调用来自图形驱动器的某个服务,该请求返回一个未知服务错误。几微秒之后,那一过程在指令存取上显示存储错误,因而被操作系统终止。问题存在于两点:调用服务的组件应当检查回归码,同时驱动器也应当支持这一服务。John把这个记录文件带给了程序员,程序员立刻查明并解决了这一问题。

在此,关键的问题是John不是程序员,某个系统完成的图形视图将问题报告由“我不能使Java 与图形一起运行,”改为“在这个图形服务实施过程中或应用方式上存在错误。”

事例3图1:黄线表示正在等待旗语的线,浅黄色的箭头表示未锁的系统调用,黄色的三角形表示锁死的系统调用,黑边框线的图标表示进入系统调用,淡色边框线的图标表示从系统呼叫中退出。

某一系统运行正确但执行速度很慢,仿佛CPU的负担很重,但问题诊断不出来。性能良好,系统正常的情况下,造成CPU负担太重的原因很多。

后来,更多的软件被添加到系统中,程序员随意查看和播放。我记录了某个测试程序执行时的某个镜头,看着这个镜头,我的注意力被一个特殊的记录过程所吸引。由于记录程序正在监视的装置没有运行,记录器应当在某个事件等待被屏蔽,但显示器显示正忙。它正在用尽每个可用的CPU周期以便尽可能快的完成事件等待系统调用。所有这些事件等待系统调用均立即返回。它们都在等待同一个事件,而且它们均来自于同一个地址。这个记录程序应当在测试程序的整个执行期间只等待一个事件等待调用,很明显其中存在一些错误。

很快,发现是事件配置不正确。在某一事件等待被返回后,后续的事件等待要无屏蔽地返回。幸亏(或许是不幸)程序进行了检查,以查看它所等待的事件是否发生;如果没有发生,它是否会继续等待。程序员修改了事件配置后,系统的运行速度大大地加快了。

这个错误或许从未被发现过。它不会导致某个软件不适配,也不会产生不正确的结果,或使系统锁死。系统即使通过了它的测试组,但是,只有用视图工具来查看系统,问题才变得一目了然。