esp-idf/docs/en/api-guides/tools/idf-size.rst
Mahavir Jain 3dc80527ab
feat: add compiler config for not merging const sections
Probably GCC-13.x and on-wards uses "-fmerge-constants" to merge
the const section (string/floating-point) across compilation units.
This makes it difficult to properly analyze the size output of rodata
section across libraries, the merged section (big in size) is showed
across a single library.

The config option added here can help to disable this compiler behavior
and help to provide better size analysis. It can be used during
development phase only as it increases rodata section size.
2024-07-15 10:04:55 +05:30

267 lines
36 KiB
ReStructuredText

********
IDF Size
********
IDF Size is a tool for analyzing statically-allocated memory in ESP-IDF project. The main functionality is provided by the esp-idf-size_ Python package, while :ref:`idf.py` offers a more user-friendly and higher-level interface through the ``size``, ``size-components``, and ``size-files`` sub-commands. These sub-commands allow you to specify various options, such as the report's output format. For more details, please use the ``--help`` option. ESP-IDF also includes a handy ``idf_size.py`` wrapper to invoke the esp-idf-size_ Python module. For more information, use the command ``idf_size.py --help``.
Size Summary ``idf.py size``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This output provides a summary of the statically-allocated memory for different memory types in the firmware binary:
.. code-block:: bash
$ idf.py size
Memory Type Usage Summary
┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Memory Type/Section ┃ Used [bytes] ┃ Used [%] ┃ Remain [bytes] ┃ Total [bytes]
┡━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ Flash Code │ 80666 │ 2.41 │ 32616383342304
│ .text │ 80666 │ 2.41 │ │ │
│ IRAM │ 51835 │ 39.55 │ 79237131072
│ .text │ 50807 │ 38.76 │ │ │
│ .vectors │ 1027 │ 0.78 │ │ │
│ Flash Data │ 38224 │ 0.91 │ 41560484194272
│ .rodata │ 37968 │ 0.91 │ │ │
│ .appdesc │ 256 │ 0.01 │ │ │
│ DRAM │ 11236 │ 6.22 │ 169500180736
│ .data │ 8988 │ 4.97 │ │ │
│ .bss │ 2248 │ 1.24 │ │ │
│ RTC SLOW │ 24 │ 0.29 │ 81688192
│ .rtc_slow_reserved │ 24 │ 0.29 │ │ │
└───────────────────────┴──────────────┴──────────┴────────────────┴───────────────┘
Total image size: 179712 bytes (.bin may be padded larger)
Espressif chips include various :doc:`/api-guides/memory-types`, which are detailed in the `Technical Reference Manual (TRM) <{IDF_TARGET_TRM_EN_URL}>`__. These memory types are listed in the ``Memory Type`` column, along with the ELF ``Sections`` that are loaded into each type. The ``Used`` columns display the memory usage for each specific memory type or section. The ``Remain`` column indicates the remaining available memory for the specified memory type. The ``Total`` column shows the total available memory for that memory type, based on the memory region sizes defined in the linker script that map into the memory type.
.. note::
The ``Total`` memory available for each memory type, like ``IRAM``, is determined by the memory region sizes specified in the link map file, which is generated by the linker script, with the MEMORY command, during the build process. The esp-idf-size tool includes YAML files for each target, detailing memory type ranges based on the TRM. The memory ranges from the link map file are mapped to these memory type ranges. This process calculates the total memory available for different memory types. Note that the total available size may differ from what is stated in the TRM, as some memory portions may be reserved for purposes such as the bootloader or cache, depending on the configuration. The remaining memory is calculated by subtracting the sizes of output ``Sections`` loaded to the specific memory type from the ``Total`` size.
.. note::
Certain memory types might map to the same hardware memory. On some targets, ``IRAM`` and ``DRAM`` could be mapped to the same hardware memory but at different virtual addresses, accessible through data and instruction buses. These memory types are referred to as ``DIRAM`` in the ``Memory Type`` column.
Below is a description of the most interesting memory types and output sections. Please note that all output sections with a non-zero size are included in the summary. Their names are determined by the output section names specified in the linker script.
- ``DRAM``: Total amount of DRAM allocated at compile time. ``Remain`` indicates the amount of DRAM left to be used as heap memory at runtime. Note that due to meta data overhead, implementation constraints, and startup heap allocations, the actual size of the DRAM heap is smaller.
- ``.data``: Amount of DRAM allocated at compile time for the ``.data`` (i.e., all statically allocated variables that are initialized to non-zero values). ``.data`` also consumes space in the binary image to store the non-zero initialization values.
- ``.bss``: Amount of DRAM allocated at compile time for ``.bss`` (i.e., all statically allocated variables that are initialized to zero). ``.bss`` does not consume extra space in flash.
- ``IRAM``: Total amount of IRAM allocated at compile time. ``Remain`` indicates the amount of IRAM left to be used as heap memory at runtime. Note that due to meta data overhead, implementation constraints, and startup heap allocations, the actual size of the IRAM heap is smaller.
- ``.text``: Amount of IRAM used for ``.text`` (i.e., all code that is executed from :ref:`IRAM <iram>`). ``.text`` also consumes space in the binary image as the code is initially stored there and is then copied over to IRAM on startup.
- ``Flash Code``: Code executed from flash.
- ``.text``: Amount of flash used for ``.text`` (i.e., all code that is executed via the flash cache, see :ref:`IROM <irom>`).
- ``Flash Data``: Data stored in flash.
- ``.rodata``: Amount of flash used for ``.rodata`` (i.e., read-only data that is loaded via the flash cache, see :ref:`DROM <drom>`).
- ``Total image size`` is the estimated total size of the binary file.
Component Usage Summary ``idf.py size-components``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The summary output from ``idf.py size`` lacks sufficient detail to identify the primary cause of excessive binary size. For a more detailed analysis, use ``idf.py size-components``, which indicates the contribution of each static library archive to the final binary size.
.. code-block:: bash
$ idf.py size-components
Per-archive contributions to ELF file
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┓
┃ Archive File ┃ Total Size ┃ DRAM ┃ .bss ┃ .data ┃ IRAM ┃ .text ┃ .vectors ┃ Flash Code ┃ .text ┃ Flash Data ┃ .rodata ┃ .appdesc ┃ RTC SLOW ┃ .rtc_slow_reserved ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━┩
│ libnet80211.a │ 11671294548393106153105310089698896981225012250000
│ libmbedcrypto.a │ 105863141816000071251712513447134471000
│ liblwip.a │ 853942470245812000794867948634383438000
│ libpp.a │ 6648439151444247120004200040377143771448514851000
│ libc.a │ 59525576316260000555135551334363436000
│ libesp_app_format.a │ 5320910100000417417527825252625600
│ libwpa_supplicant.a │ 45251124112338000423154231516951695000
│ libphy.a │ 443601229637592892289220342093420900000
│ libfreertos.a │ 21108384174131001559415594046746712061206000
│ libesp_hw_support.a │ 15147256961605654565408264826494994902424
│ libnvs_flash.a │ 14522242400001425014250248248000
│ libesp_system.a │ 1330479331348042674267075757575669669000
│ libhal.a │ 1307840008399258105810031433143125125000
│ libheap.a │ 1200912847298729803109310915901590000
│ libspi_flash.a │ 116131348241324893289320865865468468000
│ libesp_driver_uart.a │ 72552283219600064346434593593000
│ libesp_netif.a │ 59543329400057585758163163000
│ libvfs.a │ 41802364419200037573757187187000
│ libesp_mm.a │ 40031601243610021002026272627214214000
│ libesp_wifi.a │ 3919527474803573570299329934242000
│ libesp_timer.a │ 347156243216211621016591659135135000
│ libxtensa.a │ 3412104401044221317894241191193636000
│ libnewlib.a │ 335236020016015351535013461346111111000
│ libesp_event.a │ 313744000029922992141141000
│ libesp_phy.a │ 2400533617235235018681868244244000
│ libbootloader_support.a │ 193900018051805094944040000
│ libesp_partition.a │ 186588000016891689168168000
│ libesp_common.a │ 1793000000515117421742000
│ liblog.a │ 170628027282762760110211024848000
│ libefuse.a │ 16726446000014271427181181000
│ libsoc.a │ 154000037370393914641464000
│ libstdc++.a │ 15022117400012821282199199000
│ libesp_ringbuf.a │ 1121000102410240009797000
│ libmain.a │ 10278800009649645555000
│ libpthread.a │ 678201280006046045454000
│ libesp_vfs_console.a │ 59912120000415415172172000
│ libxt_hal.a │ 4750004434430003232000
│ librtc.a │ 45600045645600000000
│ libcore.a │ 331333300002552554343000
│ libesp_coex.a │ 277000118118015915900000
│ libapp_update.a │ 1864400001521523030000
│ libesp_rom.a │ 10200010210200000000
│ libgcc.a │ 89000000898900000
│ libcxx.a │ 52000000525200000
│ libnvs_sec_provider.a │ 50000005500000
(exe)30003030000000
└─────────────────────────┴────────────┴──────┴──────┴───────┴───────┴───────┴──────────┴────────────┴───────┴────────────┴─────────┴──────────┴──────────┴────────────────────┘
Generally, one static library archive is built per component, although some are binary libraries included by a particular component, for example, ``libnet80211.a`` is included by ``esp_wifi`` component. There are also toolchain libraries such as ``libc.a`` and ``libgcc.a`` listed here, these provide Standard C/C++ Library and toolchain built-in functionality.
If the project is simple and only has a ``main`` component, then all of the project's code will be shown under ``libmain.a``. If the project includes its own components (see :doc:`/api-guides/build-system`), then they will each be shown on a separate line.
The table is sorted in descending order of the total contribution of the static archive to the binary size. The columns indicate memory types and output sections as detailed in the Size Summary.
.. note::
The ``(exe)`` archive is a special archive that contains object files directly linked into the final binary, meaning they are not part of any archive file.
.. note::
The size of the ``.rodata`` section in the ``Flash Data`` memory type may appear very large for a single archive. This occurs due to linker relaxations. The linker may attempt to combine object file sections with ``MERGE`` and ``STRINGS`` flags from all archives into one to perform tail string optimization. Consequently, one archive may end up with a very large ``.rodata`` section, containing string literals from other archives. This is evident in the ``.rodata`` section of the ``libesp_app_format.a`` archive. The specific compiler behavior here can be turned off by enabling :ref:`CONFIG_COMPILER_NO_MERGE_CONSTANTS` option (only for GCC toolchain), please read help for more details.
Source File Usage Summary ``idf.py size-files``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For even more details, run ``idf.py size-files`` to get a summary of the contribution each object file has made to the final binary size. Each object file corresponds to a single source file.
.. code-block:: bash
$ idf.py size-files
Per-file contributions to ELF file
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━┳━━━━━━━┳━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┓
┃ Object File ┃ Total Size ┃ DRAM ┃ .bss ┃ .data ┃ IRAM ┃ .text ┃ .vectors ┃ Flash Code ┃ .text ┃ Flash Data ┃ .rodata ┃ .appdesc ┃ RTC SLOW ┃ .rtc_slow_reserved ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━╇━━━━━━━╇━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━┩
│ esp_app_desc.c.obj │ 7231310100000417417718867163025600
│ x509_crt_bundle.S.obj │ 67810000000006781067810000
│ ecp_curves.c.obj │ 36415000000687568752954029540000
│ phy_chip_v7.o │ 19384783533250218621860164151641500000
│ wl_cnx.o │ 185673891388922772770133431334310561056000
│ ieee80211_output.o │ 15498272522083208301284012840548548000
│ pp.o │ 14722120753115472867286055905590639639000
│ libc_a-vfprintf.o │ 140840000001350813508576576000
│ phy_chip_v7_cal.o │ 13997229541754039403909729972900000
│ pm.o │ 139585324884436303630088238823973973000
│ libc_a-svfprintf.o │ 137530000001317713177576576000
│ ieee80211_sta.o │ 13711503812144314430111811118110371037000
│ ieee80211_ioctl.o │ 1347912011642712710111271112719611961000
│ ieee80211_scan.o │ 12037327309180001111911119591591000
│ ieee80211_hostap.o │ 1197042411000108981089810301030000
│ nd6.c.obj │ 1181594093280001076410764111111000
│ phy_chip_v7_ana.o │ 11039217501672697269708125812500000
│ ieee80211_ht.o │ 110335411179117908466846613831383000
│ sae.c.obj │ 1100300000010971109713232000
│ tasks.c.obj │ 107537126961694169416000625625000
│ libc_a-svfiprintf.o │ 104460000009398939810481048000
│ libc_a-vfiprintf.o │ 1009200000095169516576576000
│ wpa.c.obj │ 968887287200008816881600000
│ tcp_in.c.obj │ 89045252000086988698154154000
[... additional lines removed ...]
The table is sorted in descending order of the total contribution of the object files to the binary size. The columns indicate memory types and output sections as detailed in the Size Summary.
For example, we can see that the file ``x509_crt_bundle.S.o`` contributed 67,810 bytes to the total firmware size, all as ``.rodata`` in flash. Therefore we can guess that this application is using the :doc:`/api-reference/protocols/esp_crt_bundle` feature and not using this feature would save at last this many bytes from the firmware size.
Some of the object files are linked from binary libraries and therefore you will not find a corresponding source file. To locate which component a source file belongs to, it is generally possible to search in the ESP-IDF source tree or look in the :ref:`linker-map-file` for the full path.
Comparing Two Binaries
^^^^^^^^^^^^^^^^^^^^^^
When making changes that impact binary size, you can use the IDF Size tool to analyze the precise differences in size. The ``--diff`` option can be used with all previously mentioned sub-commands, allowing you to specify a path to a project build for comparison with the current project.
For example to compare two ``hello_world`` project builds, follow these steps. First, create two copies of the ``hello_world`` project directory. Name the first project directory ``hello_world_Og``. This project will use the default :ref:`CONFIG_COMPILER_OPTIMIZATION` compiler optimization setting ``Debug (-Og)`` and will serve as the ``REFERENCE`` project. Name the second project directory ``hello_world_Os``. This project will use the ``Optimize for size (-Os)`` setting, which can be enabled using ``idf.py menuconfig``. This will be the ``CURRENT`` project. Build both projects. Then, from within the ``hello_world_Os`` project directory, run the following command:
.. code-block:: bash
$ idf.py size --diff ../hello_world_Og
CURRENT project file: "hello_world_Os/build/hello_world.map"
REFERENCE project file: "hello_world_Og/build/hello_world.map"
Difference is counted as CURRENT - REFERENCE, i.e. a positive number means that CURRENT is larger.
Memory Type Usage Summary
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Memory Type/Section ┃ Used [bytes] ┃ Used [%] ┃ Remain [bytes] ┃ Total [bytes]
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ Flash Code │ 74498 -6168 │ 2.23 -0.18 │ 3267806 +6168 │ 3342304 0
│ .text │ 74498 -6168 │ 2.23 -0.18 │ │ │
│ IRAM │ 45539 -6296 │ 34.74 -4.8 │ 85533 +6296 │ 131072 0
│ .text │ 44511 -6296 │ 33.96 -4.8 │ │ │
│ Flash Data │ 35784 -2440 │ 0.85 -0.06 │ 4158488 +2440 │ 4194272 0
│ .rodata │ 35528 -2440 │ 0.85 -0.06 │ │ │
│ DRAM │ 10844 -392 │ 6.0 -0.22 │ 169892 +392 │ 180736 0
│ .data │ 8612 -376 │ 4.76 -0.21 │ │ │
│ .bss │ 2232 -16 │ 1.23 -0.01 │ │ │
└─────────────────────┴──────────────┴──────────────┴────────────────┴────────────────┘
Total image size: 164432 -15280 bytes (.bin may be padded larger)
In addition to the previously mentioned Size Summary example, each column now also shows the size differences. Each difference is shown as ``CURRENT - REFERENCE``, meaning the current project sizes minus the sizes in the project specified with the `--diff` option. In this example, the final binary image of the ``hello_world_Os`` project is 15,280 bytes smaller than that of the ``hello_world_Og`` project. Additionally, the ``hello_world_Os`` project uses 6,168 bytes less in `Flash Code` memory, leaving 6,168 bytes more available in ``Flash Code``, with no difference in the total available memory.
You can also use the diff mode to generate a table showing the differences at the component level (static library archive):
.. code-block:: bash
$ idf.py size-components --diff ../hello_world_Og
Additionally, at the level of each individual source file:
.. code-block:: bash
$ idf.py size-files --diff ../hello_world_Og
.. _idf-size-linker-failed:
Showing Size When Linker Fails
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If too much static memory is allocated, the linker will fail with an error such as ``DRAM segment data does not fit``, ``region `iram0_0_seg' overflowed by 44 bytes``, or similar.
In these cases, ``idf.py size`` will also fail. However, you can run ``idf_size.py``, which is a convenient wrapper that allows you to call ``esp-idf-size`` directly from within the ESP-IDF environment and see the partial static memory usage. The ``idf_size.py`` script requires a link map file as an argument, which is located in the project's build directory as ``<projectname>.map``.
.. code-block:: bash
$ idf_size.py <projectname>.map
warning: DRAM overflow detected!: output section or its part .dram0.bss(addr: 1073422848, size: 2240) does not fit into any memory region and will be assigned to the preceding dram0_0_seg memory region
warning: DRAM overflow detected!: output section or its part .dram0.data(addr: 1073414144, size: 8704) does not fit into any memory region and will be assigned to the preceding dram0_0_seg memory region
Memory Type Usage Summary
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Memory Type/Section ┃ Used [bytes] ┃ Used [%] ┃ Remain [bytes] ┃ Total [bytes]
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ Flash Code │ 79759 │ 2.39 │ 32625453342304
│ .text │ 79759 │ 2.39 │ │ │
│ IRAM │ 51106 │ 38.99 │ 79966131072
│ .text │ 50079 │ 38.21 │ │ │
│ .vectors │ 1027 │ 0.78 │ │ │
│ Flash Data │ 38576 │ 0.92 │ 41556964194272
│ .rodata │ 38320 │ 0.91 │ │ │
│ .appdesc │ 256 │ 0.01 │ │ │
│ DRAM │ 109440 │ -10944 │ 0
│ .data_overflow │ 87040 │ │ │
│ .bss_overflow │ 22400 │ │ │
└─────────────────────┴──────────────┴──────────┴────────────────┴───────────────┘
Total image size: 178145 bytes (.bin may be padded larger)
Sections that do not fit into the memory region will have the suffix ``_overflow``.
.. _esp-idf-size: https://github.com/espressif/esp-idf-size