欲先善其事必先利其器,对嵌入式工程师来说,嵌入式编译器是不可或缺的神兵利器,它被人冠以“C语言翻译官”的名号。 由于C语言历史悠久,早期没有规范,整个计算机产业也都处于拓荒的年代,所以就涌现了很多款C语言编译器。
根据EEWorld的调研,嵌入式工程师比较青睐的嵌入式编译器主要包括Keil(ArmCC)、IAR、GCC、AVR GCC、CLion、Clang、green hills、TI的CSS、ADI的Visual DSP++。不过,随着嵌入式开发格局逐渐稳固,Keil、IAR、GCC成为嵌入式编译器三巨头,基本大部分嵌入式产品都有其身影。
尤其是GCC,作为一个完全开源的编译器,很多MCU厂商的IDE都由它改写而来。但最近一段时间,业界出现不同的声音,表示“开源才是最贵的”,这些编译器在开源背后潜藏许多隐形成本。
跑RTOS,GCC没打过IAR
现如今,“C/C++与RTOS结合使用”是嵌入式软件开发的黄金范式,所以在嵌入式领域,判别编译器好不好用,那一定是在RTOS上好用。
根据著名嵌入式Jacob Beningo的测试,使用IAR编译时,RTOS指标性能比使用GCC编译时要好得多。根据公制测试,结果略有不同,但通常要好20~40%。以其中一个示例结果为例,该示例将IAR指标结果除以 ThreadX(Eclipse ThreadX)的GCC指标结果。
RTOS测试 ThreadX
基准测试 74%
协同调度 3%
内存分配测试 28%
消息处理 41%
抢占式调度 19%
同步处理 32%
也许会有人说,编写代码的质量决定了性能好坏。这句话确实没错,人们可以花费大把时间,细致地优化代码,但这不意味着开发时间更长,开发成本更高?
比如说,一些IoT项目工期比较短,有时候如果没有来得及去优化,那可能GCC处理时间会增加20%,并且让电池更费电。又或者,GCC编译的代码可能体积也会更大,这时候,内存从120MHz就需要变相升级到200MHz,这几块钱的差距,就会让产品成本大幅度增加。
GCC的确是行业一个福音,但相比商业编译器,也许它本身也存在一定额外的隐形开销。看目前RTOS抑或是开源RTOS本身也是附带工具链的,大部分则只支持GCC,却不支持商业编译器IAR,这种情况导致客户选择面变窄。
Keil比GCC编译文件,更小
虽然Keil目前已经包括五种版本,其中不乏全免费的教育版,而且STM32之类的MCU使用Keil也是免费的,但如果做一些很深入的开发工作,Keil本身还是需要付费的。所以它实质上还是算在商业编译器范畴内。
在工程师群里,很多人都提到一个话题,就是Keil的ArmCC编译器很神。那么实际情况如何呢?
根据工程师的测试,可以得知,GCC的编译速度最快(Keil和VisualGDB都开启多线程编译的)。而bin体积最小的是ArmCC V5。代码的执行效率没有测。
而ArmCC V5和V6对比,编译用时差异不大,手动掐表可以认为是误差范围内。但是bin体积 V5比V6小很多。
优化选项 |
O0 |
O1 |
O2 |
O3 |
Ofast |
Os |
Oz |
|
ARMCC V6.9 |
bin大小(KB) |
131.13 |
90.03 |
95.54 |
98.54 |
97.45 |
87.84kB |
85.47 |
编译用时(秒) |
7.23 |
7.52 |
7.99 |
8.3 |
8.4 |
8.17 |
7.64 |
|
ARMCC V5.06 |
bin大小(KB) |
77.18 |
64.49 |
61.19 |
61.44 |
- - |
- - |
- - |
编译用时(秒) |
7.93 |
8.25 |
8.15 |
9.68 |
- - |
- - |
- - |
|
GCC 7.2 |
bin大小(KB) |
176 |
135 |
136 |
144 |
- - |
129 |
- - |
编译用时(秒) |
3.49 |
3.63 |
3.68 |
4.12 |
- - |
3.96 |
- - |
为什么有时候会出现文件大小区别的情况?有工程师也曾经遇到过GCC编译bin文件比ArmCC大的情况,通过捋顺代码,发现有些原厂本身做了一些优化工作,所以实际上这本身也就节省了工程师优化的时间。
也有工程师表示,Keil有Keil的优势,GCC有GCC的优势,二者大多数情况下不可兼得;Keil(ArmCC)编译对Arm芯片有天然的优势,无论从代码性能和代码尺寸都有更佳的表现;GCC优势在于开源,利于折腾。
也有工程师在m0上做了实验,使用同样的代码触发pendsv中断,ArmCC响应时间为68clocks,gcc响应时间为78clocks。他表示,虽然ArmCC不开源、不免费、不可控,但是它会更代码执行效率更高。
ArmCC中断响应汇编
GCC中断响应汇编
用谁,工程师各持己见
萝卜青菜各有所爱,不论如何测试,工程师总是有自己的偏好。因为公司需求不同,对于Flash、执行速度、交付等要求不同,使用不同编译器都有不同的结果。
喜欢Keil的,在实际体验中,ac6的Osize优化特别猛,性能稍微弱一丢丢,但是体积特别小,其它编译器都比不过,同样的程序比gcc能小四分之一。但它让人又爱又恨,就比如MDK AC6曾经出现过调试到处乱跳的问题,不过商业版本有所改善,或者说MDK经常把if-else结构优化成IT汇编指令,在反汇编窗口中打的断点都命中了实际确不会执行。很多人表示,习惯了。
有人更喜欢用IAR,IAR不仅比Keil便宜很多,而且还内置了misra静态检查工具,很方便。
有传统GCC派,gdb调试Vscode编辑,在Linux系统下编译很香,有些老板不在意Flash的情况下,可以有最快的交付速度。也有Clion、Clang之类的新派。
那么,你怎么看待不同编译器之间的差异问题,你又会选用什么编译器?