摘要:本文会给大家介绍下LiteOS Studio的镜像分析工具,这可是一个评估、优化镜像文件RAM、ROM占用大小的利器。

大家都知道嵌入式开发板由于受成本限制,芯片的RAM、Flash等硬件资源有限,比如有些低成本的开发板只有内置的64KB ROM、20KB RAM。在丰富功能特性编程时,一些看似无害的改变,都可能导致编译出的镜像膨胀,超出开发板的资源限制。对于硬件资源相对宽裕的开发板,合理的镜像大小规划,也会提升性能。本文会给大家介绍下LiteOS Studio的镜像分析工具,这可是个评估、优化镜像文件RAM、ROM占用大小的利器。

开发环境准备

前期的系列文章,我们掌握了如何安装LiteOS Studio,如何新建STM32F769IDISCOVERY和Qemu realview-pbx-a9工程。这次我们以STM32F429IGTx开发板为例,创建工程的方式是一样的,开发板选择STM32F429IGTx即可。镜像分析特性对任何LiteOS工程都是适用的,我们只是以该开发板为例。工程创建完毕后,执行编译,输出如下:

终端控制台输出显示编译成功了,可执行文件Huawei_LiteOS.elf对应的text段为74774 bytes,data段大小1444 bytes,bss段13080 bytes,dec表示前面三段大小的合计,为89268bytes。这些text、data、bss数据代表什么?有什么意义?我们继续,后文中会详细解释。

LiteOS 镜像分析特性

点击LiteOS Studio工具栏的调测工具Debug Tools按钮,打开调试工具,选择镜像分析,这就是本文要给大家介绍的LiteOS Studio的镜像分析工具。填写可执行文件路径、Map文件路径等,如图:

点击确定按钮,会自动打开镜像分析窗口。包含内存区域、详细信息、文件大小、模块大小等4个选项卡。我们依次演示如何使用。

  • 内存区域

内存区域页面评估分析LiteOS开发板工程对内存的细分使用情况。对于STM32F429IGTx开发板,显示的内存区域region包含FLASH、RAM、CCMRAM,展示的信息包含每个内存区域的名称、起始内存地址、总大小、空闲大小、已用大小,使用比例。在这个内存区域页面,除了数值展示分析,还提供饼图可以宏观的评估每个区域的使用、剩余情况。如下图所示,FLASH总大小 1024Kb,RAM总大小192Kb,对FLASH、RAM的使用率较低,刚刚超7%。对于CCMRAM更是没有使用,CCM(Core Coupled Memory)是给STM32F4内核专用的全速64KB RAM。

  • 详细信息

继续点击详细信息选项卡打开镜像分析详细信息页面,该页面展示每个内存区域包含的内存段section,内存段包含的符号symbol的详细信息。 比如FLASH下面包含.isr_vector、.text、.rodata等内存段, 内存段又包含分配在该段的程序符号。每一行展示的信息包含运行地址VMA(Virtual Memory Address)、装载地址LMA(Load Memory Address)、内存段/符号的大小。其中,LMA表示程序装载的内存地址;VMA表示程序运行时的内存地址。嵌入式系统中RAM内存空间有限,一般把程序放在FLASH中,LMA地址为Flash中的地址,等到程序运行时,再载入到RAM中的运行地址VMA。内存段.data、.vector_ram就属于这种情况,VMA、LMA地址不一样,并且在FLASH、RAM均出现。

在使用详情页面,支持排序和搜索过滤,支持程序符号快速跳转到源代码行。我们可以很直观的评估每个内存段、程序符号的使用大小情况,可以快速定位到潜在可优化的资源消耗大户。
如图:

从镜像分析图表中,可以看出text、data段存放在Flash存储,data、bss段数据存放在RAM存储。那么,链接器linker是怎么知道如何把各个段的符号数据存放在ROM、RAM的?这就要靠链接脚本。

链接脚本和Text、Data、BSS Section段

链接脚本包含一些规则来约束链接器如何把函数、变量放到ROM或RAM,STM32F429IGTx工程的链接脚本位置在targets\Cloud_STM32F429IGTx_FIRE\liteos.ld。我们分栏同时展示镜像分析页面和链接脚本,如下图,可以看出镜像分析页面展示的内存段使用情况和链接脚本中所定义的是一致的,开发板的内存使用情况在LiteOS Studio 镜像分析页面得到非常直观的展示。

内存段.ccmram在链接脚本中没有定义,已使用大小的也为0 byte。对于内存段.data、.vector_ram,链接脚本中使用关键字 RAM AT> FLASH,来表示装载地址、实际运行地址分别在FLASH、RAM。

链接脚本片段1如下,定义了中断处理向量.isr_vector、程序.text存放在Flash存储,使用的关键字为>FLASH,其中FLASH在上文的MEMORY{......}中定义。

  /* The startup code goes first into FLASH */.isr_vector :{. = ALIGN(4);KEEP(*(.isr_vector)) /* Startup code */. = ALIGN(4);} >FLASH/* The program code and other data goes into FLASH */.text :{. = ALIGN(4);__text_start = .;*(.text)           /* .text sections (code) */*(.text*)          /* .text* sections (code) */*(.glue_7)         /* glue arm to thumb code */*(.glue_7t)        /* glue thumb to arm code */*(.eh_frame)KEEP (*(.init))KEEP (*(.fini)). = ALIGN(4);_etext = .;        /* define a global symbols at end of code */__text_end = _etext;} >FLASH

链接脚本片段2如下,定义了.vector_ram、.data存放在Flash存储,在程序启动时,会从Flash复制到RAM。使用的关键字为 >RAM AT> FLASH,其中RAM在上文的MEMORY{}中定义。

 /* Initialized liteos vector sections goes into RAM, load LMA copy after code */.vector_ram :{. = ORIGIN(RAM);_s_liteos_vector = .;*(.data.vector)    /* liteos vector in ram */_e_liteos_vector = .;} > RAM AT> FLASH/* used by the startup to initialize data */_sidata = LOADADDR(.data);/* Initialized data sections goes into RAM, load LMA copy after code */.data ALIGN(0x1000):{__ram_data_start = _sdata;. = ALIGN(4);_sdata = .;        /* create a global symbol at data start */*(.data)           /* .data sections */*(.data*)          /* .data* sections */KEEP(*( SORT (.liteos.table.*)));. = ALIGN(4);_edata = .;        /* define a global symbol at data end */__ram_data_end = _edata;} >RAM AT> FLASH

链接脚本片段3如下,定义了.bss、._user_heap_stack占用RAM存储。使用的关键字为 >RAM。

  .bss :{/* This is used by the startup in order to initialize the .bss secion */_sbss = .;         /* define a global symbol at bss start */__bss_start__ = _sbss;__bss_start = _sbss;*(.bss)*(.bss*)*(COMMON). = ALIGN(4);_ebss = .;         /* define a global symbol at bss end */__bss_end__ = _ebss;__bss_end = _ebss;} >RAM/* User_heap_stack section, used to check that there is enough RAM left */._user_heap_stack :{. = ALIGN(8);PROVIDE ( end = . );PROVIDE ( _end = . );. = . + _Min_Heap_Size;. = . + _Min_Stack_Size;. = ALIGN(8);} >RAM

现在来总结一下,通常是这样的:

  • Text段

Text存储在只读的ROM内存区域,包含向量表、程序代码、只读常量数据。

  • Data段

表示初始化过的变量。存储在FLASH、RAM。链接器分配data段数据在Flash区域,在startup启动时,从ROM中复制到RAM。ROM中保存的是只读的副本,开发板重启也不会改变;RAM中保存的是读写副本,在程序运行过程中,变量值可能会变化。

  • BSS段

表示未初始化的变量。RAM中未初始化的数据,在程序启动时初始化为0。

  • 其他内存段

.user_heap_stack内存堆,malloc()申请内存使用此区域;.ARM.attributes、.debug_frame等存储调试信息。

Map映射文件、ASM反汇编文件

在程序编译链接时需要指定链接脚本,编译成功后会生成map映射文件,保存程序、数据的内存映射信息。映射文件是比较重要的辅助分析文件,可以获取程序中的函数、变量如何分配到RAM、ROM。在使用镜像分析功能的时候,我们指定了Map映射文件out\Cloud_STM32F429IGTx_FIRE\Huawei_LiteOS.map。反汇编文件是另外一个比较重要的文件,如果一个函数占用了太多的text代码段、data数据段时,此时可以分析反汇编代码。
利用镜像分析特性结合反汇编文件,我们很方便评估函数是否可以进一步优化改进。以main函数为例,在映射文件中的片段如下, main函数的存放地址为0x08000ea0,函数占用空间大小0x38 bytes(=56 bytes)。

 .text.startup.main0x08000ea0       0x38 d:/LiteOS_master/out/Cloud_STM32F429IGTx_FIRE/lib\libCloud_STM32F429IGTx_FIRE.a(main.o)0x08000ea0                main

这个数据在LiteOS Studio镜像分析页面也可以快速查阅到:

下面是main()函数反汇编片段。可以看出,我们是C代码和反汇编混合展示的。第一列8000ea0是地址,第二列是汇编指令的机器码、然后是汇编代码。
函数开始地址为0x8000ea0,结束地址为0x8000ed4,函数占用空间大小=0x8000ed4-0x8000ea0+0x4=0x38 bytes。如果函数长度过长,结合分析反汇编代码行,进行定位优化。

08000ea0 <main>:
main():
d:\LiteOS_master\targets\Cloud_STM32F429IGTx_FIRE/Src/main.c:45INT32 main(VOID)
{8000ea0:    b598          push    {r3, r4, r7, lr}8000ea2:    af00          add    r7, sp, #0
d:\LiteOS_master\targets\Cloud_STM32F429IGTx_FIRE/Src/main.c:46HardwareInit();8000ea4:    f7ff ffea     bl    8000e7c <HardwareInit>
d:\LiteOS_master\targets\Cloud_STM32F429IGTx_FIRE/Src/main.c:48PRINT_RELEASE("\n********Hello Huawei LiteOS********\n"8000ea8:    4b07          ldr    r3, [pc, #28]    ; (8000ec8 <main+0x28>)8000eaa:    4a08          ldr    r2, [pc, #32]    ; (8000ecc <main+0x2c>)8000eac:    4908          ldr    r1, [pc, #32]    ; (8000ed0 <main+0x30>)8000eae:    4809          ldr    r0, [pc, #36]    ; (8000ed4 <main+0x34>)8000eb0:    f000 fb84     bl    80015bc <dprintf>
d:\LiteOS_master\targets\Cloud_STM32F429IGTx_FIRE/Src/main.c:54"\nLiteOS Kernel Version : %s\n""build data : %s %s\n\n""**********************************\n",HW_LITEOS_KERNEL_VERSION_STRING, __DATE__, __TIME__);UINT32 ret = OsMain();8000eb4:    f003 fd18     bl    80048e8 <OsMain>
d:\LiteOS_master\targets\Cloud_STM32F429IGTx_FIRE/Src/main.c:55if (ret != LOS_OK) {8000eb8:    b108          cbz    r0, 8000ebe <main+0x1e>
d:\LiteOS_master\targets\Cloud_STM32F429IGTx_FIRE/Src/main.c:56return LOS_NOK;8000eba:    2001          movs    r0, #1
d:\LiteOS_master\targets\Cloud_STM32F429IGTx_FIRE/Src/main.c:62}OsStart();return 0;
}8000ebc:    bd98          pop    {r3, r4, r7, pc}8000ebe:    4604          mov    r4, r0

动手试验时间

我们动手编码创建些不同类型的变量、函数,看看这些会分配到哪些内存段,实际分配是否符合我们已掌握的知识。增加下述代码片段到targets\Cloud_STM32F429IGTx_FIRE\Src\user_task.c文件中的函数UINT32 app_init(VOID)的上方,在该UINT32 app_init(VOID)函数内首行增加对 ABC_FunName(0);的调用。

static UINT32 ABC_static_global_init = 1;UINT32 ABC_global_init = 1;UINT32 ABC_global_noInit;const UINT32 ABC_global_const = 1;static VOID ABC_Static_FunName(VOID){printf("ABC_static_global_init is %d.\n", ABC_static_global_init);printf("ABC_global_init is %d.\n", ABC_global_init);printf("ABC_global_noInit is %d.\n", ABC_global_noInit);printf("ABC_global_const is %d.\n", ABC_global_const);
}UINT32 ABC_FunName(UINT32 ABC_num){CHAR *ABC_var_inFun = "1234567890";UINT32 ABC_var_inFuc_init = 1;static UINT32 ABC_static_InFuc_init = 1;static UINT32 ABC_static_InFuc_noinit;const UINT32 ABC_inFuc_const = 1;ABC_static_InFuc_noinit = 99;printf("ABC_var_inFuc_init is %d.\n", ABC_var_inFuc_init);printf("ABC_static_InFuc_init is %d.\n", ABC_static_InFuc_init);printf("ABC_static_InFuc_noinit is %d.\n", ABC_static_InFuc_noinit);printf("ABC_inFuc_const is %d.\n", ABC_inFuc_const);CHAR *buf = LOS_MemAlloc(m_aucSysMem0, 8);buf[0] = ABC_var_inFun[0];LOS_MemFree(m_aucSysMem0, buf);(VOID)ABC_Static_FunName();return 0;}

重新编译,点击镜像分析页面的刷新按钮重新展示。我们新增的符号都以ABC_开头,我们以这个关键字搜索一下,可以看出来,ABC_FunName函数属于.text代码段,全局初始化的变量ABC_global_init属于.data段,全局未初始化变量ABC_global_noInit属于.bss段。静态函数ABC_Static_FunName、函数栈没有在这个区域展示。这符合我们已掌握的知识,如下图,大家也可以自行尝试一下。

本文介绍了嵌入式开发中的内存布局、链接脚本,映射文件,通过实例演示了如何利用LiteOS Studio的镜像分析特性,如何结合反汇编文件来评估函数空间占用。 LiteOS Studio是我们LiteOS物联网开发的利器!欢迎大家去使用这个特性,并分享使用心得,有任何问题、建议,都可以留言给我们https://gitee.com/LiteOS/LiteOS_Studio/issues。谢谢。

本文分享自华为云社区《使用LiteOS Studio镜像分析工具评估优化LiteOS镜像 》,原文作者:zhushy 。

点击关注,第一时间了解华为云新鲜技术~

用了这个评估优化LiteOS镜像利器,我有点飘...相关推荐

  1. terminal看服务器性能,终端服务服务器性能评估优化问题

    终端服务服务器性能评估优化计算问题terminal server performance:现有50客户端需要访问总部ERP,财务等资源,这些都是在一台服务器上.线路已经准备好,4M光纤. 但对于终端服 ...

  2. 优化Docker镜像大小方案 2017年12月10日 17:54:46 阅读数:1774 标

    2019独角兽企业重金招聘Python工程师标准>>> 优化Docker镜像大小方案 2017年12月10日 17:54:46 阅读数:1774 标签: Docker 更多 个人分类 ...

  3. 精简压缩优化 Docker 镜像几百MB

    转载:http://www.dockerinfo.net/3328.html 介绍 前段时间网易蜂巢曾经推出蜂巢 Logo T恤,用的正是 Docker 镜像制作,最神奇的是,它最终的镜像大小只有 5 ...

  4. python函数测试_python绘制评估优化算法性能的测试函数

    测试函数主要是用来评估优化算法特性的,这里我用python3绘制了部分测试函数的图像.具体的测试函数可以结合维基百科来了解.想要显示某个测试函数的图片把代码结尾对应的注释去掉即可,具体代码如下: im ...

  5. Docker基础镜像操作系统基础镜像对比(参考官方文档),优化docker镜像

    目录: 一. 选择Docker基础镜像 操作系统基础镜像 1. busybox 2. Alpine 3. CentOS 4. Ubuntu 5. Debian 二.编程语言基础镜像 应用基础镜像 其它 ...

  6. python评估函数_python绘制评估优化算法性能的测试函数

    测试函数主要是用来评估优化算法特性的,这里我用python3绘制了部分测试函数的图像.具体的测试函数可以结合维基百科来了解.想要显示某个测试函数的图片把代码结尾对应的注释去掉即可,具体代码如下: im ...

  7. jvm优化_镜像镜像–使用反射在运行时查看JVM内部

    jvm优化 开发人员:Takipi会告诉您何时新代码在生产中中断–了解更多 我们都习惯于在我们的日常工作中直接或通过利用反射的框架来运用反射. 它是Java和Scala编程的主要方面,它使我们使用的库 ...

  8. 四国军棋引擎开发(10)局面评估优化

    这次对局面评估做了一些优化,棋力有了一些提升,可以定为2.1版本,测试结果如下: 引擎A vs 引擎B 战绩(胜:负:和) 1.1 vs 1.0 8:2:0 1.2 vs 1.1 8:2:0 1.2 ...

  9. 【机器学习】Facets:评估机器学习数据集质量利器 (来自Google、可交互、可可视化)...

    好的数据集质量,决定后续模型的上限 (Better data leads to better models),那么怎么快速评估数据集的质量了? 本文分享的Facets,是一款由Google开源.快速评 ...

最新文章

  1. 第1章 Java语言概述
  2. Windows Server 2016之RDS部署之添加RD网关
  3. 禁用viewstate怎么还保存状态?
  4. Extjs4中up()和down()的用法以及组件查找_ComponentQuery类
  5. manually set focus for tag library
  6. 使用 C# 编程对RTF文档的支持
  7. 推荐系统知识梳理——GBDTLR
  8. 工程师软技能4:找出你的短板
  9. YUM源安装,FTP安装
  10. linux du命令参数及用法详解---linux统计磁盘空间大小命令
  11. python象棋编程_Python开发象棋小游戏(绘制棋盘)
  12. 中文词性标注的简单实现
  13. ZT 王国维先生“人生三大境界”的具体含义是什么?
  14. java阅读安卓_基于安卓Android的图书阅读与推荐系统APP的设计
  15. 如何记住OSI七层协议模型,脑洞大开有木有?
  16. GTX960M搭建《深度学习图像识别技术》所需的环境
  17. android xml 平铺,Android 图片平铺实现方式
  18. 量产 php是什么,最新的量产工具
  19. 【ZZULIOJ】1056: 幸运数字
  20. 【VBA研究】再论取EXCEL有效行列数方法

热门文章

  1. 会议报到和撒离时间算会期_【NKMUN2021】城市会议新模式:让心动成为可能
  2. matlab在activex中读取视频,[转载]matlab读取excel数据并显示在excel(activex控件)中
  3. 若依的框架怎么样_若依框架的功能代码
  4. 剑指offer 第1题
  5. 牛客寒假算法基础集训营2 处女座的测验(一) (数论+构造)
  6. 请求报文的方法及get与post的区别
  7. git与github学习笔记
  8. hibernate之一对一
  9. webpack自定义打包命令
  10. Esfog_UnityShader教程_NormalMap法线贴图