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分析界面如下:
2.2.2 裁剪规则¶
通过上述分析工具Menu Config
,可以观察到,通常情况下,不同模块根据功能来区分,裁剪/缩小资源占用可以按照以下步骤
找到对应Feature所处的总控制宏,可以对Feature进行关闭,对比开关造成的RAM资源不同关系
某一feature下可以通过feature内的配置某些数组的大小来统计RAM资源细节调整
3 总结说明¶
经过上述内容细节观察调试,我们知道,当资源比较紧张时
首先可以根据分析工具,观察整体和各部分资源占用情况
宏观上可以对较大的栈进行内存分配管理,细节上可以根据需求来裁剪/缩小变量数组
最后,当我们编码时,同样需要宏观上为线程合理分配栈大小,并且尽量使用Kconfig来规划Feature的整体和细节,方便后续调优/规整代码