引出问题:

    一个好的工程项目代码,特别是开源类的,如果能做到各种优化等级通吃,是一种非常好的工程案例,这样别人借鉴的时候,可以方便的适配到自己工程里。但实际项目中,针对一款产品代码,我们一般不会这么干,因为非常耗精力,意义也不大,一般是追求最高性能,最小代码量或者更高的稳定性,我们会选择一个合理的优化等级。

但是随着工程的复杂,特别是一些第3方组件的加入,很容易碰到不耐优化的情况。也就是这个组件没法适配到我们当前的优化等级里面。甚至有时候我们还会遇到高优化等级能用,改成0级优化反倒不能用了。

本期帖子我们就分享一种方法来解决这个问题,合理的设置不同代码的不同优化等级,即一种优化为主优化等级,其它代码设置到能用的优化等级上,以此来达到通吃的目的。

如果采用这种办法可以一步一步的锁定具体问题所在,并将工程文件全部设置到同一个优化等级是最好的。

MDK设置方法(AC5和AC6):

分两个方向:
1、开启优化后,部分功能不正常

解决思路是把这部分的文件继续设置为低优化等级,整体工程设置为高优化等级(这种方法可以锁定有问题的文件,然后锁定具体有问题的函数)。



2、开启优化后,直接整体卡死

解决思路是整体工程设置为低优化等级,逐步开启工程文件的优化等级。具体到某些函数的优化也是可以单独开启测试的。

AC5设置方法:

比如设置函数优化等级为0
https://www.keil.com/support/man ... hr1359124988971.htm

1 #pragma push
2 #pragma O0
3 void function(void){
4 ... // Optimized at O0
5 }
6 #pragma pop

AC6设置方法:

这里设置无优化

1 void function(void) _attribute__((optnone))
2
3 {
4 ... // Optimized none
5 }

IAR设置方法:

IAR和MDK的设置是一样的,同样我们也分为两个方向:

1、开启优化后,部分功能不正常

解决思路是把这部分的文件继续设置为低优化等级,整体工程设置为高优化等级(这种方法可以锁定有问题的文件,然后锁定具体有问题的函数)。



2、开启优化后,直接整体卡死

这种的解决思路是整体工程设置为低优化等级,逐步开启工程文件的优化等级。具体到某些函数的优化也是可以单独开启测试的。

比如设置函数无优化:
https://netstorage.iar.com/SuppDB/Public/UPDINFO/004916/arm/doc/EWARM_DevelopmentGuide.ENU.pdf (253页)

1 #pragma optimize=none
2 void foo(void)
3 {
4 /* Do something, but don't optimize this function */
5 }

GCC设置方法:

GCC的话,我们这里以Embedded Studio为例进行说明,同样我们也分为两个方向:

1、开启优化后,部分功能不正常

解决思路是把这部分的文件继续设置为低优化等级,整体工程设置为高优化等级(这种方法可以锁定有问题的文件,然后锁定具体有问题的函数)。



2、开启优化后,直接整体卡死

这种的解决思路是整体工程设置为低优化等级,逐步开启工程文件的优化等级。具体到某些函数的优化也是可以单独开启测试的。

比如设置函数无优化:

1 #pragma GCC push_options
2 #pragma GCC optimize ("O0")
3 void foo(void)
4 {
5 /* Do something, but don't optimize this function */
6 }
7 #pragma GCC pop_options

不同优化最容易出问题的地方:

延迟类函数最容易出问题,特别是像for循环这种简单实现的延迟。可以考虑使用DWT时钟周期计数器做延迟。

http://www.armbbs.cn/forum.php?mod=viewthread&tid=89128

不迷信编译器:

即使再强劲的编译器,有触摸不到的天花板。

MDK AC6的0级优化在这方面的设计问题最明显。比如MDK AC6.14使用0级优化编译HAL库的n级条件表达式会产生巨大的栈需求。

现象:

使用MDK5.30 AC6.14的0级优化测试RTX5的模板程序,发现启动任务需要高达2000字节的栈需求。

原因分析:

通过不断的调试和查看map,htm等文件,最终锁定是H7的HAL库函数UART_SetConfig导致的。

进一步的排查,锁定是下面这种n级条件表示导致的,下面这种类型的表达式偏偏在函数UART_SetConfig里面有一大批,导致产生巨大的栈需求。

 1 /** @brief  Get UART clok division factor from clock prescaler value.
2 * @param __CLOCKPRESCALER__ UART prescaler value.
3 * @retval UART clock division factor
4 */
5 #define UART_GET_DIV_FACTOR(__CLOCKPRESCALER__) \
6 (((__CLOCKPRESCALER__) == UART_PRESCALER_DIV1) ? 1U : \
7 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV2) ? 2U : \
8 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV4) ? 4U : \
9 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV6) ? 6U : \
10 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV8) ? 8U : \
11 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV10) ? 10U : \
12 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV12) ? 12U : \
13 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV16) ? 16U : \
14 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV32) ? 32U : \
15 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV64) ? 64U : \
16 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV128) ? 128U : \
17 ((__CLOCKPRESCALER__) == UART_PRESCALER_DIV256) ? 256U : 1U)

解决办法:

使用AC6中0以外的其它优化就解决了,或者使用AC5的任何优化等级也都可以解决。

又比如:
如果用AC6的优化等级0,没有选择使用微库的话(底层做了C标准库重定向),偶尔会造成脱机(调试仿真下可以使用,拔掉下载器运行就失败)执行失败,将微库勾上即可解决:

这坑也非常容易遇到。

各种优化等级通吃的实战案例分享:

那么问题来了,有没有不需要设置不同优化等级的综合Demo分享?  有的,早期为V6板子设计的二代示波器Demo,可以各种优化等级通吃,并且开启了时间优化。无需采用本帖的特别设置方法,直接切换优化等级就可以使用,大家有兴趣可以看看工程代码:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=45785



实际项目中让程序代码在所有优化等级下都可以正常运行来检查各种奇葩问题,也是一种非常有效的检测手段,确实可以找到程序里面的一些隐形bug。

 【来源】 http://www.armbbs.cn/forum.php?mod=viewthread&tid=109749

[STM32H7] 实战技能分享,如何让工程代码各种优化等级通吃,含MDK AC5,AC6,IAR和GCC的更多相关文章

  1. 痞子衡嵌入式:MCUXpresso IDE下设置代码编译优化等级的几种方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是MCUXpresso IDE下设置代码编译优化等级的几种方法. 最近公司芯片设计团队正在开发一款全新的基于 Cortex-M33 内核的 ...

  2. 第9期Unity User Group Beijing图文报道:《Unity实战经验分享》

    时间来到了金秋九月,北京UUG活动也来到了第九期.本次活动的主题为<Unity实战经验分享>,为此我们邀请了3位资深的行业大神.这次我们仍然在北京市海淀区丹棱街5号微软大厦举行活动,在这里 ...

  3. Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码)

    Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码)    转 https://blog.csdn.net/lhl1124281072/article/details/800 ...

  4. Linux实战技能,教你轻松应对85%的使用场景

    在Linux实操的过程中,你在网上也能搜到一堆参考资料,但是看完之后还是会觉得似懂非懂,无法举一反三,从网上复制粘贴了事,则极有可能不起作用. 如果侥幸解决了特定的问题,也意识到自己需要系统学习一下 ...

  5. java版gRPC实战之一:用proto生成代码

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. 老李分享:pep8 python代码规范

    老李分享:pep8 python代码规范 什么是PEPPEP是 Python Enhancement Proposal 的缩写,翻译过来就是 Python增强建议书 . PEP8 译者:本文基于 20 ...

  7. Android studio ocr初级app开发问题汇总(含工程代码)

    博客第一篇文章,稍作修改,增加文字介绍 开发目的 最近由于某些需求,需要在Android手机端实现OCR功能,大致为通过手机照相,识别出相片中的中文信息字段.但是由于新手光环+流程不熟悉,遇到了各种各 ...

  8. 编写Java脚本统计工程代码总行数

    在新公司工作将近一年了,一直独自一人负责服务端集群的运维和代码的编写.不知不觉从一个Project发展到了七八个Project. 看着越来越多的代码,今天突然想统计一下一共写了多少代码.[这里只统计完 ...

  9. 实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了

    实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了 前言 在日常的软件开发中,程序员往往需要花费大量的时间写CRUD,不仅枯燥效率低,而且每个人的代码风格不统一.MyBatis-P ...

  10. 【腾讯Bugly干货分享】微信读书iOS性能优化

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/578c93ca9644bd524bfcabe8 “8小时内拼工作,8小时外拼成长 ...

随机推荐

  1. 数据智慧:C#中编程实现自定义计算的Excel数据透视表

    前言 数据透视表(Pivot Table)是一种数据分析工具,通常用于对大量数据进行汇总.分析和展示.它可以帮助用户从原始数据中提取关键信息.发现模式和趋势,并以可视化的方式呈现. 在数据透视表中,数 ...

  2. adb shell getprop 获取系统属性

    adb shell getprop 以华为p30为例: [gsm.default.apn]: [gsm.defaultpdpcontext.active]: true [gsm.dualcards.s ...

  3. Android WebView 缓存处理

    加载html时,会在data/应用下生成database和cache两个文件夹:请求的url存在webviewcache.db下面,url的内容保存在webviewCache下面, Webview的两 ...

  4. beanshell导入java文件

    beanshell导入java文件 beanshell可以读取class格式的文件 步骤: a.添加BeanShell预处理程序 b.请求调用 beanshell可以读取java格式的文件 步骤: a ...

  5. 斯坦福 UE4 C++ ActionRoguelike游戏实例教程 10.5.作业五 为游戏添加一个积分系统,随机生成增益道具

    斯坦福课程 UE4 C++ ActionRoguelike游戏实例教程 0.绪论 概述 本篇文章将解决作业五提出的问题,使用PlayerState,在原本游戏的基础上引入积分系统,实现击杀敌人得分,拾 ...

  6. 文心一言 VS 讯飞星火 VS chatgpt (45)-- 算法导论6.1 3题

    三.证明:在最大堆的任一子树中,该子树所包含的最大元素在该子树的根结点上. 文心一言: 在最大堆中,根结点是整个堆中最大元素的孩子,因此它包含的最大元素是在该子树的根结点上. 我们可以通过递归的方式证 ...

  7. Vue接入谷歌广告(Google Adsense)

    1.注册账户 首先你要拥有一个google账号,点击注册谷歌账号,点击个人账号根据提示一步一步来即可注册成功.(当然你需要魔法才可以正常访问谷歌服务) 2.补充账户信息,申请广告授权 点击进入Goog ...

  8. java中的数据库连接池

    常见的连接池的优缺点: HikariCP 优点: 性能出色,尤其在高并发负载下表现良好 内存消耗低,占用系统资源较少 具有自动化的连接池维护和统计功能 缺点: 需要 JDK7 或以上版本支持 配置选项 ...

  9. 普通用户登录切换到root用户

    使用su命令: 在终端中输入以下命令并按Enter键: su - 输入root用户的密码,然后按Enter键. 如果密码正确,你将会切换为root用户,并且可以执行root用户的操作. 使用sudo命 ...

  10. 探索Reactor网络模型在当今应用领域的革新

    本文分享自华为云社区<驾驭网络技术的未来:探索Reactor网络模型在当今应用领域的革新>,作者: Lion Long . 本文介绍了Linux网络设计中的Reactor网络模型及其在实际 ...