Docs: add translation for api-guides/performance/size.rst

This commit is contained in:
Doc-intern2 2023-05-16 16:13:25 +08:00
parent f4f8d4eaa2
commit c166bcd6c6
2 changed files with 760 additions and 111 deletions

View File

@ -1,9 +1,11 @@
Minimizing Binary Size Minimizing Binary Size
====================== ======================
:link_to_translation:`zh_CN:[中文]`
{IDF_TARGET_REDUCED_BY_IRAM: default="DRAM", esp32="IRAM and/or DRAM (depending on sizes)"} {IDF_TARGET_REDUCED_BY_IRAM: default="DRAM", esp32="IRAM and/or DRAM (depending on sizes)"}
The ESP-IDF build system compiles all source files in the project and ESP-IDF, but only functions and variables that are actually referenced by the program are linked into the final binary. In some cases, it is necessary to reduce the total size of the firmware binary (for example, in order to fit it into the available flash partition size). The ESP-IDF build system compiles all source files in the project and ESP-IDF, but only functions and variables that are actually referenced by the program are linked into the final binary. In some cases, it is necessary to reduce the total size of the firmware binary, e.g., in order to fit it into the available flash partition size.
The first step to reducing the total firmware binary size is measuring what is causing the size to increase. The first step to reducing the total firmware binary size is measuring what is causing the size to increase.
@ -12,15 +14,16 @@ The first step to reducing the total firmware binary size is measuring what is c
Measuring Static Sizes Measuring Static Sizes
---------------------- ----------------------
To optimize both firmware binary size and memory usage it's necessary to measure statically allocated RAM ("data", "bss"), code ("text") and read-only data ("rodata") in your project. To optimize both the firmware binary size and the memory usage, it is necessary to measure statically-allocated RAM (``data``, ``bss``), code (``text``), and read-only data (``rodata``) in your project.
Using the :ref:`idf.py` sub-commands ``size``, ``size-components`` and ``size-files`` provides a summary of memory used by the project: Using the :ref:`idf.py` sub-commands ``size``, ``size-components``, and ``size-files`` provides a summary of memory used by the project:
.. note:: .. note::
It is possible to add ``-DOUTPUT_FORMAT=csv`` or ``-DOUTPUT_FORMAT=json`` to get the output in CSV or JSON format. It is possible to add ``-DOUTPUT_FORMAT=csv`` or ``-DOUTPUT_FORMAT=json`` to get the output in CSV or JSON format.
Size Summary (idf.py size) Size Summary ``idf.py size``
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. only:: esp32 .. only:: esp32
@ -28,14 +31,17 @@ Size Summary (idf.py size)
$ idf.py size $ idf.py size
[...] [...]
Total sizes: Total sizes:
DRAM .data size: 14956 bytes Used static DRAM: 10608 bytes ( 170128 remain, 5.9% used)
DRAM .bss size: 15808 bytes .data size: 8464 bytes
Used static DRAM: 30764 bytes ( 149972 available, 17.0% used) .bss size: 2144 bytes
Used static IRAM: 83918 bytes ( 47154 available, 64.0% used) Used static IRAM: 48834 bytes ( 82238 remain, 37.3% used)
Flash code: 559943 bytes .text size: 47807 bytes
Flash rodata: 176736 bytes .vectors size: 1027 bytes
Total image size:~ 835553 bytes (.bin may be padded larger) Used Flash size : 117391 bytes
.text: 80103 bytes
.rodata: 37032 bytes
Total image size: 174689 bytes (.bin may be padded larger)
.. only:: not esp32 .. only:: not esp32
@ -45,33 +51,87 @@ Size Summary (idf.py size)
$ idf.py size $ idf.py size
[...] [...]
Total sizes: Total sizes:
DRAM .data size: 11584 bytes Used stat D/IRAM: 53743 bytes ( 122385 remain, 30.5% used)
DRAM .bss size: 19624 bytes .data size: 6504 bytes
Used static DRAM: 0 bytes ( 0 available, nan% used) .bss size: 1984 bytes
Used static IRAM: 0 bytes ( 0 available, nan% used) .text size: 44228 bytes
Used stat D/IRAM: 136276 bytes ( 519084 available, 20.8% used) .vectors size: 1027 bytes
Flash code: 630508 bytes Used Flash size : 118879 bytes
Flash rodata: 177048 bytes .text: 83467 bytes
Total image size:~ 924208 bytes (.bin may be padded larger) .rodata: 35156 bytes
Total image size: 170638 bytes (.bin may be padded larger)
This output breaks down the size of all static memory regions in the firmware binary: This output breaks down the size of all static memory regions in the firmware binary:
.. list:: .. only:: esp32
- ``DRAM .data size`` is statically allocated RAM that is assigned to non-zero values at startup. This uses RAM (DRAM) at runtime and also uses space in the binary file. .. code-block:: bash
- ``DRAM .bss size`` is statically allocated RAM that is assigned zero at startup. This uses RAM (DRAM) at runtime but doesn't use any space in the binary file.
:esp32: - ``Used static DRAM`` is the total DRAM used by .data + .bss. The ``available`` size is the estimated amount of DRAM which will be available as heap memory at runtime (due to metadata overhead and implementation constraints, and heap allocations done by ESP-IDF during startup, the actual free heap at startup will be lower than this).
:esp32: - ``Used static IRAM`` is the total size of executable code :ref:`executed from IRAM <iram>`. This uses space in the binary file and also reduces {IDF_TARGET_REDUCED_BY_IRAM} available as heap memory at runtime. See :ref:`optimize-iram-usage`.
:not esp32: - ``Used static DRAM``, ``Used static IRAM`` - these options are kept for compatibility with ESP32 target, and currently read 0.
:not esp32: - ``Used stat D/IRAM`` - This is total internal RAM usage, the sum of static DRAM .data + .bss, and also static :ref:`iram` used by the application for executable code. The ``available`` size is the estimated amount of DRAM which will be available as heap memory at runtime (due to metadata overhead and implementation constraints, and heap allocations done by ESP-IDF during startup, the actual free heap at startup will be lower than this).
- ``Flash code`` is the total size of executable code executed from flash cache (:ref:`IROM <irom>`). This uses space in the binary file.
- ``Flash rodata`` is the total size of read-only data loaded from flash cache (:ref:`DROM <drom>`). This uses space in the binary file.
- ``Total image size`` is the estimated total binary file size, which is the total of all the used memory types except for .bss.
Component Usage Summary (idf.py size-components) $ idf.py size
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [...]
Total sizes:
Used static DRAM: 10608 bytes ( 170128 remain, 5.9% used)
.data size: 8464 bytes
.bss size: 2144 bytes
Used static IRAM: 48834 bytes ( 82238 remain, 37.3% used)
.text size: 47807 bytes
.vectors size: 1027 bytes
Used Flash size : 117391 bytes
.text: 80103 bytes
.rodata: 37032 bytes
Total image size: 174689 bytes (.bin may be padded larger)
The summary output provided by ``idf.py size`` does not give enough detail to find the main contributor to excessive binary size. To analyze in more detail, use ``idf.py size-components`` - ``Used static 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 size``: 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 size``: 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.
- ``Used static 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 size``: 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.
- ``Used Flash size``: Total amount of flash used (excluding usage by DRAM and IRAM)
- ``.text``: Amount of flash used for ``.text`` (i.e., all code that is executed via the flash cache, see :ref:`IROM <irom>`).
- ``.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.
.. only:: not esp32
.. code-block:: bash
$ idf.py size
[...]
Total sizes:
Used stat D/IRAM: 53743 bytes ( 122385 remain, 30.5% used)
.data size: 6504 bytes
.bss size: 1984 bytes
.text size: 44228 bytes
.vectors size: 1027 bytes
Used Flash size : 118879 bytes
.text: 83467 bytes
.rodata: 35156 bytes
Total image size: 170638 bytes (.bin may be padded larger)
- ``Used stat D/IRAM``: Total amount of D/IRAM used at compile time. ``remain`` indicates the amount of D/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 DRAM heap is smaller.
- ``.data size``: Amount of D/IRAM 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 size``: Amount of D/IRAM 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.
- ``.text size``: Amount of D/IRAM used for ``.text`` (i.e., all code that is executed from internal RAM). ``.text`` also consumes space in the binary image as the code is initially stored there and is then copied over to D/IRAM on startup.
- ``Used Flash size``: Total amount of flash used (excluding usage by D/IRAM)
- ``.text``: Amount of flash used for ``.text`` (i.e., all code that is executed via the flash cache, see :ref:`IROM <irom>`).
- ``.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 provided by ``idf.py size`` does not give enough details to find the main contributor to excessive binary size. To analyze in detail, use ``idf.py size-components``.
.. code-block:: bash .. code-block:: bash
@ -108,28 +168,28 @@ The summary output provided by ``idf.py size`` does not give enough detail to fi
libesp_eth.a 0 0 0 0 0 0 0 0 libesp_eth.a 0 0 0 0 0 0 0 0
libmesh.a 0 0 0 0 0 0 0 0 libmesh.a 0 0 0 0 0 0 0 0
The first lines of output from ``idf.py size-components`` are the same as ``idf.py size``. After this a table is printed of "per-archive contributions to ELF file". This means how much each static library archive has contributed to the final binary size. The first lines of the output from ``idf.py size-components`` are the same as that from ``idf.py size``. After this, a table is printed as ``Per-archive contributions to ELF file``. This means how much each static library archive has contributed to the final binary size.
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. 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 your project is simple and only has a "main" component, then all of the project's code will be shown under ``libmain.a``. If your project includes its own components (see :doc:`/api-guides/build-system`), then they will each be shown on a separate line. If your project is simple and only has a ``main`` component, then all of the project's code will be shown under ``libmain.a``. If your 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 to the binary size. The table is sorted in descending order of the total contribution of the static archive to the binary size.
The columns are as follows: The columns are as follows:
.. list:: .. list::
- ``DRAM .data & .bss & other`` - .data and .bss are the same as for the totals shown above (static variables, these both reduce total available RAM at runtime but .bss doesn't contribute to the binary file size). "other" is a column for any custom section types that also contribute to RAM size (usually this value is 0). - ``DRAM .data & .bss & other`` - ``.data`` and ``.bss`` are the same as for the totals shown above. Both are static variables and reduce the total available RAM at runtime, but ``.bss`` does not contribute to the binary file size. ``other`` is a column for any custom section types that also contribute to RAM size. Usually, the value is 0.
:esp32: - ``IRAM`` - is the same as for the totals shown above (code linked to execute from IRAM, uses space in the binary file and also reduces IRAM that can be dynamically allocated at runtime using ``HEAP_CAP_32BIT``. :esp32: - ``IRAM`` - is the same as for the totals shown above. It refers to code linked to execute from IRAM, which uses space in the binary file and also reduces IRAM that can be dynamically allocated at runtime using ``HEAP_CAP_32BIT``.
:esp32: - ``D/IRAM`` - Shows IRAM space which, due to occupying D/IRAM space, is also reducing available DRAM available as heap at runtime. :esp32: - ``D/IRAM`` - shows IRAM space which, due to occupying D/IRAM space, is also reducing available DRAM available as heap at runtime.
:not esp32: - ``IRAM`` - is the same as for the totals shown above (code linked to execute from IRAM, uses space in the binary file and also reduces DRAM available as heap at runtime. :not esp32: - ``IRAM`` - is the same as for the totals shown above. It refers to code linked to execute from IRAM, which uses space in the binary file and also reduces DRAM available as heap at runtime.
- ``Flash code & rodata`` - these are the same as the totals above, IROM and DROM space accessed from flash cache that contribute to the binary size. - ``Flash code & rodata`` - these are the same as the totals above, IROM and DROM space accessed from the flash cache that contribute to the binary size.
Source File Usage Summary (idf.py size-files) Source File Usage Summary ``idf.py size-files``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For even more detail, 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. 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 .. code-block:: bash
@ -178,26 +238,26 @@ For even more detail, run ``idf.py size-files`` to get a summary of the contribu
wpa.c.o 0 656 0 0 0 6828 55 7539 wpa.c.o 0 656 0 0 0 6828 55 7539
[... additional lines removed ...] [... additional lines removed ...]
After the summary of total sizes, a table of "Per-file contributions to ELF file" is printed. After the summary of total sizes, a table of ``Per-file contributions to ELF file`` is printed.
The columns are the same as shown above for ``idy.py size-components``, but this time the granularity is the contribution of each individual object file to the binary size. The columns are the same as shown above for ``idy.py size-components``, but this time the granularity is the contribution of each individual object file to the binary size.
For example, we can see that the file ``x509_crt_bundle.S.o`` contributed 64212 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. For example, we can see that the file ``x509_crt_bundle.S.o`` contributed 64,212 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 won't find a corresponding source file. To locate which component a source file belongs to, it's generally possible to search in the ESP-IDF source tree or look in the :ref:`linker-map-file` for the full path. 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 Comparing Two Binaries
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
If making some changes that affect binary size, it's possible to use an ESP-IDF tool to break down the exact differences in size. If making some changes that affect binary size, it is possible to use an ESP-IDF tool to break down the exact differences in size.
This operation isn't part of ``idf.py``, it's necessary to run the `esp_idf_size <https://github.com/espressif/esp-idf-size>`_ Python tool directly. This operation is not part of ``idf.py``, it is necessary to run the `esp_idf_size <https://github.com/espressif/esp-idf-size>`_ Python tool directly.
To do so, first locate the linker map file in the build directory. It will have the name ``PROJECTNAME.map``. The ``esp_idf_size`` tool performs its analysis based on the output of the linker map file. To do so, first, locate the linker map file with the name ``PROJECTNAME.map`` in the build directory. The ``esp_idf_size`` tool performs its analysis based on the output of the linker map file.
To compare with another binary, you will also need its corresponding ``.map`` file saved from the build directory. To compare with another binary, you also need its corresponding ``.map`` file saved from the build directory.
For example, to compare two builds: one with the default :ref:`CONFIG_COMPILER_OPTIMIZATION` setting "Debug (-Og)" configuration and one with "Optimize for size (-Os)": For example, to compare two builds, one of which with the default :ref:`CONFIG_COMPILER_OPTIMIZATION` setting ``Debug (-Og)`` configuration while another with ``Optimize for size (-Os)``:
.. code-block:: bash .. code-block:: bash
@ -214,12 +274,13 @@ For example, to compare two builds: one with the default :ref:`CONFIG_COMPILER_O
Flash rodata: 170592 bytes 176736 -6144 Flash rodata: 170592 bytes 176736 -6144
Total image size:~ 772789 bytes (.bin may be padded larger) 835553 -62764 Total image size:~ 772789 bytes (.bin may be padded larger) 835553 -62764
We can see from the "Difference" column that changing this one setting caused the whole binary to be over 60 KB smaller and over 5 KB more RAM is available. We can see from the ``Difference`` column that changing this one setting caused the whole binary to be over 60 KB smaller and over 5 KB more RAM is available.
It's also possible to use the "diff" mode to output a table of component-level (static library archive) differences: It is also possible to use the ``diff`` mode to output a table of component-level (static library archive) differences:
.. note:: .. note::
To get the output in JSON or CSV format using ``esp_idf_size`` it is possible to use the ``--format`` option.
To get the output in JSON or CSV format using ``esp_idf_size``, it is possible to use the ``--format`` option.
.. code-block:: bash .. code-block:: bash
@ -231,18 +292,18 @@ Also at the individual source file level:
python -m esp_idf_size --files --diff build_Og/https_request.map build_Oshttps_request.map python -m esp_idf_size --files --diff build_Og/https_request.map build_Oshttps_request.map
Other options (like writing the output to a file) are available, pass ``--help`` to see the full list. Other options, like writing the output to a file, are available, pass ``--help`` to see the full list.
.. _idf-size-linker-failed: .. _idf-size-linker-failed:
Showing Size When Linker Fails Showing Size When Linker Fails
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If too much static memory is used, then 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. 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 not succeed either. However it is possible to run ``esp_idf_size`` manually in order to view the *partial static memory usage* (the memory usage will miss the variables which could not be linked, so there still appears to be some free space.) In these cases, ``idf.py size`` will not succeed either. However, it is possible to run ``esp_idf_size`` manually to view the **partial static memory usage**. The memory usage will miss the variables that could not be linked, so there still appears to be some free space.
The map file argument is ``<projectname>.map`` in the build directory The map file argument is ``<projectname>.map`` in the build directory.
.. code-block:: bash .. code-block:: bash
@ -260,54 +321,81 @@ It is also possible to view the equivalent of ``size-components`` or ``size-file
Linker Map File Linker Map File
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
*This is an advanced analysis method, but it can be very useful. Feel free to skip ahead to :ref:`reducing-overall-size` and possibly come back to this later.* .. note::
The ``idf.py size`` analysis tools all work by parsing the GNU binutils "linker map file", which is a summary of everything the linker did when it created ("linked") the final firmware binary file This is an advanced analysis method, but it can be very useful. Feel free to skip ahead to :ref:`reducing-overall-size` and possibly come back to this later.
Linker map files themselves are plain text files, so it's possible to read them and find out exactly what the linker did. However, they are also very complex and long - often 100,000 or more lines! The ``idf.py size`` analysis tools all work by parsing the GNU binutils ``linker map file``, which is a summary of everything the linker did when it created (i.e., linked) the final firmware binary file.
Linker map files themselves are plain text files, so it is possible to read them and find out exactly what the linker did. However, they are also very complex and long, often exceeding 100,000 lines.
The map file itself is broken into parts and each part has a heading. The parts are: The map file itself is broken into parts and each part has a heading. The parts are:
- ``Archive member included to satisfy reference by file (symbol)``. This shows you: for each object file included in the link, what symbol (function or variable) was the linker searching for when it included that object file. If you're wondering why some object file in particular was included in the binary, this part may give a clue. This part can be used in conjunction with the ``Cross Reference Table`` at the end of the file. Note that not every object file shown in this list ends up included in the final binary, some end up in the ``Discarded input sections`` list instead. - ``Archive member included to satisfy reference by file (symbol)``
- ``Allocating common symbols`` - This is a list of (some) global variables along with their sizes. Common symbols have a particular meaning in ELF binary files, but ESP-IDF doesn't make much use of them.
- ``Discarded input sections`` - These sections were read by the linker as part of an object file to be linked into the final binary, but then nothing else referred to them so they were discarded from the final binary. For ESP-IDF this list can be very long, as we compile each function and static variable to a unique section in order to minimize the final binary size (specifically ESP-IDF uses compiler options ``-ffunction-sections -fdata-sections`` and linker option ``--gc-sections``). Items mentioned in this list *do not* contribute to the final binary.
- ``Memory Configuration``, ``Linker script and memory map`` These two parts go together. Some of the output comes directly from the linker command line and the Linker Script, both provided by the :doc:`/api-guides/build-system`. The linker script is partially generated from the ESP-IDF project using the :doc:`/api-guides/linker-script-generation` feature.
As the output of the ``Linker script and memory map`` part of the map unfolds, you can see each symbol (function or static variable) linked into the final binary along with its address (as a 16 digit hex number), its length (also in hex), and the library and object file it was linked from (which can be used to determine the component and the source file). - This shows you: for each object file included in the link, what symbol (function or variable) was the linker searching for when it included that object file.
- If you are wondering why some object file in particular was included in the binary, this part may give a clue. This part can be used in conjunction with the ``Cross Reference Table`` at the end of the file.
Following all of the output sections that take up space in the final ``.bin`` file, the ``memory map`` also includes some sections in the ELF file that are only used for debugging (ELF sections ``.debug_*``, etc.). These don't contribute to the final binary size. You'll notice the address of these symbols is a very low number (starting from 0x0000000000000000 and counting up). .. note::
- ``Cross Reference Table``. This table shows for each symbol (function or static variable), the list of object file(s) that referred to it. If you're wondering why a particular thing is included in the binary, this will help determine what included it.
Not every object file shown in this list ends up included in the final binary, some end up in the ``Discarded input sections`` list instead.
- ``Allocating common symbols``
- This is a list of some global variables along with their sizes. Common symbols have a particular meaning in ELF binary files, but ESP-IDF does not make much use of them.
- ``Discarded input sections``
- These sections were read by the linker as part of an object file to be linked into the final binary, but then nothing else referred to them, so they were discarded from the final binary.
- For ESP-IDF, this list can be very long, as we compile each function and static variable to a unique section in order to minimize the final binary size. Specifically, ESP-IDF uses compiler options ``-ffunction-sections -fdata-sections`` and linker option ``--gc-sections``.
- Items mentioned in this list **do not** contribute to the final binary.
- ``Memory Configuration``, ``Linker script and memory map``
- These two parts go together. Some of the output comes directly from the linker command line and the Linker Script, both provided by :doc:`/api-guides/build-system`. The linker script is partially generated from the ESP-IDF project using the :doc:`/api-guides/linker-script-generation` feature.
- As the output of the ``Linker script and memory map`` part of the map unfolds, you can see each symbol (function or static variable) linked into the final binary along with its address (as a 16 digit hex number), its length (also in hex), and the library and object file it was linked from (which can be used to determine the component and the source file).
- Following all of the output sections that take up space in the final ``.bin`` file, the ``memory map`` also includes some sections in the ELF file that are only used for debugging, e.g., ELF sections ``.debug_*``, etc. These do not contribute to the final binary size. You can notice the address of these symbols is a very small number, starting from ``0x0000000000000000`` and counting up.
- ``Cross Reference Table``
- This table shows the symbol (function or static variable) that the list of object file(s) refers to. If you are wondering why a particular thing is included in the binary, this will help determine what included it.
.. note::
Unfortunately, the ``Cross Reference Table`` does not only include symbols that made it into the final binary. It also includes symbols in discarded sections. Therefore, just because something is shown here does not mean that it was included in the final binary - this needs to be checked separately.
.. note:: Unfortunately, the ``Cross Reference Table`` doesn't only include symbols that made it into the final binary. It also includes symbols in discarded sections. Therefore, just because something is shown here doesn't mean that it was included in the final binary - this needs to be checked separately.
.. note:: .. note::
Linker map files are generated by the GNU binutils linker "ld", not ESP-IDF. You can find additional information online about the linker map file format. This quick summary is written from the perspective of ESP-IDF build system in particular. Linker map files are generated by the GNU binutils linker ``ld``, not ESP-IDF. You can find additional information online about the linker map file format. This quick summary is written from the perspective of ESP-IDF build system in particular.
.. _reducing-overall-size: .. _reducing-overall-size:
Reducing Overall Size Reducing Overall Size
--------------------- ---------------------
The following configuration options will reduce the final binary size of almost any ESP-IDF project: The following configuration options reduces the final binary size of almost any ESP-IDF project:
.. list:: .. list::
- Set :ref:`CONFIG_COMPILER_OPTIMIZATION` to "Optimize for size (-Os)". In some cases, "Optimize for performance (-O2)" will also reduce the binary size compared to the default. Note that if your code contains C or C++ Undefined Behaviour then increasing the compiler optimization level may expose bugs that otherwise don't happen. - Set :ref:`CONFIG_COMPILER_OPTIMIZATION` to ``Optimize for size (-Os)``. In some cases, ``Optimize for performance (-O2)`` will also reduce the binary size compared to the default. Note that if your code contains C or C++ Undefined Behavior then increasing the compiler optimization level may expose bugs that otherwise do not happen.
- Reduce the compiled-in log output by lowering the app :ref:`CONFIG_LOG_DEFAULT_LEVEL`. If the :ref:`CONFIG_LOG_MAXIMUM_LEVEL` is changed from the default then this setting controls the binary size instead. Reducing compiled-in logging reduces the number of strings in the binary, and also the code size of the calls to logging functions. - Reduce the compiled-in log output by lowering the app :ref:`CONFIG_LOG_DEFAULT_LEVEL`. If the :ref:`CONFIG_LOG_MAXIMUM_LEVEL` is changed from the default then this setting controls the binary size instead. Reducing compiled-in logging reduces the number of strings in the binary, and also the code size of the calls to logging functions.
- Set the :ref:`CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL` to "Silent". This avoids compiling in a dedicated assertion string and source file name for each assert that may fail. It's still possible to find the failed assert in the code by looking at the memory address where the assertion failed. - Set the :ref:`CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL` to ``Silent``. This avoids compiling in a dedicated assertion string and source file name for each assert that may fail. It is still possible to find the failed assert in the code by looking at the memory address where the assertion failed.
- Besides the :ref:`CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL`, you can disable or silent the assertion for HAL component separately by setting :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL`. It is to notice that ESP-IDF lowers HAL assertion level in bootloader to be silent even if :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL` is set to full-assertion level. This is to reduce the bootloader size. - Besides the :ref:`CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL`, you can disable or silent the assertion for the HAL component separately by setting :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL`. It is to notice that ESP-IDF lowers the HAL assertion level in bootloader to be silent even if :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL` is set to full-assertion level. This is to reduce the bootloader size.
- Set :ref:`CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT`. This removes specific error messages for particular internal ESP-IDF error check macros. This may make it harder to debug some error conditions by reading the log output. - Setting :ref:`CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT` removes specific error messages for particular internal ESP-IDF error check macros. This may make it harder to debug some error conditions by reading the log output.
:esp32: - If the binary needs to run on only certain revision(s) of ESP32, increasing :ref:`CONFIG_ESP32_REV_MIN` to match can result in a reduced binary size. This will make a large difference if setting ESP32 minimum revision 3, and PSRAM is enabled. :esp32: - If the binary needs to run on only certain revision(s) of ESP32, increasing :ref:`CONFIG_ESP32_REV_MIN` to match can result in a reduced binary size. This will make a large difference if setting ESP32 minimum revision 3, and PSRAM is enabled.
:esp32c3: - If the binary needs to run on only certain revision(s) of ESP32-C3, increasing :ref:`CONFIG_ESP32C3_REV_MIN` to match can result in a reduced binary size. This is particularly true if setting ESP32-C3 minimum revision 3 and using Wi-Fi, as some functionality was moved to ROM code. :esp32c3: - If the binary needs to run on only certain revision(s) of ESP32-C3, increasing :ref:`CONFIG_ESP32C3_REV_MIN` to match can result in a reduced binary size. This is particularly true if setting ESP32-C3 minimum revision 3 and using Wi-Fi, as some functionality was moved to ROM code.
- Don't enable :ref:`CONFIG_COMPILER_CXX_EXCEPTIONS`, :ref:`CONFIG_COMPILER_CXX_RTTI`, or set the :ref:`CONFIG_COMPILER_STACK_CHECK_MODE` to Overall. All of these options are already disabled by default, but they have a large impact on binary size. - Do not enable :ref:`CONFIG_COMPILER_CXX_EXCEPTIONS`, :ref:`CONFIG_COMPILER_CXX_RTTI`, or set the :ref:`CONFIG_COMPILER_STACK_CHECK_MODE` to Overall. All of these options are already disabled by default, but they have a large impact on binary size.
- Disabling :ref:`CONFIG_ESP_ERR_TO_NAME_LOOKUP` will remove the lookup table to translate user-friendly names for error values (see :doc:`/api-guides/error-handling`) in error logs, etc. This saves some binary size, but error values will be printed as integers only. - Disabling :ref:`CONFIG_ESP_ERR_TO_NAME_LOOKUP` removes the lookup table to translate user-friendly names for error values (see :doc:`/api-guides/error-handling`) in error logs, etc. This saves some binary size, but error values will be printed as integers only.
- Setting :ref:`CONFIG_ESP_SYSTEM_PANIC` to "Silent reboot" will save a small amount of binary size, however this is *only* recommended if no one will use UART output to debug the device. - Setting :ref:`CONFIG_ESP_SYSTEM_PANIC` to ``Silent reboot`` saves a small amount of binary size, however this is **only** recommended if no one will use UART output to debug the device.
:CONFIG_IDF_TARGET_ARCH_RISCV: - Set :ref:`CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS` to reduce binary size by replacing inlined prologues/epilogues with library calls. :CONFIG_IDF_TARGET_ARCH_RISCV: - Seting :ref:`CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS` reduces binary size by replacing inlined prologues/epilogues with library calls.
- If the application binary uses only one of the security versions of the protocomm component, then the support for others can be disabled to save some code size. The support can be disabled through :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0`, :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1` or :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2` respectively. - If the application binary uses only one of the security versions of the protocomm component, then the support for others can be disabled to save some code size. The support can be disabled through :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0`, :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1` or :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2` respectively.
.. note:: .. note::
In addition to the many configuration items shown here, there are a number of configuration options where changing the option from the default will increase binary size. These are not noted here. Where the increase is significant, this is usually noted in the configuration item help text. In addition to the many configuration items shown here, there are a number of configuration options where changing the option from the default increases binary size. These are not noted here. Where the increase is significant is usually noted in the configuration item help text.
.. _size-targeted-optimizations: .. _size-targeted-optimizations:
@ -321,7 +409,7 @@ The following binary size optimizations apply to a particular component or a fun
Wi-Fi Wi-Fi
@@@@@ @@@@@
- Disabling :ref:`CONFIG_ESP_WIFI_ENABLE_WPA3_SAE` will save some Wi-Fi binary size if WPA3 support is not needed. (Note that WPA3 is mandatory for new Wi-Fi device certifications.) - Disabling :ref:`CONFIG_ESP_WIFI_ENABLE_WPA3_SAE` will save some Wi-Fi binary size if WPA3 support is not needed. Note that WPA3 is mandatory for new Wi-Fi device certifications.
- Disabling :ref:`CONFIG_ESP_WIFI_SOFTAP_SUPPORT` will save some Wi-Fi binary size if soft-AP support is not needed. - Disabling :ref:`CONFIG_ESP_WIFI_SOFTAP_SUPPORT` will save some Wi-Fi binary size if soft-AP support is not needed.
.. only:: esp32 .. only:: esp32
@ -336,28 +424,28 @@ The following binary size optimizations apply to a particular component or a fun
Bluetooth NimBLE Bluetooth NimBLE
@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@
If using :doc:`NimBLE Bluetooth Host </api-reference/bluetooth/nimble/index>` then the following modifications can reduce binary size: If using :doc:`/api-reference/bluetooth/nimble/index` then the following modifications can reduce binary size:
.. list:: .. list::
:esp32: - Set :ref:`CONFIG_BTDM_CTRL_BLE_MAX_CONN` to 1 if only one BLE connection is needed. :esp32: - Set :ref:`CONFIG_BTDM_CTRL_BLE_MAX_CONN` to 1 if only one Bluetooth LE connection is needed.
- :ref:`CONFIG_BT_NIMBLE_MAX_CONNECTIONS` to 1 if only one BLE connection is needed. - Set :ref:`CONFIG_BT_NIMBLE_MAX_CONNECTIONS` to 1 if only one Bluetooth LE connection is needed.
- Disable either :ref:`CONFIG_BT_NIMBLE_ROLE_CENTRAL` or :ref:`CONFIG_BT_NIMBLE_ROLE_OBSERVER` if these roles are not needed. - Disable either :ref:`CONFIG_BT_NIMBLE_ROLE_CENTRAL` or :ref:`CONFIG_BT_NIMBLE_ROLE_OBSERVER` if these roles are not needed.
- Reducing :ref:`CONFIG_BT_NIMBLE_LOG_LEVEL` can reduce binary size. Note that if the overall log level has been reduced as described above in :ref:`reducing-overall-size` then this also reduces the NimBLE log level. - Reducing :ref:`CONFIG_BT_NIMBLE_LOG_LEVEL` can reduce binary size. Note that if the overall log level has been reduced as described above in :ref:`reducing-overall-size` then this also reduces the NimBLE log level.
lwIP IPv6 lwIP IPv6
@@@@@@@@@ @@@@@@@@@
- Setting :ref:`CONFIG_LWIP_IPV6` to false will reduce the size of the lwIP TCP/IP stack, at the cost of only supporting IPv4. - Setting :ref:`CONFIG_LWIP_IPV6` to ``false`` will reduce the size of the lwIP TCP/IP stack, at the cost of only supporting IPv4.
.. note:: .. note::
IPv6 is required by some components such as ``coap`` and :doc:`/api-reference/protocols/asio`, These components will not be available if IPV6 is disabled. IPv6 is required by some components such as ``coap`` and :doc:`/api-reference/protocols/asio`. These components will not be available if IPV6 is disabled.
lwIP IPv4 lwIP IPv4
@@@@@@@@@ @@@@@@@@@
- If IPv4 connectivity is not required, setting :ref:`CONFIG_LWIP_IPV4` to false will reduce the size of the lwIP, supporting IPv6 only TCP/IP stack. - If IPv4 connectivity is not required, setting :ref:`CONFIG_LWIP_IPV4` to ``false`` will reduce the size of the lwIP, supporting IPv6-only TCP/IP stack.
.. note:: .. note::
@ -365,41 +453,41 @@ lwIP IPv4
.. _newlib-nano-formatting: .. _newlib-nano-formatting:
Newlib nano formatting Newlib Nano Formatting
@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@
By default, ESP-IDF uses newlib "full" formating for I/O (printf, scanf, etc.) By default, ESP-IDF uses Newlib "full" formatting for I/O functions (``printf()``, ``scanf()``, etc.)
.. only:: CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT .. only:: CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT
Enabling the config option :ref:`CONFIG_NEWLIB_NANO_FORMAT` will switch newlib to the "nano" formatting mode. This both smaller in code size and a large part of the implementation is compiled into the {IDF_TARGET_NAME} ROM, so it doesn't need to be included in the binary at all. Enabling the config option :ref:`CONFIG_NEWLIB_NANO_FORMAT` will switch Newlib to the “Nano” formatting mode. This is smaller in code size, and a large part of the implementation is compiled into the {IDF_TARGET_NAME} ROM, so it does not need to be included in the binary at all.
The exact difference in binary size depends on which features the firmware uses, but 25 KB ~ 50 KB is typical. The exact difference in binary size depends on which features the firmware uses, but 25 KB ~ 50 KB is typical.
.. only:: CONFIG_ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT .. only:: CONFIG_ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT
Disabling the config option :ref:`CONFIG_NEWLIB_NANO_FORMAT` will switch newlib to the "full" formatting mode. This will reduce the binary size, as {IDF_TARGET_NAME} has the full formatting version of the functions in ROM, so it doesn't need to be included in the binary at all. Disabling the config option :ref:`CONFIG_NEWLIB_NANO_FORMAT` will switch Newlib to the "full" formatting mode. This will reduce the binary size, as {IDF_TARGET_NAME} has the full formatting version of the functions in ROM, so it does not need to be included in the binary at all.
Enabling Nano formatting reduces the stack usage of each function that calls printf() or another string formatting function, see :ref:`optimize-stack-sizes`. Enabling "Nano" formatting reduces the stack usage of each function that calls ``printf()`` or another string formatting function, see :ref:`optimize-stack-sizes`.
"Nano" formatting doesn't support 64-bit integers, or C99 formatting features. For a full list of restrictions, search for ``--enable-newlib-nano-formatted-io`` in the `Newlib README file`_. "Nano" formatting does not support 64-bit integers, or C99 formatting features. For a full list of restrictions, search for ``--enable-newlib-nano-formatted-io`` in the `Newlib README file`_.
.. only:: esp32c2 .. only:: esp32c2
.. note:: .. note::
:ref:`CONFIG_NEWLIB_NANO_FORMAT` is enabled by default on {IDF_TARGET_NAME} :ref:`CONFIG_NEWLIB_NANO_FORMAT` is enabled by default on {IDF_TARGET_NAME}.
.. _Newlib README file: https://sourceware.org/newlib/README .. _Newlib README file: https://sourceware.org/newlib/README
.. _minimizing_binary_mbedtls: .. _minimizing_binary_mbedtls:
mbedTLS features MbedTLS Features
@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@
Under *Component Config* -> *mbedTLS* there are multiple mbedTLS features which are enabled by default but can be disabled if not needed to save code size. Under **Component Config** > **mbedTLS**, there are multiple mbedTLS features enabled default, some of which can be disabled if not needed to save code size.
These include: These include:
@ -415,32 +503,32 @@ These include:
- :ref:`CONFIG_MBEDTLS_GCM_C` - :ref:`CONFIG_MBEDTLS_GCM_C`
- :ref:`CONFIG_MBEDTLS_ECP_C` (Alternatively: Leave this option enabled but disable some of the elliptic curves listed in the sub-menu.) - :ref:`CONFIG_MBEDTLS_ECP_C` (Alternatively: Leave this option enabled but disable some of the elliptic curves listed in the sub-menu.)
- Change :ref:`CONFIG_MBEDTLS_TLS_MODE` if both server & client functionalities are not needed - Change :ref:`CONFIG_MBEDTLS_TLS_MODE` if both server & client functionalities are not needed
- Consider disabling some ciphersuites listed in the "TLS Key Exchange Methods" sub-menu (i.e. :ref:`CONFIG_MBEDTLS_KEY_EXCHANGE_RSA`) - Consider disabling some cipher suites listed in the ``TLS Key Exchange Methods`` sub-menu (i.e. :ref:`CONFIG_MBEDTLS_KEY_EXCHANGE_RSA`)
The help text for each option has some more information. The help text for each option has some more information for reference.
.. important:: .. important::
It is **strongly not recommended to disable all these mbedTLS options**. Only disable options where you understand the functionality and are certain that it is not needed in the application. In particular: It is **strongly not recommended to disable all these mbedTLS options**. Only disable options of which you understand the functionality and are certain that it is not needed in the application. In particular:
- Ensure that any TLS server(s) the device connects to can still be used. If the server is controlled by a third party or a cloud service, recommend ensuring that the firmware supports at least two of the supported cipher suites in case one is disabled in a future update. - Ensure that any TLS server(s) the device connects to can still be used. If the server is controlled by a third party or a cloud service, it is recommended to ensure that the firmware supports at least two of the supported cipher suites in case one is disabled in a future update.
- Ensure that any TLS client(s) that connect to the device can still connect with supported/recommended cipher suites. Note that future versions of client operating systems may remove support for some features, so it is recommended to enable multiple supported cipher suites or algorithms for redundancy. - Ensure that any TLS client(s) that connect to the device can still connect with supported/recommended cipher suites. Note that future versions of client operating systems may remove support for some features, so it is recommended to enable multiple supported cipher suites, or algorithms for redundancy.
If depending on third party clients or servers, always pay attention to announcements about future changes to supported TLS features. If not, the {IDF_TARGET_NAME} device may become inaccessible if support changes. If depending on third party clients or servers, always pay attention to announcements about future changes to supported TLS features. If not, the {IDF_TARGET_NAME} device may become inaccessible if support changes.
.. note:: .. note::
Not every combination of mbedTLS compile-time config is tested in ESP-IDF. If you find a combination that fails to compile or function as expected, please report the details on GitHub. Not every combination of mbedTLS compile-time config is tested in ESP-IDF. If you find a combination that fails to compile or function as expected, please report the details on `GitHub <https://github.com/espressif/esp-idf>`_.
VFS VFS
@@@ @@@
:doc:`Virtual filesystem </api-reference/storage/vfs>` feature in ESP-IDF allows multiple filesystem drivers and file-like peripheral drivers to be accessed using standard I/O functions (``open``, ``read``, ``write``, etc.) and C library functions (``fopen``, ``fread``, ``fwrite``, etc.). When filesystem or file-like peripheral driver functionality is not used in the application this feature can be fully or partially disabled. VFS component provides the following configuration options: :doc:`/api-reference/storage/vfs` feature in ESP-IDF allows multiple filesystem drivers and file-like peripheral drivers to be accessed using standard I/O functions (``open``, ``read``, ``write``, etc.) and C library functions (``fopen``, ``fread``, ``fwrite``, etc.). When filesystem or file-like peripheral driver functionality is not used in the application, this feature can be fully or partially disabled. VFS component provides the following configuration options:
* :ref:`CONFIG_VFS_SUPPORT_TERMIOS` — can be disabled if the application doesn't use ``termios`` family of functions. Currently, these functions are implemented only for UART VFS driver. Most applications can disable this option. Disabling this option reduces the code size by about 1.8 kB. * :ref:`CONFIG_VFS_SUPPORT_TERMIOS` — can be disabled if the application does not use ``termios`` family of functions. Currently, these functions are implemented only for UART VFS driver. Most applications can disable this option. Disabling this option reduces the code size by about 1.8 KB.
* :ref:`CONFIG_VFS_SUPPORT_SELECT` can be disabled if the application doesn't use ``select`` function with file descriptors. Currently, only the UART and eventfd VFS drivers implement ``select`` support. Note that when this option is disabled, ``select`` can still be used for socket file descriptors. Disabling this option reduces the code size by about 2.7 kB. * :ref:`CONFIG_VFS_SUPPORT_SELECT` can be disabled if the application does not use the ``select`` function with file descriptors. Currently, only the UART and eventfd VFS drivers implement ``select`` support. Note that when this option is disabled, ``select`` can still be used for socket file descriptors. Disabling this option reduces the code size by about 2.7 KB.
* :ref:`CONFIG_VFS_SUPPORT_DIR` — can be disabled if the application doesn't use directory related functions, such as ``readdir`` (see the description of this option for the complete list). Applications which only open, read and write specific files and don't need to enumerate or create directories can disable this option, reducing the code size by 0.5 kB or more, depending on the filesystem drivers in use. * :ref:`CONFIG_VFS_SUPPORT_DIR` — can be disabled if the application does not use directory-related functions, such as ``readdir`` (see the description of this option for the complete list). Applications that only open, read and write specific files and do not need to enumerate or create directories can disable this option, reducing the code size by 0.5 KB or more, depending on the filesystem drivers in use.
* :ref:`CONFIG_VFS_SUPPORT_IO` — can be disabled if the application doesn't use filesystems or file-like peripheral drivers. This disables all VFS functionality, including the three options mentioned above. When this option is disabled, :doc:`console </api-reference/system/console>` can't be used. Note that the application can still use standard I/O functions with socket file descriptors when this option is disabled. Compared to the default configuration, disabling this option reduces code size by about 9.4 kB. * :ref:`CONFIG_VFS_SUPPORT_IO` — can be disabled if the application does not use filesystems or file-like peripheral drivers. This disables all VFS functionality, including the three options mentioned above. When this option is disabled, :doc:`/api-reference/system/console` can not be used. Note that the application can still use standard I/O functions with socket file descriptors when this option is disabled. Compared to the default configuration, disabling this option reduces code size by about 9.4 KB.
.. only:: CONFIG_ESP_ROM_HAS_HAL_SYSTIMER or CONFIG_ESP_ROM_HAS_HAL_WDT .. only:: CONFIG_ESP_ROM_HAS_HAL_SYSTIMER or CONFIG_ESP_ROM_HAS_HAL_WDT

View File

@ -1,2 +1,563 @@
.. include:: ../../../en/api-guides/performance/size.rst 最小化二进制文件大小
===============================
:link_to_translation:`en:[English]`
{IDF_TARGET_REDUCED_BY_IRAM: default="DRAM", esp32="IRAM 和/或 DRAM取决于大小"}
ESP-IDF 构建系统会编译项目和 ESP-IDF 中所有源文件,但只有程序实际引用的函数和变量才会链接到最终的二进制文件中。在某些情况下,需要减小固件二进制文件的总大小,例如,为使固件适配 flash 分区大小。
要减小固件二进制文件总大小,首先要找到导致其大小增加的原因。
.. _idf.py-size:
测量静态数据大小
---------------------------
为了优化固件二进制文件大小和内存使用,需要测量项目中静态分配的 RAM (``data``, ``bss``),代码 (``text``) 和只读数据 (``rodata``)。
使用 :ref:`idf.py` 的子命令 ``size`` ``size-components````size-files`` 可以输出项目使用内存概况:
.. note::
添加 ``-DOUTPUT_FORMAT=csv````-DOUTPUT_FORMAT=json``,即可用 CSV 或 JSON 格式输出文件。
数据大小概况 ``idf.py size``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. only:: esp32
.. code-block:: bash
$ idf.py size
[...]
Total sizes:
Used static DRAM: 10608 bytes ( 170128 remain, 5.9% used)
.data size: 8464 bytes
.bss size: 2144 bytes
Used static IRAM: 48834 bytes ( 82238 remain, 37.3% used)
.text size: 47807 bytes
.vectors size: 1027 bytes
Used Flash size : 117391 bytes
.text: 80103 bytes
.rodata: 37032 bytes
Total image size: 174689 bytes (.bin may be padded larger)
.. only:: not esp32
.. code-block:: bash
$ idf.py size
[...]
Total sizes:
Used stat D/IRAM: 53743 bytes ( 122385 remain, 30.5% used)
.data size: 6504 bytes
.bss size: 1984 bytes
.text size: 44228 bytes
.vectors size: 1027 bytes
Used Flash size : 118879 bytes
.text: 83467 bytes
.rodata: 35156 bytes
Total image size: 170638 bytes (.bin may be padded larger)
该输出结果细分了固件二进制文件中所有静态内存区域的大小:
.. only:: esp32
.. code-block:: bash
$ idf.py size
[...]
Total sizes:
Used static DRAM: 10608 bytes ( 170128 remain, 5.9% used)
.data size: 8464 bytes
.bss size: 2144 bytes
Used static IRAM: 48834 bytes ( 82238 remain, 37.3% used)
.text size: 47807 bytes
.vectors size: 1027 bytes
Used Flash size : 117391 bytes
.text: 80103 bytes
.rodata: 37032 bytes
Total image size: 174689 bytes (.bin may be padded larger)
- ``Used static DRAM``:编译时分配的 DRAM 大小。 ``remain`` 表示在运行时可用作堆内存的 DRAM 余量。请注意,由于元数据开销、实现限制和启动时的堆分配,实际的 DRAM 堆会更小。
- ``.data size``:编译时为 ``.data`` (即所有初始化值为非零值的静态变量)分配的 DRAM 大小。 ``.data`` 还在二进制映像中占用空间来存储非零初始化值。
- ``.bss size``:编译时为 ``.bss`` (即所有初始化值为零的静态变量)分配的 DRAM 大小。``.bss`` 不会在 flash 中占用额外空间。
- ``Used static IRAM``:编译时分配的 IRAM 大小。 ``remain`` 表示在运行时可用作堆内存的 IRAM 余量。请注意,由于元数据开销、实现限制和启动时的堆分配,实际的 IRAM 堆会更小。
- ``.text size``:用于 ``.text`` 的 IRAM 大小(即所有从 :ref:`IRAM <iram>` 执行的代码)。由于代码最初存储在 ``.text`` 中,在启动时才会复制到 IRAM因此 ``.text`` 在二进制映像中也会占用空间。
- ``Used Flash size``:使用的 flash 大小(不包括 DRAM 和 IRAM 的使用量)。
- ``.text``:用于 ``.text`` (即通过 flash 缓存执行的所有代码,请参阅 :ref:`IROM <irom>`)的 flash 大小。
- ``.rodata``:用于 ``.rodata`` (即通过 flash 缓存加载的只读数据,参阅 :ref:`DROM <drom>`)的 flash 大小。
- ``Total image size`` 是二进制文件的预估总大小。
.. only:: not esp32
.. code-block:: bash
$ idf.py size
[...]
Total sizes:
Used stat D/IRAM: 53743 bytes ( 122385 remain, 30.5% used)
.data size: 6504 bytes
.bss size: 1984 bytes
.text size: 44228 bytes
.vectors size: 1027 bytes
Used Flash size : 118879 bytes
.text: 83467 bytes
.rodata: 35156 bytes
Total image size: 170638 bytes (.bin may be padded larger)
- ``Used stat D/IRAM``:编译时使用的 D/IRAM 大小。``remain`` 表示在运行时可用作堆内存的 D/IRAM 余量。请注意,由于元数据开销、实现限制和启动时的堆分配,实际的 DRAM 堆会更小。
- ``.data size``:编译时为 ``.data`` (即所有初始化值为非零值的静态变量)分配的 D/IRAM 大小。 ``.data`` 还在二进制映像中占用空间来存储非零初始化值。
- ``.bss size``:编译时为 ``.bss`` (即所有初始化值为零的静态变量)分配的 D/IRAM 大小。``.bss`` 不会在 flash 中占用额外空间。
- ``.text size``:用于 ``.text`` 的 D/IRAM 大小(即所有从内部 RAM 执行的代码)。由于代码最初存储在 ``.text`` 中,在启动时才会复制到 D/IRAM因此 ``.text`` 在二进制映像中也会占用空间。
- ``Used Flash size``:使用的 flash 总大小(不包括 D/IRAM 的使用量)。
- ``.text``:用于 ``.text`` (即通过 flash 缓存执行的所有代码,请参阅 :ref:`IROM <irom>`)的 flash 大小。
- ``.rodata``:用于 ``.rodata`` (即通过 flash 缓存加载的只读数据,参阅 :ref:`DROM <drom>`)的 flash 大小。
- ``Total image size`` is the estimated total size of the binary file.
组件使用概况 ``idf.py size-components``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
``idf.py size`` 的输出结果不够详细,无法找出导致二进制文件过大的主要原因。要进行更详细的分析,请使用 ``idf.py size-components``
.. code-block:: bash
$ idf.py size-components
[...]
Total sizes:
DRAM .data size: 14956 bytes
DRAM .bss size: 15808 bytes
Used static DRAM: 30764 bytes ( 149972 available, 17.0% used)
Used static IRAM: 83918 bytes ( 47154 available, 64.0% used)
Flash code: 559943 bytes
Flash rodata: 176736 bytes
Total image size:~ 835553 bytes (.bin may be padded larger)
Per-archive contributions to ELF file:
Archive File DRAM .data & .bss & other IRAM D/IRAM Flash code & rodata Total
libnet80211.a 1267 6044 0 5490 0 107445 18484 138730
liblwip.a 21 3838 0 0 0 97465 16116 117440
libmbedtls.a 60 524 0 0 0 27655 69907 98146
libmbedcrypto.a 64 81 0 30 0 76645 11661 88481
libpp.a 2427 1292 0 20851 0 37208 4708 66486
libc.a 4 0 0 0 0 57056 6455 63515
libphy.a 1439 715 0 7798 0 33074 0 43026
libwpa_supplicant.a 12 848 0 0 0 35505 1446 37811
libfreertos.a 3104 740 0 15711 0 367 4228 24150
libnvs_flash.a 0 24 0 0 0 14347 2924 17295
libspi_flash.a 1562 294 0 8851 0 1840 1913 14460
libesp_system.a 245 206 0 3078 0 5990 3817 13336
libesp-tls.a 0 4 0 0 0 5637 3524 9165
[... removed some lines here ...]
libesp_rom.a 0 0 0 112 0 0 0 112
libcxx.a 0 0 0 0 0 47 0 47
(exe) 0 0 0 3 0 3 12 18
libesp_pm.a 0 0 0 0 0 8 0 8
libesp_eth.a 0 0 0 0 0 0 0 0
libmesh.a 0 0 0 0 0 0 0 0
``idf.py size-components`` 输出的前几行与 ``idf.py size`` 相同,此外还会输出 ``Per-archive contributions to ELF file`` 表格,显示每个静态库对最终二进制文件大小的贡献程度。
通常,每个组件都会构建一个静态库归档文件,尽管部分是由特定组件包含的二进制库,例如, ``esp_wifi`` 组件包含了 ``libnet80211.a``。此外,这里还列出了一些工具链库,例如 ``libc.a````libgcc.a``,用于提供 C/C++ 标准库和工具链内置功能。
对于只有一个 ``main`` 组件的简单项目,可在 ``libmain.a`` 目录下找到所有项目代码。若项目包含其特有组件(参阅 :doc:`/api-guides/build-system`),则每个组件将单独在一行中显示。
该表格按静态库归档文件对最终二进制文件大小的贡献程度降序排序。
各列含义如下:
.. list::
- ``DRAM .data & .bss & other`` - ``.data````.bss`` 分别与上方显示的总数相同。两者都是静态变量,且都会减少运行时的可用 RAM``.bss`` 不会增加二进制文件大小。 ``other`` 列指任何会增加 RAM 大小的自定义数据段,该值通常为 0。
:esp32: - ``IRAM`` - 该列与上方显示的总数相同,表示链接到从 IRAM 执行的代码,这些代码占用二进制文件空间,并且会减少执行 ``HEAP_CAP_32BIT`` 时可动态分配的 IRAM。
:esp32: - ``D/IRAM`` - 显示了 IRAM 占用的空间。D/IRAM 占用的空间会减少运行时可用作堆内存的 DRAM 空间。
:not esp32: - ``IRAM`` - 与上方显示的总数相同,表示链接到从 IRAM 执行的代码,这些代码占用二进制文件空间,并且会减少运行时可用作堆内存的 DRAM 空间。
- ``Flash code & rodata`` - 这些值与上方显示总数相同,指通过 flash 缓存访问的 IROM 和 DROM 空间,对二进制文件大小的贡献。
源文件使用概况 ``idf.py size-files``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
要了解更多详情,请运行 ``idf.py size-files``,获取每个目标文件对最终二进制文件大小的贡献概况。每个目标文件对应一个单独的源文件。
.. code-block:: bash
$ idf.py size-files
[...]
Total sizes:
DRAM .data size: 14956 bytes
DRAM .bss size: 15808 bytes
Used static DRAM: 30764 bytes ( 149972 available, 17.0% used)
Used static IRAM: 83918 bytes ( 47154 available, 64.0% used)
Flash code: 559943 bytes
Flash rodata: 176736 bytes
Total image size:~ 835553 bytes (.bin may be padded larger)
Per-file contributions to ELF file:
Object File DRAM .data & .bss & other IRAM D/IRAM Flash code & rodata Total
x509_crt_bundle.S.o 0 0 0 0 0 0 64212 64212
wl_cnx.o 2 3183 0 221 0 13119 3286 19811
phy_chip_v7.o 721 614 0 1642 0 16820 0 19797
ieee80211_ioctl.o 740 96 0 437 0 15325 2627 19225
pp.o 1142 45 0 8871 0 5030 537 15625
ieee80211_output.o 2 20 0 2118 0 11617 914 14671
ieee80211_sta.o 1 41 0 1498 0 10858 2218 14616
lib_a-vfprintf.o 0 0 0 0 0 13829 752 14581
lib_a-svfprintf.o 0 0 0 0 0 13251 752 14003
ssl_tls.c.o 60 0 0 0 0 12769 463 13292
sockets.c.o 0 648 0 0 0 11096 1030 12774
nd6.c.o 8 932 0 0 0 11515 314 12769
phy_chip_v7_cal.o 477 53 0 3499 0 8561 0 12590
pm.o 32 364 0 2673 0 7788 782 11639
ieee80211_scan.o 18 288 0 0 0 8889 1921 11116
lib_a-svfiprintf.o 0 0 0 0 0 9654 1206 10860
lib_a-vfiprintf.o 0 0 0 0 0 10069 734 10803
ieee80211_ht.o 0 4 0 1186 0 8628 898 10716
phy_chip_v7_ana.o 241 48 0 2657 0 7677 0 10623
bignum.c.o 0 4 0 0 0 9652 752 10408
tcp_in.c.o 0 52 0 0 0 8750 1282 10084
trc.o 664 88 0 1726 0 6245 1108 9831
tasks.c.o 8 704 0 7594 0 0 1475 9781
ecp_curves.c.o 28 0 0 0 0 7384 2325 9737
ecp.c.o 0 64 0 0 0 8864 286 9214
ieee80211_hostap.o 1 41 0 0 0 8578 585 9205
wdev.o 121 125 0 4499 0 3684 580 9009
tcp_out.c.o 0 0 0 0 0 5686 2161 7847
tcp.c.o 2 26 0 0 0 6161 1617 7806
ieee80211_input.o 0 0 0 0 0 6797 973 7770
wpa.c.o 0 656 0 0 0 6828 55 7539
[... additional lines removed ...]
文件总大小概况下方会显示 ``Per-file contributions to ELF file`` 表格。
该表格的列与上文运行 ``idy.py size-components`` 显示的列相同,但该表格的粒度更细,展示了每个目标文件对二进制文件大小的贡献。
例如,文件 ``x509_crt_bundle.S.o`` 对总固件大小贡献了 64,212 字节,全都存储在 flash 中的 ``.rodata`` 区域。由此可以推知,该应用程序正在使用 :doc:`/api-reference/protocols/esp_crt_bundle` 功能。如果不使用该功能,固件大小至少可以减少 64,212 字节。
某些目标文件从二进制库中链接至此,因此无法找到对应源文件。要确定一个源文件属于哪个组件,通常可以在 ESP-IDF 源代码树中搜索,或者在 :ref:`linker-map-file` 中查找完整路径。
比较两个二进制文件
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
如果某些改动影响了二进制文件大小,可以使用 ESP-IDF 工具来详细分析文件大小的确切差异。
该操作不是通过运行 ``idf.py`` 进行的,而是需要直接运行 Python 工具 `esp_idf_size <https://github.com/espressif/esp-idf-size>`_
执行该操作,首先需要在构建目录中找到链接器映射文件 ``PROJECTNAME.map````esp_idf_size`` 工具会基于链接器映射文件的输出结果分析文件大小差异。
要与另一个二进制文件进行比较,还需要保存该文件对应的 ``.map`` 文件,该文件位于构建目录中。
例如,要比较两个构建文件,其中一个使用默认的 :ref:`CONFIG_COMPILER_OPTIMIZATION` ``Debug (-Og)`` 配置,而另一个使用 ``Optimize for size (-Os)`` 配置:
.. code-block:: bash
$ python -m esp_idf_size --diff build_Og/https_request.map build_Os/https_request.map
<CURRENT> MAP file: build_Os/https_request.map
<REFERENCE> MAP file: build_Og/https_request.map
Difference is counted as <CURRENT> - <REFERENCE>, i.e. a positive number means that <CURRENT> is larger.
Total sizes of <CURRENT>: <REFERENCE> Difference
DRAM .data size: 14516 bytes 14956 -440
DRAM .bss size: 15792 bytes 15808 -16
Used static DRAM: 30308 bytes ( 150428 available, 16.8% used) 30764 -456 ( +456 available, +0 total)
Used static IRAM: 78498 bytes ( 52574 available, 59.9% used) 83918 -5420 ( +5420 available, +0 total)
Flash code: 509183 bytes 559943 -50760
Flash rodata: 170592 bytes 176736 -6144
Total image size:~ 772789 bytes (.bin may be padded larger) 835553 -62764
``Difference`` 列可以看出,改变该设置导致整个二进制文件减小了 60 KB 以上,并且可用的 RAM 增加了 5 KB 以上。
还可以使用 ``diff`` 模式来输出表格,显示组件级(静态库)的差异:
.. note::
运行 ``esp_idf_size`` 时可以使用 ``--format`` 选项输出 JSON 或 CSV 格式的结果。
.. code-block:: bash
python -m esp_idf_size --archives --diff build_Og/https_request.map build_Oshttps_request.map
同样适用于比较单个源文件级的差异:
.. code-block:: bash
python -m esp_idf_size --files --diff build_Og/https_request.map build_Oshttps_request.map
了解将输出写入文件等其他选项,可以输入 ``--help`` 查看完整列表。
.. _idf-size-linker-failed:
链接器失败时显示文件大小
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
如果被分配的静态内存大小超越上限,链接器会失败并显示错误信息,例如 ``DRAM segment data does not fit````region `iram0_0_seg' overflowed by 44 bytes`` 等。
在这些情况下, ``idf.py size`` 也无法成功执行。然而,通过手动运行 ``esp_idf_size``,可以查看 **部分静态内存使用情况** 。内存使用情况将不包含无法链接的变量,因此仍然会显示有部分可用空间。
映射文件参数为构建目录下的 ``<projectname>.map`` 文件。
.. code-block:: bash
python -m esp_idf_size build/project_name.map
还可以查看类似于 ``size-components````size-files`` 输出的内容:
.. code-block:: bash
python -m esp_idf_size --archives build/project_name.map
python -m esp_idf_size --files build/project_name.map
.. _linker-map-file:
链接器映射文件
^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. note::
这是一种非常有用的进阶分析方法。可以先跳转到 :ref:`reducing-overall-size`,以后再详阅这一部分。
分析工具 ``idf.py size`` 通过解析 GNU binutils 的“链接器映射文件”来输出结果,该文件囊括了链接器在创建(即链接到)最终固件二进制文件时的所有操作。
链接器映射文件本身是纯文本文件,因此可以进行读取并准确了解链接器的操作,但这些文件非常复杂冗长,通常有 100,000 行甚至更多。
映射文件分为多个部分,每个部分各有标题,包括:
- ``Archive member included to satisfy reference by file (symbol)``
- 该列表显示了链接器链接各个目标文件时所搜寻的特定符号(函数或变量)。
- 要了解二进制文件包含特定目标文件的原因,可以查看该列表以及文件末尾的 ``Cross Reference Table``
.. note::
请注意,并非每个显示在该列表中的目标文件最后都会出现在最终二进制文件中,有些目标文件可能会列在 ``Discarded input sections`` 中。
- ``Allocating common symbols``
- 该列表显示了部分全局变量及其大小。常见符号在 ELF 二进制文件中具有特定含义,但 ESP-IDF 并未广泛使用这些符号。
- ``Discarded input sections``
- 在链接器读取目标文件时,会将一些输入段作为文件的一部分读取并准备链接到最终的二进制文件中,但由于没有其他部分引用这些输入段,这些段最终会被丢弃。
- 对于 ESP-IDF 项目来说这个列表可能会非常长因为我们将每个函数和静态变量都编译到一个独立的段中以最小化最终二进制文件的大小。具体而言ESP-IDF 将使用编译器选项 ``-ffunction-sections -fdata-sections`` 和链接器选项 ``--gc-sections``
- 在这个列表中出现的条目 **不会** 对最终的二进制文件大小产生影响。
- ``Memory Configuration````Linker script and memory map``
- 这两部分相互关联。输出结果的一部分来自由 :doc:`/api-guides/build-system` 提供的链接器命令行和链接脚本,部分链接脚本由 ESP-IDF 项目通过 :doc:`/api-guides/linker-script-generation` 功能生成。
- 在 map 文件的 ``Linker script and memory map`` 输出中,会显示链接到最终二进制文件中的每个符号(函数或静态变量)及其地址(以 16 位十六进制数字表示)和长度(也以十六进制表示),还有链接的库和目标文件(可以用于确定组件和源文件)。
- 在所有占用最终 ``.bin`` 文件的输出段之后, ``memory map`` 还会显示一些 ELF 文件中用于调试的段,如 ``.debug_*`` 等。这些段不会对最终的二进制文件大小产生影响,且这些符号的地址数值很小,从 ``0x0000000000000000`` 开始递增。
- ``Cross Reference Table``
- 该表格显示了引用了各个符号(函数或静态变量)的目标文件。了解二进制文件包含某个特定符号的原因,可参考该表格以确定引用特定符号的目标文件。
.. note::
``Cross Reference Table`` 不仅包含最终二进制文件中的符号,还包含已丢弃的段内符号。因此,某个符号出现在该表中并不意味着最终二进制文件包含这一符号,需要单独检查。
.. note::
链接器映射文件由 GNU binutils 的链接器 ``ld`` 而非由 ESP-IDF 生成。本快速概览专从 ESP-IDF 构建系统的角度编写而成,建议自行搜索更多关于链接器映射文件格式的信息。
.. _reducing-overall-size:
减小总体文件大小
-------------------------------
可以通过以下配置选项减小几乎所有 ESP-IDF 项目最终二进制文件的大小:
.. list::
- 将 :ref:`CONFIG_COMPILER_OPTIMIZATION` 设置为 ``Optimize for size (-Os)``。在某些情况下,相较于默认设置, ``Optimize for size (-Os)`` 也可以减小二进制文件的大小。请注意,若代码包含 C 或 C++ 的未定义行为,提高编译器优化级别可能会暴露出原本不存在的错误。
- 通过降低应用程序的 :ref:`CONFIG_LOG_DEFAULT_LEVEL` ,可以减少编译时的日志输出。如果改变 :ref:`CONFIG_LOG_MAXIMUM_LEVEL` 的默认选项,则可以控制二进制文件的大小。减少编译时的日志输出可以减少二进制文件中的字符串数量,并减小调用日志函数的代码大小。
- 将 :ref:`CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL` 设置为 ``Silent``,可以避免为所有可能失败的断言编译专门的断言字符串和源文件名。尽管如此,仍可以通过查看断言失败时的内存地址以在代码中找到失败断言。
- 除 :ref:`CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL` 外,还可以通过设置 :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL` 单独禁用或静默 HAL 组件的断言。请注意,即使将 :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL` 设置为 full-assertion 级别ESP-IDF 在引导加载程序中也会把 HAL 断言级别降为 silent以减小引导加载程序的大小。
- 设置 :ref:`CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT` 会移除针对 ESP-IDF 内部错误检查宏的特定错误消息。错误消息移除后,通过阅读日志输出来调试某些错误条件可能变得更加困难。
:esp32: - 如果二进制文件只需要在某些特定的 ESP32 版本上运行,将 :ref:`CONFIG_ESP32_REV_MIN` 增加到相应版本的匹配值可以减小二进制文件的大小。如果设置 ESP32 最低版本为 3并且启用 PSRAM将大幅减小二进制文件的大小。
:esp32c3: - 如果二进制文件只需要在某些特定的 ESP32-C3 版本上运行,将 :ref:`CONFIG_ESP32C3_REV_MIN` 增加到相应版本的匹配值可以减小二进制文件的大小。由于某些功能已经移至 ROM 代码中,如果设置 ESP32-C3 最低版本为 3 并且使用 Wi-Fi 功能,将明显减小二进制文件的大小。
- 不要启用 :ref:`CONFIG_COMPILER_CXX_EXCEPTIONS`:ref:`CONFIG_COMPILER_CXX_RTTI`,也不要将 :ref:`CONFIG_COMPILER_STACK_CHECK_MODE` 设置为 Overall。这些选项已默认禁用启用这些选项会大幅增加二进制文件的大小。
- 禁用 :ref:`CONFIG_ESP_ERR_TO_NAME_LOOKUP` 将会移除查找表,该表用于将错误日志中的错误值转换成用户友好名称(参阅 :doc:`/api-guides/error-handling`)。这样做可以减小二进制文件的大小,但错误值将只以整数形式输出。
- 将 :ref:`CONFIG_ESP_SYSTEM_PANIC` 设置为 ``Silent reboot`` 可以减小一小部分二进制文件的大小,但此操作 **仅** 建议在没有任何开发者使用 UART 输出来调试设备时进行。
:CONFIG_IDF_TARGET_ARCH_RISCV: - 设置 :ref:`CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS` 以库调用替代内联的入口/出口代码,可以减小二进制文件的大小。
- 如果应用程序的二进制文件只使用 protocomm 组件的某个安全版本,取消对其他版本的支持可以减小部分代码大小。请通过 :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0`:ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1` 或者 :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2` 方式,取消对应版本的支持。
.. note::
除了上述众多配置项之外,还有一些配置选项在更改为非默认设置时会增加二进制文件的大小,这些选项未在此列出。配置项的帮助文本中通常会阐明显著增加二进制文件大小的设置。
.. _size-targeted-optimizations:
针对性优化
^^^^^^^^^^^^^^^^^^^^^^^^^^^
以下二进制文件大小优化适用于特定的组件或函数:
.. only:: SOC_WIFI_SUPPORTED
Wi-Fi
@@@@@
- 如果不需要启用 WPA3 支持,禁用 :ref:`CONFIG_ESP_WIFI_ENABLE_WPA3_SAE` 可以减小 Wi-Fi 二进制文件的大小。请注意WPA3 支持是目前认证新 Wi-Fi 设备的必要标准。
- 如果不需要启用 soft-AP 支持,禁用 :ref:`CONFIG_ESP_WIFI_SOFTAP_SUPPORT` 可以减小 Wi-Fi 二进制文件的大小。
.. only:: esp32
ADC
@@@
- 如果使用 ADC 驱动程序,禁用 :ref:`CONFIG_ADC_CAL_EFUSE_TP_ENABLE`:ref:`CONFIG_ADC_CAL_EFUSE_VREF_ENABLE`:ref:`CONFIG_ADC_CAL_LUT_ENABLE` 可以减小一小部分二进制文件的大小,但准确性会降低。
.. only:: SOC_BT_SUPPORTED
Bluetooth NimBLE
@@@@@@@@@@@@@@@@
如果使用 :doc:`/api-reference/bluetooth/nimble/index`,要减小二进制文件的大小,可以执行以下操作:
.. list::
:esp32: - 如果只需要连接一个 Bluetooth LE则将 :ref:`CONFIG_BTDM_CTRL_BLE_MAX_CONN` 设置为 1。
- 如果只需要连接一个 Bluetooth LE则将 :ref:`CONFIG_BT_NIMBLE_MAX_CONNECTIONS` 设置为 1。
- 如果不需要 :ref:`CONFIG_BT_NIMBLE_ROLE_CENTRAL`:ref:`CONFIG_BT_NIMBLE_ROLE_OBSERVER`,可以选择禁用其一。
- 降低 :ref:`CONFIG_BT_NIMBLE_LOG_LEVEL` 可以减小二进制文件的大小。请注意,如果在上述 :ref:`reducing-overall-size` 中已经降低了整体日志级别,那么也会降低 NimBLE 的日志级别。
lwIP IPv6
@@@@@@@@@
- 将 :ref:`CONFIG_LWIP_IPV6` 设置为 ``false`` 可以减小 lwIP TCP/IP 堆栈的大小,但将仅支持 IPv4。
.. note::
如果禁用 IPv6 ``coap``:doc:`/api-reference/protocols/asio` 等组件将无法使用。
lwIP IPv4
@@@@@@@@@
- 如果不需要 IPv4 连接功能,将 :ref:`CONFIG_LWIP_IPV4` 设置为 ``false`` 可以减小 lwIP 的大小,使其成为仅支持 IPv6 的 TCP/IP 堆栈。
.. note::
在禁用 IPv4 支持之前,请注意,仅支持 IPv6 的网络环境尚未普及,必须在本地网络中提供支持,例如,由互联网服务供应商提供支持,或使用受限制的本地网络设置。
.. _newlib-nano-formatting:
Newlib Nano 格式化
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ESP-IDF 的 I/O 函数( ``printf()````scanf()`` 等)默认使用 Newlib 的 “完整” 格式化功能。
.. only:: CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT
启用配置选项 :ref:`CONFIG_NEWLIB_NANO_FORMAT` 将使 Newlib 切换到 Nano 格式化模式。这种模式的代码量更小,并且大部分内容被编译到了 {IDF_TARGET_NAME} 的 ROM 中,因此不需要将其添加至二进制文件中。
具体的二进制文件大小差异取决于固件使用的功能,但通常为 25 KB 到 50 KB。
.. only:: CONFIG_ESP_ROM_HAS_NEWLIB_NORMAL_FORMAT
禁用配置选项 :ref:`CONFIG_NEWLIB_NANO_FORMAT` 将切换 Newlib 到“完整”格式化模式。这将减小二进制文件的大小,因为 {IDF_TARGET_NAME} 的 ROM 中已存有完整格式化版本的函数,因此不需要将其添加至二进制文件中。
启用 Nano 格式化会减少调用 ``printf()`` 或其他字符串格式化函数的堆栈使用量,参阅 :ref:`optimize-stack-sizes`
“Nano” 格式化不支持 64 位整数或 C99 格式化功能。请在 `Newlib README 文件`_ 中搜索 ``--enable-newlib-nano-formatted-io`` 来获取完整的限制列表。
.. only:: esp32c2
.. note::
{IDF_TARGET_NAME} 会默认启用 :ref:`CONFIG_NEWLIB_NANO_FORMAT`
.. _Newlib README 文件: https://sourceware.org/newlib/README
.. _minimizing_binary_mbedtls:
mbedTLS 功能
@@@@@@@@@@@@@@@@@@@@@
**Component Config** > **mbedTLS** 下有多个默认启用的 mbedTLS 功能,如果不需要,可以禁用相应功能以减小代码大小。
这些功能包括:
- :ref:`CONFIG_MBEDTLS_HAVE_TIME`
- :ref:`CONFIG_MBEDTLS_ECDSA_DETERMINISTIC`
- :ref:`CONFIG_MBEDTLS_SHA512_C`
- :ref:`CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS`
- :ref:`CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS`
- :ref:`CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION`
- :ref:`CONFIG_MBEDTLS_SSL_ALPN`
- :ref:`CONFIG_MBEDTLS_SSL_RENEGOTIATION`
- :ref:`CONFIG_MBEDTLS_CCM_C`
- :ref:`CONFIG_MBEDTLS_GCM_C`
- :ref:`CONFIG_MBEDTLS_ECP_C` (或者:启用此选项,但在子菜单中禁用部分椭圆曲线)
- 如果不需要 mbedTLS 的服务器和客户端功能,可以修改 :ref:`CONFIG_MBEDTLS_TLS_MODE`
- 可以考虑禁用在 ``TLS Key Exchange Methods`` 子菜单中列出的一些密码套件(例如 :ref:`CONFIG_MBEDTLS_KEY_EXCHANGE_RSA`),以减小代码大小。
每个选项的帮助文本中都有更多信息可供参考。
.. important::
**强烈建议不要禁用所有 mbedTLS 选项。** 仅在理解功能用途,并确定在应用程序中不需要此功能时,方可禁用相应选项。请特别注意以下两点:
- 确保设备连接的任何 TLS 服务器仍然可用。如果服务器由第三方或云服务控制,建议确保固件至少支持两种 TLS 密码套件,以防未来某次更新禁用了其中一种。
- 确保连接设备的任何 TLS 客户端仍然可以使用支持/推荐的密码套件进行连接。请注意,未来版本的客户端操作系统可能会移除对某些功能的支持,因此建议启用多个支持的密码套件或算法以实现冗余。
如果依赖于第三方客户端或服务器,请密切关注其有关支持的 TLS 功能的公告和变更。否则,当所支持功能变更时,{IDF_TARGET_NAME} 设备可能无法访问。
.. note::
ESP-IDF 并未测试所有 mbedTLS 编译配置组合。如果发现某个组合无法编译或无法按预期执行,请在 `GitHub <https://github.com/espressif/esp-idf>`_ 上报告详细信息。
虚拟文件系统 (VFS)
@@@@@@@@@@@@@@@@@@@@@
在 ESP-IDF 中,:doc:`/api-reference/storage/vfs` 功能允许使用标准的 I/O 函数(如 ``open````read````write`` 等)和 C 库函数(如 ``fopen````fread````fwrite``来访问多个文件系统驱动程序和类似文件的外设驱动程序。当应用程序中不需要文件系统或类似文件的外设驱动功能时可以部分或完全禁用该功能。VFS 组件提供以下配置选项:
* :ref:`CONFIG_VFS_SUPPORT_TERMIOS` — 如果应用程序不使用 ``termios`` 函数族,可以禁用此选项。目前,这些函数仅在 UART VFS 驱动程序中实现,大多数应用程序可以禁用此选项。禁用后可以减小约 1.8 KB 代码大小。
* :ref:`CONFIG_VFS_SUPPORT_SELECT` — 如果应用程序不使用 ``select`` 函数处理文件描述符,可以禁用此选项。目前,只有 UART 和 eventfd VFS 驱动程序支持 ``select`` 函数。请注意,当禁用该选项时,仍然可以使用 ``select`` 处理套接字文件描述符。禁用此选项将减小约 2.7 KB 代码大小。
* :ref:`CONFIG_VFS_SUPPORT_DIR` — 如果应用程序不使用与目录相关的函数,例如 ``readdir`` (参阅此选项的描述以获取完整列表),可以禁用此选项。如果应用程序只需打开、读取和写入特定文件,而不需要枚举或创建目录,可以禁用此选项,从而减少超过 0.5 KB 代码大小,具体减小多少取决于使用的文件系统驱动程序。
* :ref:`CONFIG_VFS_SUPPORT_IO` — 如果应用程序不使用文件系统或类似文件的外设驱动程序,可以禁用此选项,这将禁用所有 VFS 功能,包括上述三个选项。当禁用此选项时,无法使用 :doc:`/api-reference/system/console`。请注意,当禁用此选项时,应用程序仍然可以使用标准 I/O 函数处理套接字文件描述符。相较于默认配置,禁用此选项可以减小约 9.4 KB 代码大小。
.. only:: CONFIG_ESP_ROM_HAS_HAL_SYSTIMER or CONFIG_ESP_ROM_HAS_HAL_WDT
HAL
@@@
.. list::
:CONFIG_ESP_ROM_HAS_HAL_SYSTIMER: * 启用 :ref:`CONFIG_HAL_SYSTIMER_USE_ROM_IMPL` 可以通过链接 ROM 实现的 systimer HAL 驱动程序来减少 IRAM 使用和二进制文件大小。
:CONFIG_ESP_ROM_HAS_HAL_WDT: * 启用 :ref:`CONFIG_HAL_WDT_USE_ROM_IMPL` 可以通过链接 ROM 实现的看门狗 HAL 驱动程序来减少 IRAM 使用和二进制文件大小。
@@@@@@
.. list::
* 启用 :ref:`CONFIG_HEAP_TLSF_USE_ROM_IMPL` 可以将整个堆功能放置在 flash 中,从而减少 IRAM 使用和二进制文件大小。
:CONFIG_ESP_ROM_HAS_HEAP_TLSF: * 启用 :ref:`CONFIG_HEAP_TLSF_USE_ROM_IMPL` 可以通过链接 ROM 实现的 TLSF 库来减少 IRAM 使用和二进制文件大小。
引导加载程序大小
------------------------------
本文档仅涉及 ESP-IDF 应用程序的二进制文件大小,而不涉及 ESP-IDF :ref:`second-stage-bootloader`
关于 ESP-IDF 引导加载程序二进制文件大小的讨论,参阅 :ref:`bootloader-size`
IRAM 二进制文件大小
------------------------------------
如果二进制文件的 IRAM 部分过大,可以通过减少 IRAM 使用来解决这个问题,参阅 :ref:`optimize-iram-usage`