jjzjj

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

<font>痞子衡嵌入式 2023-03-28 原文

  大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是MCUXpresso IDE下设置代码编译优化等级的几种方法

  最近公司芯片设计团队正在开发一款全新的基于 Cortex-M33 内核的芯片,为了保证芯片性能达标,验证团队将 coremark 基准测试程序也当作了一个测试用例,而在 RTL 环境里指定的 C 编译器是标准 GCC,验证团队发现跑出来的 coremark 程序测试结果与 Arm 给的 Cortex-M33 参考值 4.02 CoreMark/MHz 有一定差距,痞子衡参与了这个问题调查。

  在 Arm Cortex-M33 官方主页,其备注了 4.02 CoreMark/MHz 参考值来自于 EEMBC 官网上的一款 恩智浦 LPC55S69JBD100 芯片跑出来的结果,页面里备注了跑分结果是在 Arm Clang Compiler v6.12 下开启最高优化等级 -Omax 下得到的,而验证团队用得是 GCC,痞子衡断定问题大概率是由不同编译器优化性能差异引起的,借着这个实际问题,今天痞子衡跟大家聊一聊 MCUXpresso IDE 下编译优化等级设置方法。

  • Note:本文使用的 MCUXpresso IDE 软件版本是 v11.6.0_8187。

一、查看MCUX下GCC版本

  有朋友可能会觉得奇怪,文章开头里明明聊得是 GCC 下 coremark 跑分问题,为何痞子衡引出了 MCUXpresso IDE?其实 MCUXpresso IDE 是恩智浦推出的免费集成开发环境,其底层编译器就是标准 GCC 工具链,使用 MCUXpresso IDE,我们就不用像使用 GCC 那样手动准备相应 Makefile 去做编译了。

  因为我们是借助 MCUXpresso IDE 来测试 GCC 编译优化性能,所以需要了解当前 GCC 版本,可以在 MCUXpresso IDE 安装目录如下路径下找到 GCC 版本信息。执行 arm-none-eabi-gcc.exe -v 命令即可知道其版本,MCUXpresso IDE v11.6 使用得是 GCC v10.3.1。

\MCUXpressoIDE_11.6.0_8187\ide\tools\bin\arm-none-eabi-gcc.exe
\MCUXpressoIDE_11.6.0_8187\ide\tools\lib\gcc\arm-none-eabi\10.3.1

二、GCC支持的优化等级

  既然咱们聊得是优化等级设置方法,首先我们得知道 GCC 下支持哪些优化等级,我们可以在 MCUXpresso IDE 安装目录或者 GCC 官网找到用户手册(gcc.pdf),手册里面 Section 3.11 Options that Control Optimization 章节有详细的解释。

\MCUXpressoIDE_11.6.0_8187\ide\tools\share\doc\gcc-arm-none-eabi\pdf\gcc.pdf
https://gcc.gnu.org/onlinedocs/gcc-10.3.0/gcc.pdf

  GCC 本身支持非常多的优化策略小项,大概有如下 100 多个,可以在手册里去看每个小项的具体解释,了解了这些小项,我们在编译时当然可以把这些策略参数按需加上去,不过这种方式显然比较繁琐。

  GCC 为了化繁为简,将这些策略小项做了分类整理,形成了如下 8 个等级(基于代码大小和运行速度两个方向逐步加档),我们在实际编译时一般直接用这 8 个优化等级即可。

优化等级 策略解释
-O0 不进行任何优化(如果没有指定优化级别,即为此默认设置)。
-O或者-O1 在不影响编译速度的前提下,尽量采用一些优化算法降低代码大小和提高可执行代码的运行速度。
-此等级执行了 45 个策略小项。
-O2 牺牲部分编译速度,采用几乎所有的目标配置支持的优化算法,用以提高目标代码的运行速度。
-此等级在-O1所有优化策略小项之上增加了 48 个策略小项。
-O3 采取很多向量化算法,提高代码的并行执行程度,比如利用现代CPU中的流水线,Cache等,目标是宁愿增加目标代码的大小,也要拼命的提高运行速度。
-此等级在-O2所有优化策略小项之上增加了 16 个策略小项。
-Os 与-O3有异曲同工之妙,但两者的目标不一样,这个等级是为了尽量的降低目标代码的大小,这对于存储容量很小的设备来说非常重要。
-此等级在-O2所有优化策略小项之上减掉了 6 个策略小项,然后使能了 -finline-functions 策略。
-Ofast 不会严格遵循语言标准,会针对某些语言启用部分优化,以达到最快的运行速度。
-此等级在-O3所有优化策略小项之上增加了 -ffast-math 和 -fallow-store-data-races 策略。
-Og 在保持快速编译和良好调试体验的同时,提供合理的优化级别。
-Oz 比-Os更激进的去降低目标代码的大小,GCC v12.x 之后的版本才引入。

三、MCUX下设置优化等级的三种方法

  在 MCUXpresso IDE 工程里,我们有三种方法来设置优化等级,分别针对单个函数、单个源文件、整个工程源文件。

3.1 在源文件中设置

  第一种优化等级设置方法主要针对单个函数,即使用 __attribute__ 来修饰函数(这其实是 GCC 下通用做法,与 MCUX 关系不大),经过修饰的函数可以不受 MCUXpresso IDE 工程整体优化等级设置影响。

void __attribute__((optimize("O3"))) function(void)
{
    ...
}

  第二种优化等级设置方法主要针对多个相邻函数或者整个源文件,即使用如下 #pragma 组合语句来修饰代码(这也是 GCC 下通用做法,与 MCUX 关系不大),经过修饰的代码也同样不受 MCUXpresso IDE 工程整体优化等级设置影响。

#pragma GCC push_options     // 代码作用范围起始处
#pragma GCC optimize("O3")   // 代码优化等级设置
void function1(void)
{
    ...
}
void function2(void)
{
    ...
}
...
#pragma GCC pop_options      // 代码作用范围结尾处

3.2 在IDE选项中设置

  第三种优化等级设置方法主要针对工程全部源文件,即在 MCUXpresso IDE 工程选项里 Optimization Level 一栏项目里做切换选择,这里基本上与 GCC v10.3 优化等级定义是一致的,但是缺少了 -Ofast 选项。

四、MCUX下设置-Ofast等级

  痞子衡找了一块 MIMXRT595-EVK 开发板(主芯片为 Cortex-M33 内核),在其配套 SDK 里的 hello world 工程基础之上移植了 coremark 程序,在 IAR v9.10 最高优化等级下(High-Speed, No size constraints)得到了 3.94 CoreMark/MHz 的跑分,这很接近 Arm 基准值,但是在 MCUXpresso IDE 最高优化等级下(-O3)仅得到了 2.76 CoreMark/MHz。

  莫非是必须要在 MCUXpresso IDE 下开启 GCC 的最快运行优化等级 -Ofast 才能得到理想 coremark 跑分,但是 MCUXpresso IDE 选项里并没有 -Ofast 怎么办?别着急,刚才工程选项下还有 Other optimization flags 后门,我们在这里手动添加上 -Ofast 比 -O3 多的那两个优化策略小项,以及 MCUX 团队要求的 -fno-semantic-interposition 小项,这样基本就等于 - Ofast 效果。

-ffast-math -fallow-store-data-races -fno-semantic-interposition

  重新编译,再跑一次 -Ofast 等级下的 MCUXpresso IDE 工程,发现 coremark 跑分结果并没有比 -O3 等级下有多大提升,想了想虽然跑不到 IAR 上 3.94 CoreMark/MHz 的高分有点不甘心,但是这也很正常嘛,免费的 GCC 编译器如果能达到商业 IAR 编译器那样的效果,那人家商业编译器还怎么收费呢,理解万岁!

  至此,MCUXpresso IDE下设置代码编译优化等级的几种方法痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到我的 博客园主页CSDN主页知乎主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

有关痞子衡嵌入式:MCUXpresso IDE下设置代码编译优化等级的几种方法的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  5. Ruby 方法() 方法 - 2

    我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

  6. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  7. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  8. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  9. ruby - Highline 询问方法不会使用同一行 - 2

    设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案

  10. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

随机推荐