找回密码
 注册
搜索
查看: 1750|回复: 3

[讨论] [转帖]统一进程模型

[复制链接]
发表于 2005-7-9 10:08:00 | 显示全部楼层 |阅读模式
摘要

绝大多数嵌入式系统软件工程师有个共同的观点,认为开发效率更大程度上取决于开发工具而不是所使用的实时操作系统。但是,即使用最好的工具,开发人员可能还是要将绝大部分精力用于质量保障和维护,而不是进行创新以增加产品的功能。何以如此?就在于操作系统的体系结构。传统的操作系统由于其本性只提供有限的或根本不提供内存保护单元MMU功能。由此,嵌入式产品软件代码的微小改变都需要重新进行繁重的调试与测试工作。在本文中,我们将比较不同的操作系统体系结构,并进而分析基于统一进程模型(UPMTM)的操作系统是怎样使研发人员把精力从维护转向创新的。不同于其他的体系结构,统一进程模型允许应用程序、驱动程序、协议栈甚至操作系统模块各自运行在自己的受保护的内存地址空间中。这一种方法不仅取消了不必要的调试与测试而且增加了系统实际运行中的可靠性。例如,基于统一进程模型的系统可以在系统不重新启动的情况下对系统的软件故障进行恢复,或者对包括操作系统模块在内的软硬件模块进行热插拔。

工具是否真的高于一切?

所有嵌入式操作系统都是一样的。缩短产品面市周期,提高产品可靠性,使产品功能卓著,具有”杀伤”特色,选择任何操作系统结果都是一样的。一切的关键都在于你要选择适当的工具。
你是不是这样想的?如果是这样想的,问一问自己以下几个问题:
§ 虽然你越来越努力,但你所研发的新产品的发布周期是不是越来越慢?
§ 你设法让新产品如期发布,结果牺牲了产品的特色和可靠性?
§ 随着产品功能的丰富,用于质量认证的费用是否也随之指数化上升?
如果对以上问题中的任何一个你的回答是肯定的,那么你正在失去竞争力。你需要重新思考操作系统体系结构对你的重要性了。
 楼主| 发表于 2005-7-9 10:09:00 | 显示全部楼层
平板体系结构:

图一:平板体系结构的操作系统不提供任何地址保护

研发瓶颈

首先让我们一起看一看绝大多数嵌入式操作系统还在使用着的传统的平板体系结构。如图一所示,这样的体系结构将所有软件模块与操作系统的内核挤在同一个地址空间里面,其间没有任何内存保护。结果任何无关紧要的模块都可能覆盖内核地址空间,从而使整个系统崩溃。问题真的发生时,其导火索往往是如C指针崩溃这样的一点点编程错误。
显然这样的体系结构没有为故障留下任何回转空间。对于简单嵌入式系统而言这是可以的,因为在简单系统情况下,绝大多数这种问题可以在程序集成测试时查到。但如果你的项目包含了五十个、一百个或一千个模块,情况又怎么样呢?在上万行代码、上千个线程同时运行时,情况又怎么样呢?如果有一个内存冲突,导致系统崩溃,你又从那里开始检查?再好的工具也不能帮你找到哪一个模块出了故障。任何人都不可掌握这一系统的全部代码,因此即便是经验丰富的内核程序员也需要几天、几周甚至几个月的时间才能找到故障代码段。

繁重的重复测试

退一步说,假设你已经找到的故障代码段,或者增加了一点点新的功能,情况又会怎么样呢?这时,你需要对你的全部代码进行重新测试。原因非常简单:在平板体系结构下,你对代码做了任何改变后,你都需要对全部的运行影象做新的连接,生成一个具有不同内存地址偏置的新影象。结果就是,某些模块以前覆盖了没有使用的数据段地址,现在覆盖了一些其他模块的特别关键的数据段地址甚至内核。而这种情况甚至于在仅仅增加一行代码的情况下就可能出现。

更少的原型制造时间
测试并不是唯一的瓶颈。平板体系结构使你没有能力去尝试其他设计思想。因为修改一点点代码后,你就要用几个小时的时间对整个运行影象进行新的编译和连接。这样,哪怕尝试一个很简单的思想都可能要花费很长的时间。
性能的迷思
对于平板体系结构而言,软件臭虫是如此难以定位,以致于质量认证部门不得不发布那些并不稳定的代码。实际上,随着代码量的增长,你用于开发新产品或丰富产品功能的时间远远没有用于质量认证的时间多。如图二所示。

图二:对于平板体系结构而言,测试与维护时间随着代码长度指数化上升

那么,为什么还有那么多的操作系统在使用平板体系结构呢?这是由两个原因造成的:其一是历史原因。直到今天,很多嵌入式处理器缺少集成内存管理单元。其二是性能冲突。很多商用的或者自用的操作系统研发工程师发现支持内存管理单元的额外开销难以承受。事实上,有些人甚至于声称为了保证系统的性能,内存管理单元必须被牺牲掉。
然而,事实并非如此。如我们下面讨论所要显示的,一个设计良好的操作系统,不仅能够提供内存管理单元,而且还能提供与传统的平板体系结构下的操作系统相同、甚至于更优的性能。
 楼主| 发表于 2005-7-9 10:09:00 | 显示全部楼层
单一内核体系结构:

图三:单一内核体系结构只为应用程序提供地址保护,解决了问题的一半

为了解决平板体系结构所面对的上述困难,一些嵌入式操作系统制造商采用了单一内核体系结构,如图三。
在这种体系结构下,每个应用程序都在自己的受保护的内存地址空间下运行。如果一个应用程序企图覆盖另一个应用程序的内存空间,内存管理单元将会捕捉到这一错误,使研发人员能够找到错误的发生地点。
第一眼望去,这种体系结构非常好,开发人员再也不必为应用程序的软件臭虫盲目搜索。但这只是表面的。所有底层模块,包括文件系统、协议栈、驱动程序等等,都还连接在与内核相同的内存地址空间中。一个驱动程序中的一点内存冲突,就会使整个系统崩溃,而不留下任何蛛丝马迹。
这才是问题的关键,因为嵌入式产品工程师的决大多数时间是在进行底层模块的开发。例如,电信系统的交换机,就有很多协议栈和驱动程序。结果平板体系结构所具有的那些问题 — 如夜以继日地追索崩溃的C指针,代码变化后的繁重的重复测试,以及一个无关紧要的模块就可能使整个系统瘫痪的潜在危险 — 都将伴随着使用单一内核体系结构的操作系统的嵌入式产品研发工程师。
 楼主| 发表于 2005-7-9 10:09:00 | 显示全部楼层
统一进程模型体系结构:

图四:统一进程模型体系结构为所有软件模块,包括操作系统模块和驱动程序,提供了内存保护

臭虫止于此处

要想消除这些研发瓶颈,操作系统必须实施基于统一进程模型的体系结构。如图四所示,基于统一进程模型的操作系统在内核中仅仅提供了最基本的服务,如调度、进程间通信和初始中断句柄。所有的其他系统服务都通过可选的进程额外提供。结果是,每一个驱动程序、协议栈、文件系统、I/O管理器以及图形子系统都各自运行在自己的受保护的内存地址空间中。
显而易见,你可以看到这种体系结构提高了系统可靠性。第一,操作系统内核只含有很少的代码,绝无故障;第二,任何模块,包括写得很差、优先级很高的驱动程序,也不可能使内核崩溃;第三,每一个模块都是作为独立进程在运行着。这就意味着你不必进行重新启动或系统构建,就可以随心所欲地对系统的任何模块作开始执行、停止执行、修改或升级的工作。
可以想象,这样的开发过程是何等的流畅,换而言之,你的系统在实际运行时又是何等的好用!

开发时的优点

首先,让我们看一看嵌入式产品软件工程师的绝大多数时间是被消耗在哪里?结论是编写设备驱动程序代码
对于传统的操作系统体系结构,所有的驱动程序代码都被捆绑在内核之中。如图五。

图五:传统的操作系统结构使驱动器开发显得笨拙耗时
结果是:
1. 每次新增加一个驱动程序时,需重构内核,将系统重新启动。
2. 每次重构多用户系统时,其他工程师都必须停工等候。由于通常这是不允许的,驱动程序研发工程师只能夜间工作。
3. 为了系统调试,必须使用底层内核调试工具,而不是使用易学易用的源代码调试工具。这意味着你不仅仅要加班加点,多干少睡,而且要成为内核专家。
4. 如果内存崩溃,没有任何可靠的办法对其定位。
现在再与统一进程模型体系结构作一下对比,这时驱动程序是作为一个独立的、内存受保护的进程在运行:(如图六)

图六:统一进程模型使驱动器开发非常合理

1. 如果你要修改一个驱动程序,你只需要对其重新进行编译,几秒钟内就可完成,没有内核重构的问题。
2. 由于内核不必重构,同事们也不必在一旁等待。多个程序员共享一个目标系统,驱动程序工程师晚上也可以睡个好觉了。
3. 调试驱动程序或任何其他传统的内核模块时,你可以使用源代码调试器与剖析器。编写一个驱动程序或者操作系统扩展模块,就如同编写一个应用程序一样容易。
4. 内存崩溃时,操作系统立即知道哪一个模块应当负责,并且精确到具体的指令。现在再也不需要花费好几周的时间来查找问题了,几分钟内一切都会完成。

二进制代码重用简化系统测试

如我们上面所讨论的,对于传统的操作系统而言,添加了新的驱动程序后,将生成一个新的内核影象,带来繁重的系统测试工作。
对于统一进程模型而言,内核仅仅包含最基本的系统服务。你可以重复使用被供货商在实验室反复测试、用户在各种应用中反复使用,证明为万无一失的同一个系统内核。对于普通模块而言,每个模块都有一个0起始的线性虚拟地址空间。因此,对于未做修改的应用程序、驱动程序、内核模块及协议栈,你可以进行二进制影象重用。结果就是,大多数情况下,修改代码后,你只需要测试受影响的模块,而不是所有的软件代码。
由于减少了测试工作量,你有更多的时间和精力去丰富系统的已有功能,或者增加新的功能。这一点就是到了设计周期的最后阶段也为时不晚,你也可以更快地推出产品的新版本。

更高的研发资源回报率

对于传统的操作系统体系结构而言,每一个研发人员都需对所有的模块了如指掌,以避免自己的模块覆盖其他模块的地址空间。随着应用系统变得越来越复杂,程序员用在看懂整个代码树的时间比用于自己的工作的时间要多得多。
对于统一进程模型而言,程序员不需要对整个代码树作通盘了解。如果内存崩溃,操作系统将会对其定位,高级程序员有更多的时间做他们应当做的事情:解决系统的核心问题,为产品添加真正的价值。同时,新手也更容易上路。因为统一进程模型使得底层模块可以使用源代码调试工具进行调试,以前只能编写用户应用程序的新手,现在也可以编写驱动程序及文件系统等等。
同样道理,因为第三方制造商可以不需了解源代码树就能发布自己的软件代码,统一进程模型使得非源代码软件开发也变得简易。同时,通过运行时各模块间的内存保护,统一进程模型也极大地减小了自研模块与第三方模块相冲突的风险。

并行开发,缩短周期

研发人员再也不需透彻地了解全部系统,统一进程模型使得大的项目组可以被分为几个小而独立的项目组。这样至少在两个方面加快了研发进度:
1. 三到五人的小项目组比起十到十五人的效率更高。因为小项目组成员之间的沟通效率更高,他们可以开更少的会议、做更少的备忘录,把时间用在自己更重要的工作上。
2. 即使相关的子系统还没有完成开发,项目组也可以方便地进行开发和测试自己的软件子系统。假设甲组开发A模块,乙组开发B模块,在最终系统中,A、B两模块是紧密相关的。由于每个模块或模块组可以作为独立进程运行,甲组可以在乙组还没有着手B模块的工作之前开始编写、测试和调试A模块。两个组需要做的唯一的一件事就是约定两个模块间共享数据的格式。
如上所述,统一进程模型允许多人共享同一个目标系统,这就意味着一个组的测试与调试不会干扰或推迟另一个组的调试与测试工作。各个组并行地进行工作而不是串行地进行工作。
快速原型制造

对于统一进程模型而言,尝试新的思想也更加容易。我们看到在传统的平板体系结构和单一内核体系结构下,由于运行影象须不停地重构,原型制造是多么的困难。在统一进程模型下,你只需编译和重新启动受影响的模块。这样,在传统的体系结构下,尝试一个思想的时间,现在可以尝试好多个。

运行时的优势

统一进程模已经消除了内核故障的可能性。不仅如此,它还具有另一些优秀的性能,使嵌入式系统产品更加可靠好用。这包括软件故障的自动恢复、软硬件模块的热插拔以及在不同处理器的应用系统之间共享应用模块。

提升容错能力

无论你怎样仔细,有些软件臭虫还是会溜过去,直到运行时出现。对于平板体系结构而言,唯一的办法就是系统重新启动;对于单一体系结构而言,只有在应用层的故障才可能免于重新启动;对于统一进程模型而言,无论是故障发生在驱动程序、协议栈还是定制的操作系统模块,你都可以不重新启动整个系统就能进行故障恢复。要做到这一点,你只需使用智能的软件看门狗就行。
例如,一个驱动器出现故障。不是整个系统重新启动,而是由看门狗触发以下动作:
? 重新启动驱动器,或
? 重新启动驱动器及相关进程,或
? 如果故障是致命的,发出警报信息,将整个系统重新启动。

故障分析

在触发部分重启或整体重启的同时,软件看门狗还会收集错误信息。例如,当系统访问大容量介质(如闪存,硬盘或网络上其他机器的硬盘)时,看门狗会产生一个记录文件。通过源代码一级的调试工具,你可以查看这个记录文件。从而:
? 精确定位故障代码的行号
? 查看变量及函数调用历史等资源
让我们将这种过程和传统的硬件看门狗作一个比较,你就会明白。硬件看门狗只是简单地将系统复位,对故障不做任何跟踪;使用软件看门狗后,你不再手足无措,而是马上可以着手解决问题。
更进一步,软件看门狗可以监视那些硬件看门狗所看不到的系统信息。例如,硬件看门狗可以知道一个硬件的驱动程序是否在工作,但是要让它知道其他程序是否与这个驱动程序在正常通信,就很困难了。软件看门狗可以堵上这个漏洞,在驱动器还没有发现任何问题之前就会采取行动。

软件的热插拔使系统更加可用

当然,软件臭虫不是使系统停止运行的唯一原因。平板体系与单一内核体系的用户在对驱动程序、协议栈和操作系统模块等软件模块升级时,需关机进行;统一进程模型体系的用户,可以对这些软件模块在线升级,而不必系统重启。
注意,这并不是简单地在工作系统中添加新的模块。有一些单一内核体系结构的操作系统也允许用户动态捆绑驱动程序到内核上。但由于驱动器工作在内核空间,它们不能被删除、重启或替代。统一进程模型却允许用户随心所欲地添加或删除驱动器。

硬件故障恢复

由于这种对底层模块的灵活控制,你可以不必系统重启就对过时的或损坏的硬件进行更换。例如,以太网卡出现故障时,你可以终止以太网卡驱动程序,插入新的网卡,启动新的网卡驱动程序,就完成了更换。当然你也可以使用另一种套片的网卡和相应的驱动程序。这里要强调的是硬件此时是支持热插拔的。
用同样的方法,你甚至可以处理那些灾难性的故障,如硬盘崩溃。如果本地硬盘出现故障,你可以把所有的文件操作指向网络上的另一台机器。这与传统操作系统的体系结构是大相径庭的。传统的操作系统体系结构面对即使是更换鼠标这样的小事儿,也要重新启动,甚至于内核重构。

分布式处理的伸缩性

提高系统可靠性的一个好的办法,就是将应用模块在多个处理器之间分配。这样,如果是一个处理器出现故障,应用系统也不会停止整个服务。实际上,随着应用系统越来越大,除了在多个处理器之间进行分配以外,别无选择。这不仅是为了提高可靠性,虽然这也是一个因素,而更是因为应用程序需要更多的物理接口、更强的处理能力,这是单CPU所不能提供的。
不幸的是,传统的操作系统使此项工作特别尴尬。因为,它们把大部分或全部的软件模块都捆绑到内核之中。例如,如果你把协议栈从一个处理器移向另一个处理器,你就需要生成两个全新的内核影象。如果操作系统不能提供透明通讯功能,那么你需要把应用模块和与之通讯的另一个模块都重新编写。
更令人头痛的是,通常你不知道把哪个进程放到哪个处理器上运行。直到最后的集成阶段,你不知道这样的分配并没有提供最好的性能。那时,再重新编程、构建和测试你的软件就已经太晚了。
统一进程模型把所有这些问题推在一边。所有的软件模块都与内核解偶,作为独立的可移动的目标工作。在实施了统一进程模型后,进程间通信在整个网络上透明传输。一个进程可以和另一个处理器上的另一个进程连续地透明对话。不需作任何代码变更,也不需重新代码联接。事实上,同一个二进制代码进程可以在任何时间,包括运行时,重新定位。
理所当然地,这就意味着程序员编写代码时不必把具体的系统配置放在心里。不论最终系统扩展得很大还是收缩得很小,程序员都一样工作。例如,不论硬盘与其驱动程序是放在本地机器上,还是在网络上的远程机器上,都没有分别。两种情况下,只要有相应的授权,任何进程都可以透明地访问这个硬盘,而无须任何特别代码。
性能如何?
我们已经看到了统一进程模型在开发阶段和运行时所带来的好处。然而,我们还有一个疑问,那就是将应用程序、驱动程序和OS模块放到自己的内存保护单元段落中,是否会拖累系统的性能?回答是否定的。只需正确地实施统一进程模型。
例如,实施了统一进程模型的QNX操作系统,从一个进程停止到另一个进程开始的上下文切换时间,只有1.95微秒/奔腾133MHz。这对任何性能关键型的应用都已经足够了。

更多的创新

回到我们最初的问题,选择这样的操作系统确实使你今非昔比。不仅仅系统的可靠性和性能上去了,而且,在有限的时间窗口里推出新产品的能力也上去了。当然,工具也能对你有所帮助,但是正如我们所分析的一样,工具并不能补偿使用传统操作系统体系结构所带来的调试、测试、以及维护的额外花销。
通过消除额外花销,统一进程模型结构倡导了一种新的创新文化。设计队伍有了丰富或提升产品新功能、新特色甚或一个全新产品的回旋余地。喜欢创新的技术尖子更加愿意留在现在的公司,而不是另谋高就。而队伍本身也变得更小、更为精干,相互之间需要更少的电话沟通,从而对新产品的发布期限更加游刃有余。更进一步,统一进程模型使得集成第三方代码变得更加容易,从而能够从容面对越来越短的研发周期。

图示七:统一进程模型可以帮助你扳平曲线,让竞争力走上一个新台阶

除了创新之外,统一进程模型提供了用户所最寻觅的东西:可靠性。
与基于传统的体系结构上的应用系统不同,基于统一进程模型的应用系统能够在系统不重启的情况下对软硬件故障进行恢复。它也让你在不中断服务的情况下,对驱动程序、应用程序、协议栈甚至操作系统模块自身进行升级。
更多的创新、更短的面市周期、更强的可靠性,这就是统一进程模型带给你的好处!不论嵌入式产品市场如何变化无常,不论竞争何等激烈,你都将因此而立于不败之地!

(待续)
高级模式
B Color Image Link Quote Code Smilies

本版积分规则

Archiver|手机版|小黑屋|52RD我爱研发网 ( 沪ICP备2022007804号-2 )

GMT+8, 2024-5-3 20:31 , Processed in 0.048542 second(s), 16 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表