关注+星标公众号,不错过精彩内容: v9 D5 l- z" e5 [* a) x, V" ]
vcg11mt52ac64013505640.jpg
) H4 R! C( ]$ J8 Q: G" s* [% w作者 | strongerHuang微信公众号 | 嵌入式专栏
8 k9 Y* i8 } M% t9 D3 g最近看到小伙伴讨论【我的代码不按照流程执行】相关的话题。。。1 e, C5 R$ n4 r( p
这类问题,有经验的工程师肯定能想到是什么原因导致的,那就是编译器把你代码优化了。) r5 e" C5 e1 X, {6 L
本文围绕Keil MDK优化选项,以及相关拓展知识(微库、实际应用、调试)进行讲述,希望对你项目开发有所帮助。* f4 c# n7 B0 r
概述
; e9 C- H) S8 x* i! b/ `我们所指的优化,主要两方面:代码大小(Size)代码性能(运行时间)* l/ \6 M: u' t6 d+ |- \ ^
" O5 w& R6 {5 {+ o1 _在MDK-ARM中,优化相关的配置选项:- Z0 V4 @; o2 B# Z
rrfun252eec64013505740.png
! G3 `* p. T% M) ^6 t
fprjslzlzd364013505840.jpg
9 O& d4 H- M0 ~当然,如果选择编译器(AC5、AC6)不同,优化选项也有差异(下面讲述)。; v0 b5 c+ g5 n* N1 e
举例:某些项目MCU容量有限时,你除了修改代码(优化开支),同时你有必要使用优化选项。
! j# E( z% I7 O某些项目(比如某算法)需要高效(最短时间)运行,此时有必要使用优化选项。
1 n% n4 L8 g6 P$ s: J( S/ x优化选项说明
1 D( m& W2 [; S) ~; t' a5 E4 K本节详细讲述优化相关选项,同时,编译器选择AC5和AC6时有差异,下面也会针对AC5和6分别讲述。
* A, B3 `$ P2 x! M0 c1.Use Cross-Module Optimization:使用跨模块优化使用跨模块优化可以启用链接器反馈文件(进行两次编译),从而允许进一步的代码优化。( a% [/ ~; J4 Y0 C3 G5 E* S% ]
提示:$ D1 S' p# w6 O6 g: T& Q! l
A.不针对库目标执行跨模块优化。B.跨模块优化将增加构建项目所需的时间,因为会自动执行多个编译和链接步骤。
3 w- T, P5 U' V4 \5 V2.Use MicroLIB:使用微库它是ISO标准C运行时库的子集(其中一部分),提供了性能和代码大小之间的权衡。
/ F* }7 Y: ]) Z/ h& n微库并不完全兼容ANSI,但对于大多数小型嵌入式应用程序来说已经足够了。
. I$ x, q2 V) Q4 T4 ^: |3.Use Link-Time Code Generation:使用链接时代码生成(优化)在V5版本之前有这个优化选项,多文件编译,链接时进行优化:函数跨模块内联删除未引用的变量和函数通过重新排列变量优化内存访问在可能的情况下重用内存- }6 h9 A- @) V6 ?0 ^, o
4.Execute-only Code:生成只执行的代码不包含未使用(函数、变量等)代码段。
8 G+ j; g5 A4 R/ Q0 k( f仅限于:, l, I0 R- y0 c) E/ `
C、Thumb代码基于Cortex-M3、M4的处理器编译器5.04以上
( C6 a. @- t' [+ k' V: H6 T8 q5.Optimize for Time:优化时间
- O T0 B# L! M# K以更大的代码大小为代价,减少执行时间。比如:使用内联函数。9 ~/ F" x0 `3 a% W0 g( T$ v
编译器为AC6时,此选项为【Link-Time Optimization】,在链接状态下执行模块间优化。' \/ G) n7 {6 _% D
6.Split Load and Store Multiple:分割加载和多存储指示编译器将LDM和STM指令拆分为两个或多个LDM或STM指令,以减少延迟,此选项可以提高系统的总体性能。! v( q' j$ ^# b9 U; F" j
7.The One ELF Section per Function:每个函数一个ELF段ELF代码段通常包含许多函数的代码,此选项告诉编译器将所有函数放入它们自己的ELF段,这允许链接器删除未使用的ELF段(而不是未使用的函数)。. E1 c1 T& P2 T
8.AC5时:Optimization优化选项:默认值,以优化性能为主。
e3 w1 a2 U* {! S$ F' w# |/ T' iLevel 0 (-O0):关闭大部分优化,除了一些简单的转换,生成的代码具有最佳的调试视图。
5 {$ E9 ^( _; O8 k, m5 fLevel 1 (-O1):应用受限优化。比如:删除未使用的内联函数和静态函数,删除冗余代码和重新排序指令等。生成的代码经过合理优化,具有良好的调试视图。
; S6 N1 J& R! J) \, A$ `Level 2 (-O2): 高度优化,目标代码到源代码的映射并不一定对应,因此,不利于调试。
! {0 m0 d" O% j9 _, Z8 |0 G5 \7 HLevel 3 (-O3):最大级别优化,级别3与时间优化相结合可能生成比级别2更多的代码。
! p/ |5 X1 [& q. j9.AC6时:Optimization优化选项当编译器选择AC6时,优化选项有差异(有更多优化选项):7 ~# h, x! g; {3 h. u! D2 u
jsdhs2qp0hg64013505940.jpg
8 Z4 V" a5 d. [3 w
AC6优化选型中前面5项(default、-O0 ~ 3)和AC5的作用基本一样,但AC6多了三个选项。- s$ h, d; R1 Q, B& t/ [
-Ofast:启用-O3的所有优化,以及其他可能违反语言标准(严格遵守)的优化。
+ c3 Y4 M4 j. P% m2 s-Os balanced:平衡代码大小与代码速度。默认情况下,编译器执行优化以提高性能,但可能会增加image文件大小。- f$ ]5 E9 }( f3 @7 v
-Oz image size:优化代码大小。
2 D; r- f; p5 g) d; O如何优化% s4 w9 u" H; [5 }9 f
本节讲述三种编译优化,使其达到最优(代码最小、性能最好)代码大小代码性能(速度)代码平衡(大小和速度) J; J0 F7 U9 d0 _& M
1.优化代码大小针对AC5编译器:( |9 f; m! m" s0 d" K! ^+ j& P
Use MicroLIBUse Cross-module optimizationOptimization:level 2 (-O2)% K3 Z- t _$ E
针对AC6编译器:Use MicroLIBOptimization:-Oz image size
2 {5 `& C7 m2 A! M( h+ U说明:A.代码量大(ELF代码段通常包含许多函数的代码),可考虑使用The One ELF Section per Function选项减小代码。1 |$ P6 \) v- y) \! f
B.AC6编译器改进了优化功能(可以理解为增加的3个选项集成了优化功能)。5 A; i( k, U7 O# N1 z
代码优化大小(对比): m, H2 H T, H R
sa15wgadujd64013506040.png
5 K+ y' f& a1 k; D0 k$ l4 Z2.优化代码性能, \ X, Q* p. o0 Z3 q
针对AC5编译器:Use Cross-module optimizationOptimization:level 3 (-O3)Optimize for Time3 g. _; h6 R+ \* y0 a. k x: z% {2 i* H
针对AC6编译器:Optimization:-OfastLink-Time Optimization5 \' H7 T) i0 `8 x; b2 T$ f
代码优化性能(对比):' a1 h/ e) z' G: ]$ v8 g3 h8 G0 k
q0k0wbrrcky64013506140.png
1 i s* Z, @5 r' E, a& d% @3.代码平衡这种情况下,在满足代码大小的同时,我们应尽量满足性能。
" D9 j& i4 N/ F7 J3 d这里其实就是一个相关平衡的关系,结合上面两种优化方式根据自己实际情况出发,一般优化考虑如下配置。: p9 I. X' A$ G. }/ J
针对AC5编译器:Use Cross-module optimizationOptimization:level 3 (-O3)Optimize for Time' C# a f" F/ M5 ]' l8 a3 r
针对AC6编译器:Optimization:-Os balancedLink-Time Optimization
7 k3 ]) N" ^: P当然,AC6中-Os balanced优化选项更智能。4 ]. z2 ~* g ^2 v1 {
拓展
+ L; C; n! w4 D3 o' M: }& s+ WKeil MDK的优化功能需要结合项目实际情况进行优化。对一些项目能起到很大帮助作用,但优化之后也可能带来一些影响。
9 A5 E. w0 v# O( v$ J# S1.使用高度优化(-O1以上),可能会影响Debug调试(因为优化之后,编译输出和实际代码不匹配)。
- M8 [0 H# d) q+ p8 p/ @2.指定源文件/文件组优化有些代码不需要优化,我们优化指定的源文件/文件组就行。# D4 G* p8 M; Z
hzyniaczkft64013506240.jpg
8 x8 L; K" S H; E, g3 K9 G6 V------------ END ------------
$ ~) v$ I0 M& Q% I. h: X' }; r$ m& } y
jho4tjigpdp64013506340.gif
) y, K' x% X% e+ W
, I# N; H+ S3 d! z& T# d●专栏《嵌入式工具》6 ~# I' m9 N4 ]* K1 E% k
●专栏《嵌入式开发》4 ?. ~! z2 _& u; g
●专栏《Keil教程》* r9 m* Q! [, Z
●嵌入式专栏精选教程
/ L- N& X9 n3 T) Y# @6 M
$ X. {) ~, w9 x. J关注公众号回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。
* q0 b% O' e% J4 t" ]
4vp3obun5qz64013506440.jpg
4 f+ h. u2 T. z- ?- g
6 M. d, i8 ~9 _0 o% F' k5 T( e# a
drvnsxjuqkb64013506540.png
5 @0 m8 @8 U* S% O) l1 l( z* r6 I. S' K
, f: C& A7 l- N0 `: m+ y0 x h3 F9 k点击“阅读原文”查看更多分享。 |