Karthik-Swaminathan98/mcu-function-size-analyser
GitHub: Karthik-Swaminathan98/mcu-function-size-analyser
Python工具,通过解析map文件和objdump反汇编构建调用图,精确计算MCU函数的真实代码尺寸(含全部依赖),支持ARM Cortex-M和RISC-V架构的嵌入式基准测试与架构对比分析。
Stars: 0 | Forks: 0
# mcu-function-size-analyser
在 **TU Chemnitz / Infineon Technologies** 攻读硕士学位期间开发(2025年)。
用于测量 20 多个 CMSIS-DSP/NN 和 NMSIS/Andes-DSP/NN 内核的代码大小。
**源码仓库:**
- ARM 基准测试:[ARM-Project](https://github.com/Karthik-Swaminathan98/ARM-Project)
- RISC-V 基准测试:[RISCV-Project](https://github.com/Karthik-Swaminathan98/RISCV-Project)
- 完整结果:[arm-riscv-benchmark-results](https://github.com/Karthik-Swaminathan98/arm-riscv-benchmark-results)



## 为什么依赖感知的代码大小很重要
嵌入式基准测试中一个常见的错误是,仅报告函数自身的编译后大小。
实际上,集成一个内核意味着要为其调用的每一个例程付出代价——
辅助函数、数学工具、初始化代码。
例如,`arm_cfft_f32` 本身只有 **308 字节**,但包含所有依赖项在内的完整内存占用空间
是 **3308 字节**——大了超过 10 倍。
如果仅报告 308 字节,将会误导那些在严格的 Flash 限制下
在 CMSIS 和 NMSIS 之间进行选择的开发者。
这些脚本始终会同时报告这两个数值——自身大小以及包含完整依赖项细分在内的总大小。
## 脚本
### `function_size.py` — ARM Cortex-M (CMSIS)
解析 ARM `.map` 文件和 `objdump` 反汇编(使用 `bl`, `blx`, `b.w` 调用指令)
以构建调用图并计算函数总的内存占用。
```
python function_size.py [function_name2 ...]
```
**示例:**
```
python function_size.py \
Release/arm_fft_benchmark.map \
Release/arm_fft_benchmark.objdump \
arm_cfft_f32 arm_cfft_q15
```
**输出:**
```
[*] Analyzing file: Release/arm_fft_benchmark.map
[*] Function: arm_cfft_f32
Own size: 308 bytes
Total size (with dependencies): 3308 bytes
[*] Breakdown:
arm_radix8_butterfly_f32 1404 bytes
arm_cfft_radix8by4_f32 1176 bytes
arm_cfft_radix8by2_f32 420 bytes
arm_cfft_f32 308 bytes
------------------------------------------------------------
```
### `function_size_riscv.py` — RISC-V Andes D25F (NMSIS / Andes)
针对 RISC-V 目标进行相同的分析——从 RISC-V objdump 反汇编中解析 `jal`, `j`, `c.j`, `call` 指令
(支持 RVC 压缩编码)。
```
python function_size_riscv.py [function_name2 ...]
```
**示例:**
```
python function_size_riscv.py \
output/map.txt \
output/objdump.txt \
riscv_dsp_cfft_f32 riscv_dsp_cfft_q15
```
**输出:**
```
[*] Analyzing file: output/map.txt
[*] Function: riscv_dsp_cfft_f32
Own size: 272 bytes
Total size (with dependencies): 2184 bytes
[*] Breakdown:
riscv_dsp_cfft_rd4_f32 1052 bytes
riscv_dsp_cfft_rd2_f32 624 bytes
riscv_dsp_cfft_f32 272 bytes
riscv_dsp_bitreversal 236 bytes
------------------------------------------------------------
```
## Makefile 集成 — 自动化的构建后分析
这两个脚本都被设计为在项目 Makefile 中作为构建后步骤自动运行——
每次构建后无需手动调用。
### RISC-V (AndeSight / riscv-32-elf-gcc)
将此目标添加到您的项目 Makefile 中:
```
.PHONY: function-analysis
FUNCTIONS := riscv_dsp_cfft_f32 riscv_dsp_cfft_q15 \
riscv_dsp_cifft_f32 riscv_dsp_cifft_q15
function-analysis: output/objdump.txt output/map.txt
@echo "Running function size analysis..."
python tools/function_size_riscv.py \
output/map.txt \
output/objdump.txt \
$(FUNCTIONS) > tools/code_size_report.txt || true
```
每次构建后,运行:
```
make function-analysis
```
输出将保存到 `tools/code_size_report.txt`。
### ARM (ModusToolbox / GCC ARM)
将此添加到您的 ModusToolbox `Makefile` 中作为 `POSTBUILD` 钩子——
每次项目成功构建时自动运行:
```
TARGET_FUNC := arm_cfft_f32 arm_cfft_q15 arm_fir_f32
POSTBUILD=\
$(MTB_TOOLCHAIN_GCC_ARM__BASE_DIR)/bin/arm-none-eabi-objdump -S \
$(MTB_TOOLS__OUTPUT_CONFIG_DIR)/$(APPNAME).$(MTB_TOOLCHAIN_GCC_ARM__SUFFIX_TARGET) \
> $(MTB_TOOLS__OUTPUT_CONFIG_DIR)/$(APPNAME).objdump && \
python tools/function_size.py \
$(MTB_TOOLS__OUTPUT_CONFIG_DIR)/$(APPNAME).map \
$(MTB_TOOLS__OUTPUT_CONFIG_DIR)/$(APPNAME).objdump \
$(TARGET_FUNC) > tools/code_size_report.txt
```
ModusToolbox 中的 `POSTBUILD` 变量会在成功构建后执行——
objdump 会自动生成,分析随即运行,
并将结果保存到 `tools/code_size_report.txt`。
## 工作原理
这两个脚本都遵循相同的 3 步流水线:
```
1. Parse .map file
└─► Extract function names + sizes from .text.* sections
2. Parse objdump disassembly
└─► Build call graph: which functions call which
ARM: bl / blx / b.w instructions
RISC-V: jal / j / c.j / call instructions
3. BFS traversal from root function
└─► Visit all reachable callees
└─► Sum sizes of all unique visited functions
└─► Report: own size + total size + breakdown
```
### ARM 和 RISC-V 版本之间的主要区别
| | `function_size.py` (ARM) | `function_size_riscv.py` (RISC-V) |
|---|---|---|
| 解析的调用指令 | `bl`, `blx`, `b.w`, `b` | `jal`, `j`, `c.j`, `call` |
| 压缩编码 | 否 (ARM Thumb) | 是 (RISC-V RVC) |
| Map 节格式 | `.text.arm_*` | `.text.riscv_*` |
## 环境要求
```
Python >= 3.8
```
无外部依赖项——仅使用 Python 标准库(`sys`, `re`, `os`,
`collections`)。无需 `pip install`。
## 仓库结构
```
mcu-function-size-analyser/
├── function_size.py # ARM Cortex-M code size analyser
├── function_size_riscv.py # RISC-V Andes D25F code size analyser
└── README.md
```
## 添加到您自己的项目中
1. 将 `function_size.py` (ARM) 或 `function_size_riscv.py` (RISC-V) 复制到您项目中的 `tools/` 文件夹中
2. 添加上面所示的 Makefile 目标
3. 在 `FUNCTIONS` / `TARGET_FUNC` 中设置您的目标函数名称
4. 构建您的项目——报告会自动生成
## 相关仓库
| 仓库 | 描述 |
|---|---|
| [ARM-Project](https://github.com/Karthik-Swaminathan98/ARM-Project) | ARM Cortex-M4 CMSIS-DSP/NN 基准测试——使用 `function_size.py` |
| [RISCV-Project](https://github.com/Karthik-Swaminathan98/RISCV-Project) | RISC-V NMSIS-DSP/NN 基准测试——使用 `function_size_riscv.py` |
| [arm-riscv-benchmark-results](https://github.com/Karthik-Swaminathan98/arm-riscv-benchmark-results) | 包含代码大小比较的完整跨架构结果 |
## 致谢
作为 **Technische Universität Chemnitz** 硕士学位论文的一部分,与德累斯顿的
**Infineon Technologies** 合作开发(2025年)。
## 作者
**Karthik Swaminathan** — 嵌入式固件工程师
理学硕士 · 嵌入式系统 · TU Chemnitz
[LinkedIn](https://linkedin.com/in/karthik-swaminathan98) · karthik94870@gmail.com
标签:ARM, Python, RISC-V, 代码体积分析, 嵌入式系统, 性能分析, 无后门