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 benchmarks:[ARM-Project](https://github.com/Karthik-Swaminathan98/ARM-Project)
- RISC-V benchmarks:[RISCV-Project](https://github.com/Karthik-Swaminathan98/RISCV-Project)
- 完整结果:[arm-riscv-benchmark-results](https://github.com/Karthik-Swaminathan98/arm-riscv-benchmark-results)



## 为什么依赖感知代码大小很重要
A common mistake in embedded benchmarking is reporting only a function's own compiled size.
In practice, integrating a kernel means paying for every routine it calls —
helper functions, math utilities, initialisation code.
For example, `arm_cfft_f32` itself is only **308 bytes** but its full footprint
including all dependencies is **3308 bytes** — more than 10× larger.
Reporting only 308 bytes would mislead any developer choosing between CMSIS and NMSIS
under tight Flash constraints.
These scripts always report both figures — own size and total size with full dependency breakdown.
## 脚本
### `function_size.py` — ARM Cortex-M (CMSIS)
Parses ARM `.map` files and `objdump` disassembly (using `bl`, `blx`, `b.w` call instructions)
to build a call graph and compute total function footprint.
```
python function_size.py [function_name2 ...]
```
**Example:**
```
python function_size.py \
Release/arm_fft_benchmark.map \
Release/arm_fft_benchmark.objdump \
arm_cfft_f32 arm_cfft_q15
```
**Output:**
```
[*] 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)
Same analysis for RISC-V targets — parses `jal`, `j`, `c.j`, `call` instructions
from RISC-V objdump disassembly (RVC compressed encoding supported).
```
python function_size_riscv.py [function_name2 ...]
```
**Example:**
```
python function_size_riscv.py \
output/map.txt \
output/objdump.txt \
riscv_dsp_cfft_f32 riscv_dsp_cfft_q15
```
**Output:**
```
[*] 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 集成 — 自动化构建后分析
Both scripts are designed to run automatically as post-build steps inside the
project Makefile — no manual invocation needed after each build.
### RISC-V (AndeSight / riscv-32-elf-gcc)
Add this target to your project 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
```
After each build, run:
```
make function-analysis
```
Output is saved to `tools/code_size_report.txt`.
### ARM (ModusToolbox / GCC ARM)
Add this to your ModusToolbox `Makefile` as a `POSTBUILD` hook —
runs automatically every time the project builds successfully:
```
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
```
The `POSTBUILD` variable in ModusToolbox executes after a successful build —
objdump is generated automatically and the analysis runs immediately,
saving results to `tools/code_size_report.txt`.
## 工作原理
Both scripts follow the same 3-step pipeline:
```
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) |
|---|---|---|
| Call instructions parsed | `bl`, `blx`, `b.w`, `b` | `jal`, `j`, `c.j`, `call` |
| Compressed encoding | No (ARM Thumb) | Yes (RISC-V RVC) |
| Map section format | `.text.arm_*` | `.text.riscv_*` |
## 要求
```
Python >= 3.8
```
No external dependencies — uses only Python standard library (`sys`, `re`, `os`,
`collections`). No `pip install` needed.
## 仓库结构
```
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. Copy `function_size.py` (ARM) or `function_size_riscv.py` (RISC-V) into a `tools/` folder in your project
2. Add the Makefile target shown above
3. Set your target function names in `FUNCTIONS` / `TARGET_FUNC`
4. Build your project — the report generates automatically
## 相关仓库
| Repo | Description |
|---|---|
| [ARM-Project](https://github.com/Karthik-Swaminathan98/ARM-Project) | ARM Cortex-M4 CMSIS-DSP/NN benchmarks — uses `function_size.py` |
| [RISCV-Project](https://github.com/Karthik-Swaminathan98/RISCV-Project) | RISC-V NMSIS-DSP/NN benchmarks — uses `function_size_riscv.py` |
| [arm-riscv-benchmark-results](https://github.com/Karthik-Swaminathan98/arm-riscv-benchmark-results) | Full cross-architecture results including code size comparisons |
## 致谢
Developed as part of a Master's thesis at **Technische Universität Chemnitz**
in collaboration with **Infineon Technologies**, Dresden (2025).
## 作者
**Karthik Swaminathan** — Embedded Firmware Engineer
M.Sc. Embedded Systems · TU Chemnitz
[LinkedIn](https://linkedin.com/in/karthik-swaminathan98) · karthik94870@gmail.com
标签:CMSIS-DSP, Cortex-M, Flash占用优化, Infineon, MCU开发, NMSIS, Objdump, Python, RISC-V, TU Chemnitz, 云安全监控, 代码体积分析, 代码依赖分析, 嵌入式系统, 性能可视化, 无后门, 架构对比, 硕士论文工具, 调用图解析, 链接映射文件, 静态分析