Hello,

as I mentioned in my previous message (the request for pull request ;-) ), I noticed flash (program memory) usage increase that happened over last few months.

I bisected the source code and it pointed at commit 6ed4ea63d8168be30227415ea85ae936ca41bb6f . It adds new parameter to mm_initialize_heap (renamed from mm_initialize.) Further investigation showed that the program size increase is caused by the new branch (heap != NULL). I verified this by forcing the variable to be NULL, the branch was optimized away and linker eliminated mm_memalign and mm_shrinkchunk from the resulting binary - yielding 1400 bytes of reduced size. This matched the increase I spotted.

I work with 8bit microcontroller with 128kB program flash, so 1400 bytes is not an insignificant amount.

I then went to analyze how is this function called, I found these occurences:

1. drivers/rptun/rptun.c - called with heap parameter set
2. inline function mm_initialize - heap set to NULL

Other than that, mm_initialize_heap is not called directly. Indirectly, it is either called from mm_initialize_pool, or it replaces this function via #define (mm_initialize_pool translated to mm_initialize_heap)

Considering this, I also analyzed how mm_initialize_pool is called, I found:

1. multiple occurrences in various functions in mm/ directory. These either call mm_initialize_heap with heap set to NULL, or pass whatever was given to them through
2. fs/fs_heap.c - sets heap parameter to NULL
3. drivers/pci/pci_epc.c - is not using config parameter at all, instead it passes four parameters so it was probably not converted when the interface changed?

(As a side note - this is the second time this week where I found a change authored or co-authored by Xiaomi that alters some internal interface and then converts users of that interface... except some. Seemingly missing are the ones that are fairly recent additions - the other one is AVR DA/DB subarchitecture which currently fails to build with default configuration; proposed fix is in my previous message.

Are they/are you working on some outdated fork of NuttX upstream? Even more curious is that the broken - at least if I understand that correctly - file pci_epc.c is also authored by Xiaomi. Anyway, back to the topic at hand.)

If my research above is correct, then in-tree code has only a single use case for the change added by the commit but incurs program memory size penalty for all users (with varying impact.) In such case, I think this should be made optional. (This may be up for discussion though - the memory reduction I achieved is 1400 bytes on AVR but only 400 bytes on rv-virt. The question is if the code clutter - albeit a small one - is worth it for one less significant architecture.)

I prepared a patch that eliminates this program memory size increase if the heap parameter is not actually used by anything. It wraps member value FAR struct mm_heap_s *heap in struct mm_heap_config_s with #ifndef CONFIG_MM_DISABLE_INIT_HEAP_POINTER , a new configuration option which defaults to DEFAULT_SMALL. The RPTUN driver is made to depends on !MM_DISABLE_INIT_HEAP_POINTER . Other than that, mm_initialize_heap adds multiple #ifndef directives to eliminate code related to heap parameter.

This approach has two benefits:

1. if more users of the heap parameter are added but not made to depend on !MM_DISABLE_INIT_HEAP_POINTER, build with DEFAULT_SMALL will fail - no hidden errors 2. other users of struct mm_heap_config_s use memset to clear it before use. The heap parameter is not set so no code change is needed for those calls

The patch is available in a git repository nuttx.git at git.kerogit.eu accessible through HTTP/S. (Trying to prevent bot traffic by not posting the URL in machine-readable form.) The relevant branch is called mm_init_optional_heap. If someone has the time to look at it and provide feedback and/or create pull request on GitHub (I don't have an account), it would be greatly appreciated. I think the change is quite trivial to be reasonably sure that it does not break anything but this is definitively an area where I only have a vague understanding of the code at best.

As of note - I did some tests of the change but there was one thing I was not able to test - the RPTUN driver itself. Don't have any hardware to try with and I wasn't even able to compile it for AVR (well, to be more precise - when I tried, it started downloading things from the web so I stopped the build.)

Following is for the GitHub PR (if it comes to it)

================

Summary

Make heap parameter of function mm_initialize_heap optional in mm/mm_heap/mm_initialize.c

Problem:

Parameter heap added in commit 6ed4ea63d8168be30227415ea85ae936ca41bb6f necessitates call of function mm_memalign which can otherwise be eliminated from compiled binary on small architectures, namely 8-bit AVR DA/DB family. This increases program memory consumption by 1400 bytes on that architecture. This parameter is currently only used by RPTUN driver.

Solution:

Add MM_DISABLE_INIT_HEAP_POINTER configuration option which removes this parameter and the associated code, if set

Impact

Users: will be able to use more program memory for their application code

Build:

- new Kconfig option MM_DISABLE_INIT_HEAP_POINTER, defaults to DEFAULT_SMALL
- rptun driver depends on !MM_DISABLE_INIT_HEAP_POINTER

Compatibility:

- no functional change for architectures/boards that do not set DEFAULT_SMALL - architectures that set DEFAULT_SMALL will be unable to build rptun driver unless the new option is unset manually

Testing

Test 1

Hardware: AVR128DA28 (NSH build for breadxavr board)

Tests performed:

- build test with the new option unset to verify that code does not change - build test with the new option set to verify that the code is functional

Before the patch:

$ make
Register: nsh
Register: sh
LD: nuttx
Memory region         Used Size  Region Size  %age Used
           flash:       51489 B       128 KB     39.28%
            sram:         636 B        16 KB      3.88%
          eeprom:           0 B        512 B      0.00%
          rodata:         592 B         4 KB     14.45%
CP: nuttx.hex
CP: nuttx.asm
$ sha256sum nuttx
818bad0a984a3b75ccd0f138e4bfcfa00264807b9a9d6d16683ea42eac01413d  nuttx

After the patch (new option not set)

$ make
LD: nuttx
Memory region         Used Size  Region Size  %age Used
           flash:       51489 B       128 KB     39.28%
            sram:         636 B        16 KB      3.88%
          eeprom:           0 B        512 B      0.00%
          rodata:         592 B         4 KB     14.45%
CP: nuttx.hex
CP: nuttx.asm
$ sha256sum nuttx
818bad0a984a3b75ccd0f138e4bfcfa00264807b9a9d6d16683ea42eac01413d  nuttx

Result - the patch does not change the compiled binary when the new configuration option is not enabled

After the patch (new option set)

$ make
LD: nuttx
Memory region         Used Size  Region Size  %age Used
           flash:       50079 B       128 KB     38.21%
            sram:         636 B        16 KB      3.88%
          eeprom:           0 B        512 B      0.00%
          rodata:         592 B         4 KB     14.45%
CP: nuttx.hex
CP: nuttx.asm

$ minicom
Welcome to minicom 2.10

OPTIONS: I18n
Port /dev/serial/by-id/usb-FTDI_FT230X_Basic_UART_DU0DQ17J-if00-port0, 16:37:48 [U]

Press CTRL-A Z for help on special keys


NuttShell (NSH) NuttX-12.12.0
nsh> help
help usage:  help [-v] [<cmd>]

    ?       help
nsh>

Result - NSH is functional and flash usage is reduced

Test 2

Hardware: building for Risc-V Qemu - rv-virt:nsh

Tests performed:
- build test with the new option unset to verify that code does not change, run in Qemu, run ostest - build test with the new option set to verify that code runs correctly, run in Qemu, run ostest

Before the patch

$ sha256sum nuttx nuttx.asm
9c68c09fae0effec154957ed0a3b45b9e45879d708c3cd55f15f7be3c07c443d  nuttx
146c24fad25f74f923b7398fbce5310adfdb88fc3875ed5127f74c058ebf7c60 nuttx.asm

ostest:
dump_assert_info: Current Version: NuttX 12.12.0 b4242042e1 Feb 22 2026 14:44:13 risc-v
...
ostest_main: Exiting with status 0

After the patch (new option in default state, ie. unset)

$ sha256sum nuttx nuttx.asm
79005fc3be7f240896caa2b03b231254f903705b38bfc1eefeb263da880f7150  nuttx
146c24fad25f74f923b7398fbce5310adfdb88fc3875ed5127f74c058ebf7c60 nuttx.asm

dump_assert_info: Current Version: NuttX 12.12.0 ee396982d7 Feb 22 2026 15:46:21 risc-v
...
ostest_main: Exiting with status 0

Result - the resulting binary does differ but the disassembly does not. Ostest completes successfully.

After the patch (new option set)

Program size reduced by cca 400 bytes (compared by last instruction's address in disassembly.)

dump_assert_info: Current Version: NuttX 12.12.0 ee396982d7 Feb 22 2026 16:24:11 risc-v
...
ostest_main: Exiting with status 0

NOTE - RPTUN driver, the only user of the (optionally removed) heap parameter, was not tested - no access to relevant hardware.

================

Thanks for your time

Reply via email to