通过在库中描绘特定函数减小代码大小
技术领域
本发明涉及一种减小计算机代码集大小的方法,并且还涉及一种创建计算机代码库的方法。
背景技术
在此所引用的术语“计算装置”广泛地解释为覆盖任何形式的电子计算装置,包括数据纪录装置、任何类型或形式的计算机以及任何构成方式的通信装置,所述任何类型或形式的计算机包括诸如个人数字助理(PDA)的手持个人电脑,所述任何构成方式的通信装置包括移动电话、智能电话、在一个装置中结合了通信、图像纪录和/或播放以及计算功能的通信器以及其它形式的无线和有线信息装置,包括数码照相机、MP3和其它音乐播放器以及数字收音机。
现代计算装置通常含有多种存储器。可将存储器大致分为两种类型:
1.可用于本地执行(eXecute In Place,XIP)程序的存储器,其中无需为了执行程序而将程序载入不同类型的存储器。各同类型的RAM(随机存储器)是该类型存储器最突出的例子。然而,由于RAM具有易失性以及当断电时会丢失内容,许多装置包括较少的更贵但更慢的非易失性XIP存储器类型,例如NOR闪存。
2.可用于存储但不是XIP的存储器,通常这是因为只可对XIP进行顺序地或成块地存取而不是可随机寻址。磁盘驱动器和NAND闪存是该类型存储器的突出例子。保持在存储器中的程序必须被拷贝到XIP存储器中以便能够执行。
这两种存储器有另外一个显著的区别:XIP存储器比只能用于存储的存储器要昂贵得多。因为现代计算装置的制造存在相当大的成本压力,该计算装置包括定位于价格敏感的大量销售的诸如移动电话的便携装置,所以需要此装置应该尽可能地减少对XIP存储器的需求。
已经知道,作为制造工艺的一部分,需要向计算装置提供软件,该软件存储在某种永久非易失性存储器中并且为计算装置执行适当功能所必需。所述软件通常包括数据和程序,所述数据和程序为开机时运行启动程序所必需,或者提供经常需要的操作系统(OS)服务,或者提供关键的应用程序。
尽可能在存储器中保存这种软件的装置,在需要时将软件拷贝到(载入)XIP存储器中而在不再需要时释放XIP存储器(卸载软件),从而与将更多这种软件保持在XIP存储器中的装置相比能够将其制造成本最小化。
更具体地,如果在制造阶段已经将装置的核心操作系统提供在存储器中,则通常需要将该核心操作系统作为整个操作系统镜像从存储器拷贝到XIP存储器,以作为开启(重启)过程的一部分。在此所用的术语“核心操作系统”通常意义上是指为计算装置基本操作所必需从而在打开计算装置时自动载入的操作系统部分。“操作系统镜像”是代表整个操作系统软件的文件。操作系统镜像的大小就是当操作系统存储在存储器中时的操作系统覆盖区。
通常,一旦被载入XIP存储器,操作系统镜像实际上不能被卸载,甚至卸载其中的一部分也不可能;本领域的技术人员知道,由于这种操作系统镜像通常使用如静态链接的技术来创建,所以它们所占据的存储单元被视为保留,而不能由其他软件重新使用。
可使核心操作系统最小化的装置将会使提供专用XIP存储器的固定成本最小化,进而使得装置对XIP存储器的需求最小化,并且使其更加便宜以便一般大众能够购买和使用。其还具有以下优点:需要用来存储核心操作系统的存储器越小,装置的启动就会越快速,这是因为需要将更少的数据从存储器拷贝到XIP存储器;并且电力消耗可以更低,这是因为使用更少的动态RAM形式的XIP存储器将会降低整个电力消耗。
如果计算装置制造商提供装置系列而该装置系列中每个装置具有不同的功能但都从相同或相似的软件开发而成,则从装置制造商的角度来看,希望装置系列中的所有装置包括兼容的核心操作系统。已经知道的是,这降低了制造商的开发成本,并且增加了装置的可靠性。
另外,如果这种装置是开放式的并且允许在制造之后安装提供附加功能的软件模块和程序,则在整个装置系列上提供兼容核心操作系统将会使得这种模块和程序能够针对多得多的装置。由此造成的规模经济可以降低开发成本并且为第三方制造商提高了可靠性。
最后,对于这些计算装置的终端用户而言还有另外的益处。除了从低价格和更好的产品所获得的好处之外,在整个装置系列上使用这种软件模块可以极大地降低获取和安装后续市场软件的复杂性。在确切地知道装置系列中的所有装置均相互兼容的情况下,仅指定终端用户的装置所属的系列便已足够,而无需指定终端用户所拥有的计算装置的准确型号
装置系列中的相关装置典型地由特征集进行区分,所述特征集使得特定型号指向市场的不同部分。
这对于例如移动蜂窝电话的多功能计算装置而言更加如此。已经知道,这些装置展示了一个称为“会聚”(convergence)的现象,从而先前包含在各个装置中的功能变成在单个装置中即可获得。例如,先前在数字音乐播放器、数码相机、FM收音机、PDA、传呼机、闹钟、电子信息机(例如,RIM黑莓)、录音机、便携游戏控制台以及移动电话中分别可用的十项功能都可以在当前可获得的计算装置中找到,例如索尼爱立信P910i。然而,已经知道,会聚装置的复杂性经常成为其有效使用的阻碍,在单个装置上以单一形式提供所有功能所需要的妥协安排可能会导致不太满意的用户体验。
这就是为什么在计算装置中用特征集进行区分变为越来越普遍的一个原因。再以移动电话作为例子,现在顾客可以从为数字音乐(具有存储器,优质的耳机以及为音乐播放设计的按钮)、或为数字照相(具有存储器和高级镜片)、或为电子收发信息(具有适当的QWERTY键盘)、或为玩游戏(具有特殊拇指按钮)而设计的装置中进行选择;现在已经出现了很多其他指定的特征集,并且在接下来的几年中毫无疑问将会看到更多。
指定具体特征集的一个相关原因是根据价格来进行细分,去除更昂贵的特征以便在产品系列中提供更低价格的装置。
因此,制造商正在更多地提供属于相同装置系列但是其特征集相区别的产品范围。
在此需要解决的问题是,没有明显的方法来协调所有以下三个要求:
1.核心操作系统镜像大小最小化,这使得装置更加便宜、启动更快并且消耗更少电力。
2.获得属于相同装置系列所有型号的兼容性,这可带来降低软件开发成本以及提高软件兼容性的规模经济。
3.在相同装置系列中区分各个装置,以便使其满足不同用户群的不同需求。
显然地,当计算装置不同时,需要加入该系列中每个型号的核心操作系统镜像中的项目也将不同。拿三个特定应用来说,即音乐播放列表编辑器和选择器、相机和电影应用程序以及802.11无线网络驱动器,可容易地看出,音乐播放器装置、数码相机装置和信息发送装置的要求是不兼容的。对于所有三个装置,对一个装置而言必须作为核心操作系统镜像一部分的必要特征对于另两个装置而言则是不重要的。如果将不重要的特征从核心操作系统镜像中去除,则三个不同装置中的每个装置将更加便宜、制造更快,启动更迅速并且消耗更少的电力。
但是简单地在差异化的会聚装置上去除不重要的特征会使得装置不兼容,从而破坏型号系列概念中固有的大部分价值。不兼容的最主要的原因如前所述;核心操作系统镜像用静态链接创建,后继市场的软件希望通过该镜像中的特定位置为相同产品系列中的所有型号提供特定功能。因此,将核心操作系统镜像从存储器拷贝到XIP存储器的现有计算装置系列必须包括对非必要或很少使用的特征的支持,以便保持兼容性。这使得操作系统变得庞大,并且增加了制造成本,却没有任何其他的价值。这还增加了启动时间,因为用于这些特征的支持代码需要从存储器被拷贝到XIP存储器中,尽管它不会被经常被使用,而且在所述XIP存储器为动态RAM的情况下还会增加电力消耗。
虽然可以制造不包括较少使用部分的另外一个版本的核心操作系统,但是这个版本必然会放弃维持相关装置系列的制造商及用户的可观的经济利益:
1.这种版本的核心操作系统将不会从原始完整版本所具有的兼容性中获益。特别地,在制造装置之后所安装的依存于完整版本核心操作系统中所包含代码的任何软件将不能工作。
2.由于另一版本的操作系统将装置系列细分,因此将需要分别进行开发和测试,进而增加了开发成本并且延长了上市的时间。
发明内容
根据本发明的第一个方面,提供一种减少用于计算装置的计算机代码集的大小的方法,所述代码集用于当打开所述计算装置电源时自动载入存储器,并且包括用于执行计算任务的函数,所述方法包括:指定所述计算装置的具体应用;在所述计算机代码集中识别出那些将要用来实现所述计算装置的所述具体应用的那些函数;以及,从所述代码集中去除所识别出的函数,并且将所识别出的函数置于单独的计算机代码库中。
所述去除所识别出的函数的步骤可以包括以用于调用所述单独的计算机代码库的代码替换所识别出的函数,从而使得缩减后的计算机代码集和所述单独的计算机代码库相结合的函数等于原来代码集的函数。
所述识别出所需函数的步骤可以包括:执行原始计算机代码集以在测试计算装置上执行所述应用;以及确定在执行期间所用的计算机代码集中的函数。
所述确定在执行期间所用的计算机代码集中的函数的步骤可以包括函数描绘(function profiling)或调用关系图分析技术的使用。
所述计算装置的具体应用可以表示在所述计算装置中不经常使用的应用程序和/或对于装置的操作不是必需的应用程序。
所述单独的计算机代码库可以是动态链接库。
所述将识别出的函数置于单独的计算机代码库的步骤可以产生一个库,所述库中的函数根据相关计算装置的相应应用进行群集。
所述计算机代码集优选地是可执行代码。
根据本发明的第二个方面,提供一种经缩减的计算机代码集,所述计算机代码集从前面所述方法获得。
根据本发明的第三个方面,提供一种操作系统,包括从前面所述方法获得的经缩减的计算机代码集。
所述操作系统可以进一步包括所述单独的计算机代码库。
根据本发明的第四个方面,提供一种计算装置,包括从前面所述方法获得的经缩减的计算机代码集。
所述计算装置可以进一步包括所述单独的计算机代码库。
所述经缩减的计算机代码集和所述单独的计算机代码库可以是所述计算装置的操作系统的一部分。优选地,所述单独的计算机代码库可以独立于所述经缩减的计算机代码集被载入到所述装置的存储器中。
根据本发明的第五个方面,提供一种用于创建用于计算装置的计算机代码库的方法,所述方法包括:指定所述计算装置的具体应用;识别出用于执行计算任务的函数集,所述函数集用于实现所述计算装置的所述具体应用;以及,将所述函数集置于一个库中,以便所述库中的函数根据所述计算装置的应用进行编组,而不是根据由所述函数集中的各个函数所执行的计算任务进行编组。
根据本发明的第六个方面,提供一种包括用于执行计算任务的函数集的动态链接库,其中,所述函数集中的每个函数用于为相关计算装置执行具体应用。
在此所讨论的术语“库”是指可以从另一个代码集访问的一组计算机代码。
在一些实施例中,本发明因此可提供一种方法,所述方法可以减小XIP或RAM存储器以便考虑特征集中的区别,并且同时保持产品系列中所有产品之间的兼容性,无论这些产品具有什么特征。
本发明的优选实施例提供了一种在装置上节约XIP或RAM存储器的机制,所述装置在NAND闪存存储器中提供核心操作系统以及其它(非核心)可执行程序。
所述核心操作系统典型地包括可执行文件和所有其相依存的程序,并且在启动时递归地从NAND闪存中被拷贝到RAM中。该核心操作系统镜像作为NAND闪存上的单个文件提供;当该镜像被拷贝到RAM中时,它在传统的XIP只读文件系统(ROFS)中表现为多个文件。剩余的非核心可执行程序保留在NAND闪存上的非XIP ROFS中,并且根据要求被载入和卸载;与核心镜像的内容不同,它们不必占据存储器的保留部分,并且它们所消耗的任何资源在不再需要时都可以被释放。
如上所述,在具有不同特征的装置上提供完全不同版本的核心操作系统将不可避免地要为非核心特征将启动时宝贵稀有的XIP存储器分配给装置的操作。另外,由于整个核心为静态链接,所以将所分配的RAM进行释放以用于其它用途是不可行的。
在此公开的方法可减少存储器开销,而同时保留与完全不同的核心操作系统装置之间的兼容性。
应当理解,在计算装置中可以以两种不同的形式提供函数。一种可执行文件(在许多操作系统中称为EXE文件)提供具有单个入口点(entry point)的单个应用程序,并且典型地包括不与其它应用程序共享的函数。从核心操作系统镜像去除这种独立可执行文件不会导致兼容性问题,那是因为它不提供可通过调用特定内部存储器位置来访问的共享函数。
与此相反,共享函数的多个区域由不同类型的可执行文件来提供,一般称为动态链接库(DLL)。这种可执行文件不仅提供了一种以模块形式提供函数的方法,还有助于减少存储器开销,因为DLL可同时由多个需要相同函数的应用程序共享。与提供单个应用程序的其它类型的可执行文件不同,所述其它类型的可执行文件通常在开始时从单个入口点执行,DLL提供有多个入口点,每个入口点通常提供不同的函数。
需要注意的是,有两种主要方法可识别进入DLL的这些入口点。第一种方法是通过名称指示入口点。第二种方法是指通过序号指示入口点。后一种方法通常被称为函数序号映射(function ordinalmapping)或函数序号链接(function ordinal linking)。
由于名字可能会比序号长,需要用于其定义的附加代码,并且由于相对于定位其序号位置需要更长的时间来通过匹配名称定位函数,所以与使用序号相比,使用名称通常被认为是浪费计算装置的存储器以及其它资源。
因此入口点的序号链接是优选的实施例,特别是对于资源敏感的操作系统而言,具体地在那些为小型的、便携式的、电池供电的资源制约型装置而设计的操作系统中,与那些台式或便携式PC装置相比这些设备具有非常有限的物理资源。对于这种装置而言,代码的有效使用是非常重要的;移动电话是此种计算装置的一个例子。本发明的描述针对序号链接;然而,这并不意味着以任何方式限制本发明的应用。
本发明的基本想法是,对于任何不同计算装置的DLL中所提供的来自整个系列的共有操作系统的共享函数,可以将单个以静态方式载入的原始DLL分割为一个较小的以静态方式载入的宿主DLL以及一个或多个以动态方式载入的协助DLL。
附图说明
以下将参考附图用示例的方式对本发明进行描述,其中:
图1示出对函数集进行分析的流程图;
图2-图7示出根据本发明可使用的一些代码分析技术。
具体实施方式
以下实施例表示如何实现原始DLL的优化分离,以及如何通过分解复杂的静态依存链(static dependency chain)来节省大量的XIP存储器。我们将描述新的宿主DLL(host DLL)如何与旧的宿主DLL保持完全二进制兼容但能够按需要动态地载入函数。如果宿主DLL被调用以便提供已经分离的某函数,则所述宿主DLL载入适当的协助DLL(helper DLL)以满足请求。进而,当不再需要协助DLL时,可将其卸载,并且释放其存储器。
分离原始DLL
第一个步骤是,确定如何对用于任何特定区分装置的原始DLL集进行分离,以生成用于该装置的典型用途的使用实例集。这是本领域技术人员所熟知的技术。应该注意的是,所考虑的装置不同于装置系列中其他装置的事实意味着不同使用实例的生成是相对简单的。
第二个步骤是,使用原始DLL为所述装置系列创建通用测试操作系统,并且在DLL中对从第一个步骤产生的使用实例中执行的所有函数进行描绘。随后对该数据的分析使我们能够确定没有用在所述使用实例中或用在一个或非常少的使用实例中的那些函数组。在不同使用实例中具有高重复使用率的那些函数可以保留在宿主(静态)DLL中,而在不同使用实例中具有低重复使用率的那些函数则可保留在协助(动态)DLL中。应该注意的是,计算装置启动的使用实例被视为特殊的实例;当计算装置启动时所执行的函数将被保留在宿主DLL是,即使这是其唯一一次出现的使用实例。
第三步骤是,分析具有低重复使用率的函数,以判断它们是否围绕特定使用实例而群集(cluster)。如果是这样,则存在一个明显实例用于生成多个协助DLL,因为这将是与具有单一协助DLL相比调用所需函数更快捷和更有效的方法。
应该注意,在本实施例中,每个协助DLL根据使用实例进行排列,而不是根据函数进行排列。这与传统的DLL设计是相反的,在传统设计中,将所有相关函数编组到单个DLL中以便方便使用,而不管这些函数的使用率如何。例如,将所有数学函数编组到单个数学DLL中是很常见的。通过这个实施例,编组将变得更加以用户为中心;因此,如果启动电话需要执行余弦函数,而运行应用程序需要执行正切函数,那么这些函数可以会被放到不同的DLL中,即使传统的设计思想会将它们放在一起。
评价将哪些函数移入协助DLL的第四个步骤也是最后一个步骤是,递归地分析位于分配给宿主DLL的函数函数下面的调用关系图。函数下面的调用关系图越大,其具有越多的依存关系,并且可通过将其移入协助DLL而获得的节约就越多。应该注意的是,该步骤可提供最大的好处,因为它具有断开静态依存链的能力。这个步骤的目的是寻找一些点,在这些点上函数链的狭窄范围向下沿着依存d11的深度树,这些点被称为“窄点”(pinch point)。这可以通过数学过程手动或自动完成,所述数学过程通过对可能的函数组组合进行替换来为协助DLL找到优化的分离。在识别出窄点之后,在依存树顶部的函数以及被依存树顶部函数调用的所有函数都可以被移到一个或多个单独的库中。
在图1中用框图示出了上述步骤。
剩余附图对最后两个步骤进行了图示。图2示出可从函数描绘和调用关系图分析所获得的信息类型,以及不同DLL的函数和方法之间的依存关系是如何相互隔离的。图3和图4示出这些依存关系如何群集到两个不同的使用实例中。
图2、图3和图4中所示的使用实例1是计算装置启动的特殊实例;因此,它所使用的方法和函数以及它们之间的所有依存关系都保留在核心操作系统镜像中,并且继续静态链接。另一方面,使用实例2由计算装置的用户启动或者由特定外部事件触发。其使用的方法和函数可被移动到新的动态载入的DLL;这里,其他使用实例不需要它的依存DLL,这些依存DLL也可以动态载入。图5示出上述分析所建议的分离,图6示出使用实例1的详细细节,图7示出使用实例2的详细细节。
将调用从宿主DLL传到协助DLL
通常,从原始DLL生成宿主DLL的同时加上这一机制。宿主DLL将用桩代码(stub code)替换那些已经分配给协助DLL的函数。桩代码是指不执行任何满足原始要求的处理的代码。在这个例子中,桩代码所做的处理是将调用传给适当的协助DLL中的适当函数。这种方法使原始DLL分为宿主DLL和多个协助DLL。
载入协助DLL
载入协助DLL有多种方法。
a)根据任何函数的请求可以载入协助DLL。这对任何调用程序都是透明的;宿主DLL保持与原始DLL二进制兼容。用于载入协助DLL的代码(如果需要)将被包含在与宿主DLL同时生成的桩代码中。
b)一旦协助DLL到一个点,在该点上对于使用适当函数的需要变得明显,则所述协助DLL可由应用程序或客户端通过直接请求而主动载入。这种机制具有缺点,即应用程序或客户端将需要被修改,从而在相同装置系列中针对不同装置需要不同的版本。
c)如果使用实例分析揭示出一种能够用于发现何时需要适当函数的模式或者揭示出需要该函数的使用实例已经运行,则可以将协助DLL主动载入。这对于应用程序或客户端是透明的。例如,如果我们知道函数“y”总是刚好在使用实例“b”需要函数组之前被调用,那么我们就可以开始不同步地为使用实例“b”载入正确的协助DLL,从而在我们需要时可以使用该协助DLL。当宿主DLL生成时,这个触发可包含在函数“y”的代码中。这种机制具有以下优点:一个以上的宿主DLL所需要的协助DLL可能被链接到相同的使用实例;因此,一旦已经识别出该使用实例,则它可以为多个宿主DLL触发所有适当的协助DLL。这种机制的一种变形可以是,函数“y”使用将触发适当载入的系统宽度的通知机制(例如,发布和订阅服务器)。调用协助DLL的代码可被加入到已经通过分析识别出来的桩函数中。
卸载协助DLL
使用协助DLL之后,当不再需要该协助DLL时,可将其卸载并释放它所占用的存储器以便用于其它用途。有多种用于卸载协助DLL的机制。
a)一旦协助DLL到一个点,在该点上明显地不再需要使用适当函数,则所述协助DLL可由应用程序或客户端通过直接请求而主动载入。这种机制具有缺点,即应用程序或客户端将需要被修改,从而在相同装置系列中针对不同装置需要不同版本。
b)如果使用实例分析揭示出一种能够用于发现何时不再需要适当函数的模式或者揭示出需要该函数的使用实例已经结束,则可以将协助DLL主动卸载。这对于应用程序或客户端是透明的。例如,如果我们知道使用实例“b”所需要的函数组在函数“y”之后不再被调用,那么我们就可以在函数“y”之后立即卸载用于使用实例“b”的协助DLL。当宿主DLL生成时,这个触发可包含在函数“y”的代码中。这种机制具有以下优点:一个以上的宿主DLL所需要的协助DLL可能被链接到相同的使用实例;因此,一旦已经识别出该使用实例,则它可以为多个宿主DLL触发对于多个协助DLL的卸载。用于卸载协助DLL的代码可被加入到已经通过分析识别出来的桩函数中。这种机制的一种变形可以是,函数“y”使用将触发适当卸载的系统宽度的通知机制(例如,发布和订阅服务器)。
c)协助DLL将在其函数不再被调用时卸载;这种机制类似于存储分页连接中所用的最不经常使用算法(leastfrequently used algorithm)。
前面描述了如何将属于相同系列的不同特征型号的计算装置的RAM需求与每个具体型号的特征等级相匹配,同时保持与相同系列中其它型号的兼容性。此概念的实现特别适合于那些在NAND闪存或不可执行的非易失性存储器中存储核心操作系统镜像并且在启动时将镜像拷入RAM的装置。优选的实施例包括步骤:识别出不同装置较少使用的函数,所述不同装置通过为这些装置生成使用实例进行区分;然后在该装置系列中具有完全不同特征的装置上对这些使用实例所调用的函数进行描绘。对于所产生的调用关系图所作的分析揭示出哪些函数需要作为核心操作系统镜像中的宿主DLL进行保留,哪些函数可以合理地从协助DLL动态载入。通过用将调用和请求传到协助DLL的桩代码来替换从宿主DLL移到协助DLL的那些函数,装置系列的二进制兼容性得以保持。
从上述具体例子中可见,使用本发明实施例可导致多个优点。一些潜在的优点是:
●属于一个装置系列的NAND闪存计算装置中操作系统核心镜像的大小可设计为与该装置所需要的函数相适应,同时保持与该装置系列中具有完全不同特征的其它装置之间的二进制兼容性。
●NAND闪存中较小的核心操作系统镜像意味着载入时该镜像占用较少的RAM。
●NAND闪存中较小的核心操作系统镜像意味着该装置将启动得更快。
●需要较少RAM的事实意味着,具备压缩特征集的装置能够在较低的成本和消耗较少的自然资源的情况下进行制造。
●需要较少RAM的事实意味着,具备压缩特征集的装置将消耗更少的电力。
本领域技术人员应当理解,可以采用替换实施例,在由所附权利要求书所限定的本发明的保护范围中,可以对上述方法和实施例进行各种修改。