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) ![Language](https://img.shields.io/badge/language-Python%203-blue) ![Targets](https://img.shields.io/badge/targets-ARM%20%7C%20RISC--V-informational) ![Thesis](https://img.shields.io/badge/thesis-TU%20Chemnitz%20%2F%20Infineon%202025-green) ## 为什么依赖感知代码大小很重要 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, 云安全监控, 代码体积分析, 代码依赖分析, 嵌入式系统, 性能可视化, 无后门, 架构对比, 硕士论文工具, 调用图解析, 链接映射文件, 静态分析