引出问题:

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

但是随着工程的复杂,特别是一些第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. 【Python】【OpenCV】凸轮廓和Douglas-Peucker算法

    针对遇到的各种复杂形状的主体,大多情况下,我们可以求得一个近似的多边形来简化视觉图像处理,因为多边形是由直线组成的,这样就可以准确的划分区域来便捷后续的操作. cv2.arcLength() Meth ...

  2. 学透java自增(++)自减(--)运算符

    基本介绍 自增(++)和自减(--)运算符是对变量在原始值的基础上进行加1或减1的操作. 它们都有前缀和后缀两种形式. 前缀就是++在前面,后缀就是++在后面 前缀先自增(减),后缀后自增(减) 前缀 ...

  3. 【Azure APIM】APIM 策略语句如何来设置多个Cookie值让浏览器保存

    问题描述 在APIM的 <return-response> 策略中,设置Cookie值,因为需要设置多个Cookie值,使用下面两种方式都只能保存一个Cookie值: 方式一:把多个coo ...

  4. 如何保证XML正确性

    如何保证XML正确性 XML是个盒子,什么都能装,但是装进去的东西正确与否恐怕无法得知.往往我们都人工审核.双人复核保证,但是次数多了难免会出错.那么我们如何保证和避免这种问题出现呢? 那就是XSD, ...

  5. video标签视频指定帧作为预览图

    <video :src="videoUrl" :poster=" videoUrl + '?x-oss-process=video/snapshot,t_0,f_j ...

  6. LeetCode 贪心篇(455、55)

    455. 分发饼干 假设你是一位很棒的家长,想要给你的孩子们一些小饼干.但是,每个孩子最多只能给一块饼干.对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸:并且每块饼干 ...

  7. 如何快速部署本地训练的 Bert-VITS2 语音模型到 Hugging Face

    Hugging Face是一个机器学习(ML)和数据科学平台和社区,帮助用户构建.部署和训练机器学习模型.它提供基础设施,用于在实时应用中演示.运行和部署人工智能(AI).用户还可以浏览其他用户上传的 ...

  8. Java 插入Excel页眉、页脚

    前言 在Excel文档中,我们常用页眉页脚来显示文档的附加信息,例如日期.公司名称.Logo或作者信息等.本文将通过Java程序来介绍如何给Excel文档添加页眉页脚.代码示例主要从以下几方面来演示添 ...

  9. 华为云CCE集群健康中心:一个有专家运维经验的云原生可观测平台

    本文分享自华为云社区<新一代云原生可观测平台之华为云CCE集群健康中心>,作者:云容器大未来. "Kubernetes运维确实复杂,这不仅需要深入理解各种概念.原理和最佳实践,还 ...

  10. 如何正确使用Python临时文件

    摘要:临时文件通常用来保存无法保存在内存中的数据,或者传递给必须从文件读取的外部程序.一般我们会在/tmp目录下生成唯一的文件名,但是安全的创建临时文件并不是那么简单,需要遵守许多规则. 1.前言 临 ...