MCU作为一种集成了处理器、存储器和外设接口等功能的微控制器,其资源包括存储器、计算能力、输入输出端口等。然而,大多数MCU的资源都是有限的,特别是在一些资源受限的应用中,如小型便携设备或低功耗系统。在这些情况下,优化占用空间变得至关重要,以确保系统的性能、功能和可靠性,同时最大限度地减少资源的使用。Zephyr提供了一系列工具用于分析Zephyr镜像占用的Flash和内存大小,主要涵盖的是在编译期可确定的占用存储大小:

  • RAM占用:数据段和BSS段
  • ROM占用:代码段和只读内容
  • 函数堆栈占用

本文的所有示例都基于mm_feather的shell示例进行展示,首先进行目标进行编译

west init -m https://github.com/zephyrproject-rtos/zephyr --mr v3.4.0 zephyr_v3.4.0
cd zephyr_v3.4.0
west build -b mm_feather zephyr/samples/subsys/shell/shell_module/

ram_report 链接到标题

这是zephyr构建系统自带的一个工具,在构建镜像完成后执行下面命令

west build -t ram_report

结果将以树形列出所有已编译对象及其 RAM 使用情况,其中包含每个符号的字节数及其使用的百分比。通过对这些数据的查看和分析找到哪些模块在大量占用RAM,并进行针对性的修改

Path                                                                                             Size    %
==============================================================================================================
Root                                                                                            14628 100.00%
├── (hidden)                                                                                        0   0.00%
├── (no paths)                                                                                   4138  28.29%
│   ├── _cpus_active                                                                                4   0.03%
│   ├── _kernel                                                                                    56   0.38%
│   ├── _sw_isr_table                                                                            1280   8.75%
│   ├── buf.0                                                                                       1   0.01%
│   ├── dynamic_regions.0                                                                          12   0.08%
│   ├── g_rtcXtalFreq                                                                               4   0.03%
│   ├── g_xtalFreq                                                                                  4   0.03%
│   ├── in_use.0                                                                                    2   0.01%
│   ├── k_sys_work_q                                                                              232   1.59%
│   ├── optreset                                                                                    4   0.03%
│   ├── shell_init_work.2                                                                          16   0.11%
│   ├── tail.1                                                                                      2   0.01%
│   ├── tx_busy.1                                                                                   1   0.01%
│   ├── wait_q.0                                                                                    8   0.05%
│   ├── z_idle_threads                                                                            200   1.37%
│   ├── z_interrupt_stacks                                                                       2112  14.44%
│   └── z_main_thread                                                                             200   1.37%
├── arch                                                                                            5   0.03%
│   └── arm                                                                                         5   0.03%
│       └── core                                                                                    5   0.03%
│           └── aarch32                                                                             5   0.03%
│               └── mpu                                                                             5   0.03%
│                   ├── arm_core_mpu.c                                                              4   0.03%
│                   │   └── log_dynamic_mpu                                                         4   0.03%
│                   └── arm_mpu.c                                                                   1   0.01%
│                       └── static_regions_num                                                      1   0.01%
├── drivers                                                                                       242   1.65%
│   ├── clock_control                                                                               6   0.04%
│   │   └── clock_control_mcux_ccm.c                                                                6   0.04%
│   │       ├── __devstate_dts_ord_53                                                               2   0.01%
│   │       └── log_dynamic_clock_control                                                           4   0.03%
│   ├── gpio                                                                                      126   0.86%
│   │   └── gpio_mcux_igpio.c                                                                     126   0.86%
│   │       ├── __devstate_dts_ord_124                                                              2   0.01%
│   │       ├── __devstate_dts_ord_157                                                              2   0.01%
│   │       ├── __devstate_dts_ord_190                                                              2   0.01%
│   │       ├── __devstate_dts_ord_219                                                              2   0.01%
│   │       ├── __devstate_dts_ord_252                                                              2   0.01%
│   │       ├── __devstate_dts_ord_326                                                              2   0.01%
│   │       ├── __devstate_dts_ord_45                                                               2   0.01%
│   │       ├── __devstate_dts_ord_62                                                               2   0.01%
│   │       ├── __devstate_dts_ord_91                                                               2   0.01%
│   │       ├── mcux_igpio_0_data                                                                  12   0.08%
│   │       ├── mcux_igpio_1_data                                                                  12   0.08%
│   │       ├── mcux_igpio_2_data                                                                  12   0.08%
│   │       ├── mcux_igpio_3_data                                                                  12   0.08%
│   │       ├── mcux_igpio_4_data                                                                  12   0.08%
│   │       ├── mcux_igpio_5_data                                                                  12   0.08%
│   │       ├── mcux_igpio_6_data                                                                  12   0.08%
│   │       ├── mcux_igpio_7_data                                                                  12   0.08%
│   │       └── mcux_igpio_8_data                                                                  12   0.08%
│   ├── serial                                                                                     94   0.64%
│   │   └── uart_mcux_lpuart.c                                                                     94   0.64%
│   │       ├── __devstate_dts_ord_283                                                              2   0.01%
│   │       ├── __devstate_dts_ord_284
└── subsys                                                                                       6816  46.60%
    ├── logging                                                                                  2254  15.41%
    │   ├── log_core.c                                                                           2242  15.33%
    │   │   ├── backend_attached                                                                    1   0.01%
    │   │   ├── buf32                                                                            1024   7.00%
    │   │   ├── buffered_cnt                                                                        4   0.03%
    │   │   ├── curr_log_buffer                                                                     4   0.03%
    │   │   ├── dropped_cnt                                                                         4   0.03%
    │   │   ├── initialized                                                                         4   0.03%
    │   │   ├── last_failure_report                                                                 8   0.05%

例如我们的硬件并没有使用gpio 4~8,而镜像分析结果含有mcux_igpio_4_data~mcux_igpio_8_data,那么我们可以通过设备树将其移除。 例如我们看到log_core.c的buf32占用RAM比较大,我们可以通过查看代码分析看是否可以适当缩小buf32

rom_report 链接到标题

这是zephyr构建系统自带的一个工具,在构建镜像完成后执行下面命令

west build -t rom_report

结果将以树形列出所有已编译对象及其 ROM 使用情况,其中包含每个符号的字节数及其使用的百分比。通过对这些数据的查看和分析找到哪些模块在大量占用ROM,并进行针对性的修改

Root                                                                                            75428 100.00%
├── (hidden)                                                                                    16305  21.62%
├── (no paths)                                                                                   2677   3.55%
│   ├── CSWTCH.483                                                                                 20   0.03%
│   ├── __aeabi_idiv0                                                                               2   0.00%
│   ├── __device_dts_ord_124                                                                       24   0.03%
│   ├── __device_dts_ord_157                                                                       24   0.03%
│   ├── __device_dts_ord_190                                                                       24   0.03%
│   ├── __device_dts_ord_219                                                                       24   0.03%
...
└── ZEPHYR_BASE                                                                                 54156  71.80%
    ├── arch                                                                                     3034   4.02%
    │   └── arm                                                                                  3034   4.02%
    │       └── core                                                                             3034   4.02%
    │           └── aarch32                                                                      3034   4.02%
    │               ├── cortex_m                                                                 1908   2.53%
    │               │   ├── fault.c                                                              1748   2.32%
    │               │   │   ├── bus_fault.constprop.0                                             396   0.53%
    │               │   │   ├── mem_manage_fault                                                  424   0.56%
    │               │   │   ├── usage_fault.constprop.0                                           308   0.41%
    │               │   │   ├── z_arm_fault                                                       604   0.80%
    │               │   │   └── z_arm_fault_init                                                   16   0.02%
    │               │   ├── irq_init.c                                                             24   0.03%
    │               │   │   └── z_arm_interrupt_init                                               24   0.03%
    │               │   ├── thread_abort.c                                                         44   0.06%
    │               │   │   └── z_impl_k_thread_abort                                              44   0.06%
    │               │   └── timing.c                                                               92   0.12%
    │               │       ├── arch_timing_counter_get                                            12   0.02%
    │               │       ├── arch_timing_init                                                   60   0.08%
    │               │       └── arch_timing_start                                                  20   0.03%
...
    ├── drivers                                                                                  8576  11.37%
    │   ├── clock_control                                                                         158   0.21%
    │   │   └── clock_control_mcux_ccm.c                                                          158   0.21%
    │   │       ├── __devstate_dts_ord_53                                                           2   0.00%
    │   │       ├── __init___device_dts_ord_53                                                      8   0.01%
    │   │       ├── log_const_clock_control                                                         8   0.01%
    │   │       ├── log_dynamic_clock_control                                                       4   0.01%
    │   │       ├── mcux_ccm_driver_api                                                            28   0.04%
    │   │       ├── mcux_ccm_get_subsys_rate                                                      104   0.14%
    │   │       └── mcux_ccm_on                                                                     4   0.01%
    │   ├── console                                                                                88   0.12%
    │   │   └── uart_console.c                                                                     88   0.12%
    │   │       ├── __init_uart_console_init                                                        8   0.01%
    │   │       ├── console_out                                                                    40   0.05%
    │   │       └── uart_console_init                                                              40   0.05%
    │   ├── gpio                                                                                 6124   8.12%
    │   │   └── gpio_mcux_igpio.c                                                                6124   8.12%
    │   │       ├── __devstate_dts_ord_124                                                          2   0.00%
    │   │       ├── __devstate_dts_ord_157                                                          2   0.00%
    │   │       ├── __devstate_dts_ord_190                                                          2   0.00%

通过对百分比可以找到哪些模块/符号占用空间大,再进行有针对性的优化

puncover 链接到标题

puncover是zephyr导入的一个第三方Python工具包,可以通过网页查看ROM,RAM和函数堆栈的使用情况,首先需要安装puncover

pip install git+https://github.com/HBehrens/puncover --user

如果要想在结果中看到函数堆栈的信息,需要在编译的时候开启CONFIG_STACK_USAGE=y

west build -b mm_feather zephyr/samples/subsys/shell/shell_module/  -- -DCONFIG_STACK_USAGE=y

安装完后执行

west build -t puncover

可以看到提示

parsing stack usages starting at /mnt/e/westz/zephyr_v3.4.0/build

  • Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

浏览器访问http://127.0.0.1:5000/,通过选择不同的链接可以看到每个函数的stack,code大小,可以看到静态数组的大小

问题处理 链接到标题

执行时会报错

Traceback (most recent call last): File “/home/frank/.local/bin/puncover”, line 8, in sys.exit(main()) File “/home/frank/.local/lib/python3.8/site-packages/puncover/puncover.py”, line 55, in main gcc_tools_base = os.path.join(find_arm_tools_location(), ‘bin/arm-none-eabi-’) File “/usr/lib/python3.8/posixpath.py”, line 76, in join a = os.fspath(a) TypeError: expected str, bytes or os.PathLike object, not NoneType

这是因为puncover依赖arm-none-eabi-objdump,需要将对应的工具链加入到环境变量

export PATH=/mnt/e/westz/gcc-arm-none-eabi-9-2020-q2-update/bin:$PATH

pahole 链接到标题

Poke-a-hole (pahole) 是一种目标文件分析工具,用于分析结构体的大小,以及由于编译器将数据元素与 CPU 字大小对齐而导致的漏洞。Zephyr通过导入dwarves来支持该分析,因此使用前需要先安装dwarves

sudo apt-get install dwarves

使用下面命令进行分析

west build -t pahole

可以得到类似下面的log

/* Used at: /mnt/e/westz/zephyr_v3.4.0/modules/hal/nxp/mcux/mcux-sdk/devices/MIMXRT1062/drivers/fsl_clock.c */
/* <7b728> /mnt/e/westz/zephyr_v3.4.0/modules/hal/nxp/mcux/mcux-sdk/devices/MIMXRT1062/drivers/fsl_clock.h:1261 */
struct _clock_video_pll_config {
	uint8_t                    loopDivider;          /*     0     1 */
	uint8_t                    postDivider;          /*     1     1 */

	/* XXX 2 bytes hole, try to pack */

	uint32_t                   numerator;            /*     4     4 */
	uint32_t                   denominator;          /*     8     4 */
	uint8_t                    src;                  /*    12     1 */

	/* size: 16, cachelines: 1, members: 5 */
	/* sum members: 11, holes: 1, sum holes: 2 */
	/* padding: 3 */
	/* last cacheline: 16 bytes */
};

含义说明

uint8_t loopDivider; /* 0 1 */

loopDivider在结构体struct _clock_video_pll_config中的偏移地址为0,占用内存为1字节

/* XXX 2 bytes hole, try to pack */

此处有2个字节的空洞

/* size: 16, cachelines: 1, members: 5 */

结构体总计占用16个字节,占用一行cacheline,有5个成员

/* sum members: 11, holes: 1, sum holes: 2 */

结构体成员总计使用11个字节,有一个空洞,空洞总计占用2个字节

/* padding: 3 */

结构体对齐需要padding 3个字节

/* last cacheline: 16 bytes */

最后一行cacheline 使用了16个字节

参考 链接到标题

https://docs.zephyrproject.org/3.4.0/develop/optimizations/tools.html