MDK编译优化笔记

Wesley13
• 阅读 919

在一次使用MDk的编译优化等级比较高的时候发现编译不优化时功能正常,开了优化等级02就出现异常,调试中看了很多博客总结一下。

  • 一个变量,如果你的主程序要用到,同时中断还要用到,要加volatile修饰。告诉编译器这个变量是可能随时发生变化的,使得编译器编译程序的时候,每次都从RAM里面读取数据,而不是使用之前缓存到寄存器里面的值。
  • 对于多任务的程序,如果一个公共变量被多个任务用到也要加volatile修饰。
  • 同时变量定义的时候用了关键字volatile修饰,但是在其他文件引用时不加volatile变量修饰一样会被编译器优化掉。现则反过来想想,原因还是很简单的,MDK编译多个文件时是分别编译,最后再用链接器链接,当编译的时候一个模块引用另外一个模块的变量,完全是靠的变量声明,如果声明都不加volatile,那么引用的模块肯定会把变量当成普通变量的,再反推一下,如果原变量没有加volatile,但是声明的时候加了volatile,是不是引用的模块会将这个变量当成volatile型变量呢

C编译器是以每个C文件作为基本编译单元的,称为模块,被编译为obj;而模块之间的函数或变量访问都是通过标号来实现的,标号本身没有任何属性,只是提供给链接器使用的一个符号名称而已,标号的属性完全就靠调用的地方的原型声明来决定的!因此,你在一个.C模块中定义为volatile,仅仅是在.C模块中告诉编译器不要优化而已,在另外的模块内使用了这个变量,而它们是不知道该变量是什么属性的,所以只有靠原型声明来告诉编译器这些信息了。

最后简单的给总结一下:别小看原型声明,它是联系各个模块的桥梁,是各种输出符号的属性信息所在。编译原理不懂就是比较亏啊。。。

最后补充一下MDK中关于编译的一些选项说明:

USE Cross-Module Optimization

跨模块优化从先前的构建中获取信息,并使用它将UNUSED函数放入其中在相应的目标文件中拥有自己的ELF部分。 此选项也称为链接器反馈,需要构建程序两次以利用它来减少代码大小。

USE MicroLIBMicroLIB

是一个针对嵌入式平台优化过的C库可以减少应用程序的大小。他是标准C库的一个子集,以提供功能和代码大小之间的权衡,比如一些标准C库的memcpy函数应用到微控制器上就运行速度来说比较慢。原文(Some of the standard C library functions such as memcpy() are slower, while some features of the default library are not supported.)这里还说默认的库还不支持一些特性:

包括:

  1. 操作系统功能,例如 abort(),exit(),time(),system(),getenv()
  2. 宽字符和多字节支持,例如 mbtowc(),wctomb()
  3. stdio文件I/O函数,stdin,stdout和stderr除外
  4. 位置无关且线程安全的代码

Link-Time Code Generation(这个选项新版好像没有了)
链接时代码生成指示编译器以中间格式创建对象,以便链接器可以执行进一步的代码优化。 这使代码生成器可以同时查看所有对象的跨文件依赖性,从而允许它应用更高级别的优化。 链接时代码生成可以减少代码大小,并使您的应用程序运行得更快。
Optimization Levels

不同的优化级别允许您在级别之间进行权衡已编译代码中可用的调试信息以及代码的性能。以下优化级别可用:
-O0应用最小优化。
大多数优化都被关闭,生成的代码具有最佳的调试视图。
-O1应用受限优化。
例如,删除未使用的内联函数和未使用的静态函数。在这个优化级别,编译器还应用自动优化,例如删除冗余代码和重新排序指令以避免互锁情况。生成的代码经过合理优化,具有良好的调试视图。
-O2应用高优化(这是默认设置)。
在此级别应用的优化利用了ARM对处理器体系结构的深入了解,利用给定目标的特定于处理器的行为。它生成优化良好的代码,但有限调试视图。
-O3应用最积极的优化。
优化符合用户的-Ospace / -Otime选择。默认情况下,多文件编译是启用,这会导致更长的编译时间,但会提供最高级别的优化。

Optimize for Time
“优化时间”复选框使编译器进行优化,更加注重实现最佳效果检查时的性能(-Otime)或未选中时的最小代码大小(-Ospace)。
取消选中Optimize for Time就意味着选择-Ospace选项,该选项指示编译器执行优化以可能增加的执行时间为代价来减小Image文件大小。例如,使用非内联函数调用而不是大型结构副本的内联代码。 这是默认选项。从中运行编译器时命令行,使用'-Ospace'调用此选项选中Optimize for -Otime选项,该选项指示编译器以最快的速度优化代码执行时间,有可能增加image文件大小。建议编译时间关键部分您的代码使用-Otime,其余使用-Ospace指令。

Split Load and Store Multiples
指示编译器将涉及大量寄存器的LDM和STM指令拆分为一系列较少多个寄存器的加载/存储。这意味着16个寄存器的LDM可以分成4个独立的LDM,每个LDM由4个寄存器组成。此选项有助于减少没有缓存或写缓冲区的ARM系统上的中断延迟,以及使用零等待状态32位内存的系统。
例如,ARM7和ARM9处理器只能在指令边界上执行异常。如果在无缓存的ARM7和ARM9系统中的16个寄存器的LDM开始时发生异常,则系统将在获取异常之前完成对存储器的16次访问。根据存储器仲裁系统,这可能导致非常高的中断延迟。将LDM拆分为4个寄存器的4个独立LDM意味着处理器在加载最多4个寄存器后将采用异常,从而大大减少中断延迟。选择此选项可提高系统的整体性能。
One ELF Section per Function
选项告诉编译器将所有函数放入它们各自的ELF部分。 这允许链接器删除未使用的函数.ELF代码部分通常包含许多函数的代码。 链接器通常只能删除未使用的ELF部分,而不是未使用的函数。 只有当所有内容都未使用时,才能删除ELF部分。因此,将每个函数拆分为自己的ELF部分允许编译器轻松识别哪些未使用,并将其删除。选择此选项会增加编译代码所需的时间,但可以提高性能。

常见优化目标选项

最小的目标代码:

选中
• The MicroLIB C library
• Cross-module optimization
• Optimization level 2 (-O2)

最好的代码表现性能:

选中
• Cross-module optimization
• Optimization level 3 (-O3)
• Optimize for time

最后总结一句话,只要代码逻辑够严密无论是多高的编译优化等级都是不会出问题的,所以在资源不是出现了必须要优化的时候不建议优化代码,自己增加实现难度而已,反之如果你追求功能的稳定可以在优化等级下发现0级优化下存在的问题进行完善在改回0级优化编译此时代码的逻辑漏洞会减少。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这