当前文档版本为v0.3.0,您可以访问 开发中 的文档以获取最近可能的更新。

Zephyr RAM 使用情况分析指南

此文档记录Bluetooth项目中,通用的资源调试分析步骤

mesh_panchip类似的sample,不同需求产生不同配置需求,在资源有限的前提下,需要根据实际占用资源对资源分配情况进行分析和规划

主要包括以下两部分

  • 分析编译占用RAM资源

    • 通过分析工具,观察宏观占用的资源情况,其中比较大的是线程栈的分配

    • 通过分析工具,观察细节资源占用情况,主要是不同Feature开启时,会占用零星的一些资源

  • 优化RAM资源

    • 通过代码内开启栈实时调用情况打印的接口,运行多种case,保证不溢出情况下的最小栈分配

    • 通过分析不同feature占用的资源,根据需求,裁剪feature或者在了解功能需求情况下,缩小feature内的变量大小

1 分析编译占用RAM资源

使用VSCode打开工程,ctrl+shift+B运行build命令后后,TERMINAL内显示资源总体占用情况,Memory region可以看到整体占用的Flash,SRAM,IDT_LIST,例如mesh_panchip

   Memory region      Used Size  Region Size  %age Used
           FLASH:      348352 B      1020 KB     33.35%
            SRAM:       49585 B        64 KB     75.66%
        IDT_LIST:          0 GB         2 KB      0.00%

其中SRAM包含

  • Controller RAM Code

  • RAM report工具所分析的SRAM资源

1.1 Controller RAM Code

可以通过bulid 工程目录下zephyr/zephyr.map文件确认具体RAM占用情况

搜索ramfunc即可,例如mesh_panchip内,Controller RAM Code占用资源在zephyr.map文件中显示如下:

 *(SORT_BY_ALIGNMENT(.ramfunc.*))
                0x200017c0                . = ALIGN (_region_min_align)
                0x200017c0                __ramfunc_end = .
                0x000017c0                __ramfunc_size = (__ramfunc_end - __ramfunc_start)
                0x00052aac                __ramfunc_load_start = LOADADDR (.ramfunc)

1.2 RAM report工具所分析的SRAM资源

使用VSCode打开工程,ctrl+shift+B运行RAM Report命令后后,TERMINAL内显示资源具体占用情况,通常包含以下几部分,根资源包含以下几部分:

其中数据内容满足以下公式, 字母小写同理 $$ X = A + B + C + D $$

$$ D = D1+ D2 + D3 +D4 + D5 $$

$$ D5 = D51+ D52 + D53 + D54 + D55 $$

Path                                                                                             Size    %
==============================================================================================================
Root                                                                                            X    100.00%
├── (hidden)                                                                                    A         a%
├── (no paths)                                                                                  B         b%
├── WORKSPACE                                                                                   C         c%
└── ZEPHYR_BASE                                                                                 D         d%
  └── driver                                                                                    D1       d1%
  └── kernel                                                                                    D2       d2%
  └── lib                                                                                       D3       d3%
  └── sample                                                                                    D4       d4%
  └── subsys                                                                                    D5       d5%
    └── controller_panchip                                                                      D52     d51%
    └── host                                                                                    D53     d52%
    └── mesh                                                                                    D54     d53%
    └── logging                                                                                 D55     d54%
    └── setting                                                                                 D56     d55%
    └── storage                                                                                 D57     d56%

==============================================================================================================
                                                                                                X

分析RAM report的内容如下

  • ROOT:SRAM 总大小 对应占比100%

  • (hidden) :隐藏RAM大小,通常不大

  • (no paths):包含zephyr未追溯到的RAM资源大小

  • WORKSPACE:ble controller占用资源大小

  • ZEPHYR_BASE:zephyr资源占用大小,通常包括以下及部分

    • driver:driver占用的资源,通常与外设选择有关

    • kernel:主要是栈分配,主要包含z_main_stack

    • lib: 外部调用库,通常包含std.lib等

    • sample:sample应用占用RAM,自己开发项目时管理

    • subsys

      • controller_panchip: controller 层级占用的SRAM,主要包含hci tx/rx stack

      • host: host层级占用的SRAM,主要包含tx_thread_stack , ecc_thread_stack etc.

      • mesh: mesh层级占用的SRAM,主要包含adv_thread_stack

      • logging: logging占用的资源,不需要zephyr 内的log系统可以关闭

      • setting:setting占用的资源,通常很小,管理nvs机制等的接口

      • storage:storage占用的资源,通常很小,管理存储接口

2 优化RAM资源

优化RAM资源分为两个方向:

  • 通过代码内开启栈实时调用情况打印的接口,运行多种case,保证不溢出情况下的最小栈分配

  • 通过分析不同feature占用的资源,根据需求,裁剪feature或者在了解功能需求情况下,缩小feature内的变量大小

2.1 栈分配大小优化

栈分配大小优化时,需要以下步骤

  • 确认使用栈的个数和大小

  • 根据调试栈的代码使能,挂起测试多功能运行时,使用到的最大栈资源,并以此为据,在保证栈不溢出的情况下缩减栈资源

2.1.1 确认使用栈的个数和大小

由上述RAM Report工具,可以看到stack分配的个数和大小,并且可以通过工程编译目录下zephyr\include\generated\autoconf.h双重确认

2.1.2 调试栈打印宏

CONFIG_THREAD_NAME=y
CONFIG_THREAD_ANALYZER=y
CONFIG_THREAD_ANALYZER_AUTO=y
CONFIG_THREAD_ANALYZER_RUN_UNLOCKED=y
CONFIG_THREAD_ANALYZER_USE_PRINTK=y
CONFIG_THREAD_ANALYZER_AUTO_INTERVAL=5
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_PRINTK=y

在sample prj.conf内增加开启以上宏后,可以每CONFIG_THREAD_ANALYZER_AUTO_INTERVAL的时间,打印出STACK占用累计的最大值

测试时,运行尽量多的功能,保持尽量长的时间,来确认线程中最大栈资源分配

并且还可以打印CPU使用率,来观测线程运行的频繁程度

注意:栈打印功能本身也会占用一定资源,栈分配时需要8B对齐

打印示例(最大栈运行没问题后,通常保持在分配最大栈的80~90%比较合理):

BT Mesh adv         : STACK: unused 164 usage 860 / 1024 (83 %); CPU: 0 %
BT RX               : STACK: unused 1308 usage 1764 / 3072 (57 %); CPU: 1 %
BT CTLR             : STACK: unused 1420 usage 628 / 2048 (30 %); CPU: 7 %
BT ECC              : STACK: unused 212 usage 932 / 1144 (81 %); CPU: 0 %
BT TX               : STACK: unused 1036 usage 1012 / 2048 (49 %); CPU: 0 %
thread_analyzer     : STACK: unused 556 usage 468 / 1024 (45 %); CPU: 0 %
sysworkq            : STACK: unused 1200 usage 848 / 2048 (41 %); CPU: 0 %
logging             : STACK: unused 236 usage 532 / 768 (69 %); CPU: 0 %
idle 00             : STACK: unused 972 usage 52 / 1024 (5 %); CPU: 89 %

栈大小具有底层默认值,配置修改时,需要在prj.conf内修改,如mesh_pacnhip sample中示例

#           main stack
CONFIG_MAIN_STACK_SIZE=1024
#           isr stack
CONFIG_ISR_STACK_SIZE=2048
#           idle 00
CONFIG_IDLE_STACK_SIZE=128
#           sysworkq
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1024
#           BT ECC
CONFIG_BT_HCI_ECC_STACK_SIZE=1024
#           BT TX
CONFIG_BT_HCI_TX_STACK_SIZE_WITH_PROMPT=y
CONFIG_BT_HCI_TX_STACK_SIZE=1024
#           BT RX
CONFIG_BT_RX_STACK_SIZE=2048
#           BT CTLR
CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=1024
#           BT Mesh adv
CONFIG_BT_MESH_ADV_STACK_SIZE=1024
#           logging
CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=768
#           thread_analyzer
CONFIG_THREAD_ANALYZER_AUTO_STACK_SIZE=512

需要注意:修改tx stack需要按以下方式,需要开启CONFIG_BT_HCI_TX_STACK_SIZE_WITH_PROMPT

CONFIG_BT_HCI_TX_STACK_SIZE_WITH_PROMPT=y
CONFIG_BT_HCI_TX_STACK_SIZE=1024

2.2 裁剪或减少Feature资源

通过上述RAM report分析后,可以观察到部分模块,也就是对应的feature,会零星得占用RAM资源,这些资源是我们可以按照需求进行调整的,以减小资源占用

  • 当某些模块在某些需求内不需要时,可以进行关闭,如Mesh Friend Feature在目前音箱中不需要则可以进行关闭

  • 当某些模块在某些需求内,通过较小的数组就可以满足需求时,可以缩小数组变量的大小,如Mesh Remote Feature/Provisioner 扫描到得设备数量,减少一个便可以减少16字节的UUID数组存储

2.2.1 分析工具

使用VSCode打开工程,ctrl+shift+B运行Menu Config命令后后,弹出Kconfig分析文件

关于Kconfig文件的原理,可以参考官方文档https://docs.zephyrproject.org/latest/guides/build/index.html?highlight=kconfig

Kconfig分析界面如下

图 Menu Config

2.2.2 裁剪规则

通过上述分析工具Menu Config,可以观察到,通常情况下,不同模块根据功能来区分,裁剪/缩小资源占用可以按照以下步骤

  • 找到对应Feature所处的总控制宏,可以对Feature进行关闭,对比开关造成的RAM资源不同关系

  • 某一feature下可以通过feature内的配置某些数组的大小来统计RAM资源细节调整

3 总结说明

经过上述内容细节观察调试,我们知道,当资源比较紧张时

首先可以根据分析工具,观察整体和各部分资源占用情况

宏观上可以对较大的栈进行内存分配管理,细节上可以根据需求来裁剪/缩小变量数组

最后,当我们编码时,同样需要宏观上为线程合理分配栈大小,并且尽量使用Kconfig来规划Feature的整体和细节,方便后续调优/规整代码