您的位置:首页 > 移动开发 > IOS开发

iOS开发中可以节省50%编译等待时间的解决方案

2016-01-08 09:18 483 查看


作为开发者,我们是不是经常在等待Xcode完成build的过程中,感觉iOS程序需要编译很久,有时候,老板迫切希望给他的手机装上最新的版本,然后马上出门见客户,这个时候,你肯定是特别希望,Xcode编译的时候,能够快一点,我记得有一次,我就因为这个,而被老板记住了。所以,当我们按下运行来测试修改过的内容,看着那几乎无止境的等待循环。对于这种状况我感觉特别浪费时间。

所以:如何缩短build时间,似乎是一个有待解决也很有趣的难题,也是一个了解OSX内部结构的大好机会。因此,我决定尝试一下。非常幸运,取得了显著效果:我减少了50%的等待时间。


解决方案

我的开发流程(也是最常见的一种情况)如下:

修改一些源文件。
按下Xcode中的运行程序按钮。
观察在phone或者模拟器上的效果(我的例子中使用的是模拟器)。
跳到第一步。在我修改了一个Spotify的iOS客户端中相对较小的 Objective C 源文件之后,我记录了一下步骤(2)到步骤(3)花费的时间,直到模拟器加载完应用程序:我的家用iMac(说实话,已经很旧了)花费了82秒(平均值)。通过观察Xcode的编译流程我意识到大部分时间花费在“Linking”和“Generating dSYM file”阶段。





在命令行中进行一些测量证实了这一点,平均而言:

Linking花费了29秒
生成dSYM 花费了25秒这两个阶段占用了等待时间的(29 + 25) / 82 * 100 = 62 % 。但是,毕竟,Spotify的iOS客户端代码库是非常大的(链接器要把大约2000个目标文件组合起来),花费这么多时间或许也有些道理。然而,并非完全如此……


dSYM 文件生成

老实说我对dSYM bundles了解不多,只知道其中包含调试信息。得知dSYM最初是作为Apple的一个“临时解决方案”,我感到非常惊讶。事情是这样的:在OSX早期阶段,Apple为了避免在链接器中引入DWARF支持的麻烦,创建了独立的链接器(dsymutil),这个链接器将调试信息从目标文件中取出,放到一个同一个地方:一个dSYM
bundle中。

dSYM bundles 对于发行版本有用,但在开发过程中并不需要。调试器可以从中间目标文件中获取调试信息,这些文件在 build 完成后仍然存在。

Xcode 允许开发者设置自己工程的 “Debug Information Format”,可以选择使用“DWARF”而不是“DWARF 和 dSYM File”。



由此,在XCode中简单地改变一个选项,就可以减少大约25秒等待时间:非常棒!


Linking

不幸的是,没有神奇的选项可以跳过链接。或许,你也能跳过它,但是你最终会得到一大堆无用的目标文件:)

最初,我认为缩短30秒链接时间(像永恒那么久!)的唯一途径是研究Apple的链接器,Id64,实现增量链接。这项任务相当复杂,所以我决定首先
profile 一下 Id64 的执行过程来寻找已有的实现方案。

Apple提供了Id64的C++源代码,尽管是过时版本,我还是尝试了一下,希望和XCode中包含的最新版本之间不要有根本性的差别。源代码不是编译好即时可用的,我参照Macports代码,快速地在
instrument 中运行起来Instruments)。



上面的截图,也许你一眼看上去并不能获得太多信息,但是如果你读过Id64的设计文档,你会迅速得出:ld::tool::Resolver::resolve()相当于Id64管道的Resolving
阶段。简言之,这个阶段负责将表示各个目标文件的图表放到一个更大的全局表里面。

早些时候已经完成了目标文件各自图表的加载,因此,原则上,解析不会太费时,当然不应该影响执行时间(占执行时间的76.9%)。因此,如果你仔细观察,你会发现ld::tool::Resolver::linkTimeOptimize()占用了51.3%的链接时间。

linkTimeOptimize()执行链接时优化(LTO)。在Clang/LLVM领域,这意味着链接器获得的是LLVM字节码,而不是通常的目标文件。这些字节码在一种更抽象的层次上代表程序的执行过程,允许LTO得以进行,但是坏处是,仍然需要将他们转换成机器代码,在链接时需要额外的处理时间。

在Id64加入了一些logging做了一些枯燥的探索,我成功定位那些令人生厌的二进制文件。这些二进制文件是一个静态库的一部分。而这个静态库,出于善意,编译优先级设定为-O4。 Quoting Clang手册记述如下:

-O4能够优化链接时间;目标文件以LLVM二进制文件格式存储,在链接期间,优化了整个程序。

我将优先级标志降为-O3,然后链接器速度提高了51%,每个周期节约了大约15秒。


结果

每个周期大约缩短了25 + 15 = 40秒(占等待时间的40 / 82 * 100 = 49 %)。我们大胆估算一下大约能节省多少时间:

假设:

由于使用新的硬件,效率提高了2倍。
开发者每10分钟一个Edit-Build-Test周期。
开发者每天工作5个小时。这样每人每天可以节省 40 秒/ 2 (5 60 / 10) = 600 秒 = 10 分钟。在一些大的 iOS 团队像 Spotify,每10个iOS开发者,每天将会节省1小时40分钟,完全不需要花费任何代价.这只是粗略估计,我们也要有所保留。我并没有打算建立一个严格的测试对比。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: