电子产业一站式赋能平台

PCB联盟网

搜索
查看: 73|回复: 0
收起左侧

写个单片机程序,居然被优化了!

[复制链接]

320

主题

320

帖子

2688

积分

三级会员

Rank: 3Rank: 3

积分
2688
发表于 2023-11-15 11:45:00 | 显示全部楼层 |阅读模式
关注+星标公众,不错过精彩内容: v9 D5 l- z" e5 [* a) x, V" ]

vcg11mt52ac64013505640.jpg

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

    rrfun252eec64013505740.png
    ! G3 `* p. T% M) ^6 t

    fprjslzlzd364013505840.jpg

    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

    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 MicroLIB
  • Use Cross-module optimization
  • Optimization:level 2 (-O2)% K3 Z- t  _$ E
    针对AC6编译器:
  • Use MicroLIB
  • Optimization:-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

    sa15wgadujd64013506040.png

    5 K+ y' f& a1 k; D0 k$ l4 Z2.优化代码性能, \  X, Q* p. o0 Z3 q
    针对AC5编译器:
  • Use Cross-module optimization
  • Optimization:level 3 (-O3)
  • Optimize for Time3 g. _; h6 R+ \* y0 a. k  x: z% {2 i* H
    针对AC6编译器:
  • Optimization:-Ofast
  • Link-Time Optimization5 \' H7 T) i0 `8 x; b2 T$ f
    代码优化性能(对比):' a1 h/ e) z' G: ]$ v8 g3 h8 G0 k

    q0k0wbrrcky64013506140.png

    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 optimization
  • Optimization:level 3 (-O3)
  • Optimize for Time' C# a  f" F/ M5 ]' l8 a3 r
    针对AC6编译器:
  • Optimization:-Os balanced
  • Link-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

    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

    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

    4vp3obun5qz64013506440.jpg
    4 f+ h. u2 T. z- ?- g
    6 M. d, i8 ~9 _0 o% F' k5 T( e# a

    drvnsxjuqkb64013506540.png

    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点击“阅读原文”查看更多分享。
  • 回复

    使用道具 举报

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    联系客服 关注微信 下载APP 返回顶部 返回列表