一个项目原本只需要几分钟就能完成编译,但是在某次修改之后,编译的速度突然就慢下来了,这种变化不一定是由于代码量增加所导致的。当我们想要弄清楚TASKING编译速度为什么会突然变慢,以及编译缓存明明开了却没有起效时该从哪些方面去排查,就要先把全量重编译、缓存连续未命中、头文件连锁变化以及链接阶段耗时这几种情况区分开来。TASKING的SmartCode编译器本身具备缓存中间结果的功能,当源文件经过预处理之后的内容、相关的编译选项以及编译器的版本都维持不变时,就可以直接把已经生成的结果拿来复用,不必从头再编译一次。
一、TASKING编译速度为什么突然变慢
在编译速度出现变动的时候,不应该仅仅去看总的耗时有多少。更合理的做法是先把构建过程的日志打开,从里面分辨出时间主要是花在了编译环节、汇编环节还是链接环节。
1、检查是否触发全量重编译
当执行了【Project】→【Clean】这个操作以后,整个工程就会从头开始构建。另外,如果头文件、公共宏、芯片配置文件以及启动文件发生了变化,也很可能带动大量的源文件重新编译一遍。可以先在日志里查看实际参与编译的文件个数,然后再判断是不是因为某个公共文件被修改,从而引起了一大片连锁更新。
2、检查是否开启复杂优化
打开【Project】→【Properties】→【C/C++Build】→【Settings】→【Tool Settings】这些菜单,去查看优化设置。像应用级的优化、MIL链接、调试信息以及各类静态检查,都会让处理的时间变长。TASKING的工具选项里面提供了应用级优化、调试信息、MISRA检查和CERT检查等配置,平时用来调试的版本没有必要把所有选项都同时打开。
3、检查链接脚本和生成文件
LSL脚本、自动生成的头文件或者配置工具的输出内容一旦发生了变化,工程就可能不断地触发重新构建。可以通过观察构建目录里文件的修改时间,来确认是不是有某个脚本在每次编译的时候都会重新写入同一份文件,哪怕文件的内容其实一点都没有变,这样也可能让依赖关系的判断变得不再可靠。
4、区分C和C++耗时
如果工程是用C++写的,当模板展开得比较多的时候,编译时间通常就会显得更加明显。在TASKING工具设置当中,支持对C++项目使用预编译头文件,可以为那些使用频繁但又很少改动的公共头文件启用它,这样就能减少重复解析头文件所花的时间。
二、TASKING编译缓存没有生效时该查什么
在缓存功能被打开以后,如果每一次编译还是要完整地走一遍流程,那通常就是缓存目录、清理选项或者具体的命中条件没有满足。排查的时候可以先去看一看配置,再检查一下日志。
1、确认缓存已经启用
首先要检查缓存功能是不是真的已经被打开了,顺着【Project】→【Properties】→【C/C++Build】→【Settings】→【Tool Settings】→【C/C++Compiler】→【Optimization】→【Compilation Speed】这个路径点进去,找到【Cache generated code to improve the compilation speed】这一项并把它勾选上。默认情况下,缓存目录会被放在工程目录下的.cache文件夹中,编译器会在里面创建一个叫做ctccache的子目录。
2、检查Clean是否清空缓存
在同一个设置页面里,还有一个选项叫做【Clear cache upon project clean】,如果这个选项被勾上了,那么每次执行【Project】→【Clean】操作的时候,缓存就会被一起清掉。在日常开发中,如果只是想重新做一次链接,或者验证一下增量编译的效果,最好不要顺手就点Clean,否则就会让缓存根本没有被利用上的机会。
3、检查缓存命中条件
缓存的命中是有条件的,它只在单个C输入文件对应单个输出文件这种场景下才起作用,如果使用了--mil-split参数,缓存就不会被命中。另外,只要源文件经过预处理之后的内容发生了改变,或者编译选项、编译器版本跟之前不一样了,都会产生新的缓存结果。如果公共头文件和宏定义改得特别勤,缓存的效果自然就会打折扣。
4、检查缓存目录状态
缓存目录自身需要有正常的读写权限。虽然把它放在网络共享盘上可以让多个人共同使用,但网络访问的速度和连接的稳定程度也会影响实际使用体验,这需要根据具体的环境去验证。缓存文件并不会自动地一直清理下去,TASKING建议为它们设置一个最大的保留天数,并且定期去运行专门用来清理过期缓存的工具。
三、TASKING编译耗时怎么稳定下来
要想让编译时间稳定下来,光靠缓存这一项还不够,工程的配置和日常构建的习惯也需要一起整理好。
1、保存一次完整日志
可以分别记录一次完整的全量构建(Clean Build)和一次增量构建(Incremental Build)所花费的时间,并且把编译的文件数量、链接消耗的时间和缓存目录的变化情况放在一起进行比较。如果没有留下日志,光靠感觉去判断,就很容易把链接阶段慢的问题当成是缓存没有生效。
2、减少无意义文件更新
对于用来自动生成文件的脚本,最好只在文件内容真的发生了变化的时候才去覆盖原来的文件。在修改公共头文件之前,要先弄清楚它的改动到底会影响到多大的范围,不要把所有局部配置都一股脑地塞进同一个总头文件里面。
3、区分日常和发布配置
可以把日常开发用的配置和最后准备发布时的配置分开来,在日常开发的配置里只保留必要的优化选项和调试信息,等到快要发布的时候,再把完整的检查项和应用级优化打开。这样做就可以缩短每一次小改动之后等待编译的时间。
总结
总的来看,当TASKING的编译速度突然下降时,可以先排查是不是发生了全量重编译、公共头文件被修改、开启了复杂的优化选项,或者是由生成文件反复更新引起的。如果发现编译缓存没有起到作用,就需要重点检查【Compilation Speed】里面的启用状态、关于Clean时清理缓存的选项、缓存目录的读写权限,以及缓存的命中条件是否满足。只要把构建过程的日志、工程的各项配置,还有文件的修改时间放在一起对照着看,通常就能更容易地找到真正让编译变慢的地方。