Skip to main content

Analysing Static Footprint

·6 mins·
Building Products
Table of Contents

The ESP32 is equipped with a 512KB of SRAM. While this may seem quite small, it can pack a lot of punch in this compact form if used well.

As we use the various components and its features in our application firmware, the linker pulls in different functions and variables from these components. The linker will typically optimise out entities that aren’t being used (or referenced) from the current application firmware. So, depending upon what you do in your application, the contribution from various components to your footprint changes.

The IDF provides a utility, idf_size.py, that lets you peek into the footprint utilisation so you could identify and optimise the relevant bits. The utility is also linked with the build scripts so you could directly run make targets to look at the footprint without having to remember a number of commands.

Let’s look at some quick ways how this can be used to look at the effective static footprint.

Per-Component Size
#

One way to look at the static footprint is to look at what impact every component has on your final firmware image. This can be done using the size-components target of the build system. Executing this target after building the examples/wifi/power_save application shows me the following output:

$ __make IDF_PATH=~/work/idf size-components__ 
Total sizes:
 DRAM .data size:   14200 bytes
 DRAM .bss  size:   23224 bytes
Used static DRAM:   37424 bytes ( 143312 available, 20.7% used)
Used static IRAM:   62344 bytes (  68728 available, 47.6% used)
      Flash code:  368546 bytes
    Flash rodata:   65916 bytes
Total image size:~ 511006 bytes (.bin may be padded larger)
Per-archive contributions to ELF file:
  __Archive File DRAM .data & .bss   IRAM Flash code & rodata   Total__ 
 libnet80211.a       1976   8891   3358      92337    10206  116768
     liblwip.a         19   3865      0      72280    14962   91126
       libpp.a        855   6339  13035      40707     7311   68247
        libc.a          0      0      0      55343     3889   59232
      libphy.a       1334    869   4584      29104        0   35891
    libesp32.a       2685    436   8067      10719     7388   29295
      libwpa.a          0    682      0      20314     2320   23316
 libfreertos.a       4148    776  12215          0     1595   18734
libnvs_flash.a          0     32      0       9497     2705   12234
      libgcc.a          4     20    104       9899      848   10875
...upplicant.a          0      0      0       9492        4    9496
...spi_flash.a         36    323   6465        912     1724    9460
     libheap.a        876      4   3390       1123      996    6389
   libdriver.a         24      4      0        883     4990    5901
      libsoc.a        669      8   3841          0     1239    5757
  libcoexist.a       1277     94   3344          0      137    4852
   libstdc++.a          8     20      0       2613     1253    3894
  libmbedtls.a          0      0      0       3109      320    3429
...p_adapter.a          0    124      0       2578      316    3018
      libvfs.a         40     63      0       2212      417    2732
   libnewlib.a        152    252    750        463       95    1712
  libpthread.a         16     12    178        770      655    1631
      liblog.a          8    268    438        396      166    1276
     libmain.a          0      0      0        574      643    1217
     libcore.a          0      5      0        709      402    1116
      librtc.a          0      4   1090          0        0    1094
...pp_update.a          0      0      0        123      725     848
      libhal.a          0      0    515          0       32     547
        libm.a          0      0     92          0        0      92
      libcxx.a          0      0      0         11        0      11
      libwps.a          0      1      0          0        0       1
     libwpa2.a          0      1      0          0        0       1
 libethernet.a          0      0      0          0        0       0
 ..._support.a          0      0      0          0        0       0

As you can see from the output above, it will display footprint information that is contributed by all the components towards the firmware. The information is additionally displayed in multiple columns:

  • DRAM .data : This is the size of the .data section of the component. This includes any pre-initialized data that can be read or written at runtime
  • DRAM .bss : This is the size of the .bss section of the component. This includes any global or statically defined variables and objects that are zero-initialised on boot-up.
  • IRAM : This is the size of the code (.text) section that needs to be loaded into IRAM. Note that most code can directly be executed from flash (XIP), without having to load it into IRAM. Typically code that is executed in interrupt context or accesses flash for read/write directly goes in here.
  • Flash Code : This is the size of the code (.text) section that is in the flash and is directly executed from there. Most of your code section will end up in this column.
  • Flash rodata : Any read-only data that is used by your firmware (strings, statically initialized and unmodifiable arrays) all go into this section. Since the flash can directly be accessed during execution, this need not be loaded into memory.
  • Total: The total contribution of this component.

As you might have guessed the size contributions to the IRAM and DRAM section here are critical. Since SRAM is limiting factor (512KB) relative to flash (about 2–8 MB).

Per-Symbol Size
#

Now Let’s say you found out that one of the components that you have written consumes much more memory that it should have. You can dig deeper by trying to check which symbols within this component contribute the most to the footprint. This can be done using the size-symbols target to the build system. For example,

$ __make IDF_PATH=~/work/idf size-symbols COMPONENT=soc__ Total sizes:
 DRAM .data size:   14200 bytes
 DRAM .bss  size:   23224 bytes
Used static DRAM:   37424 bytes ( 143312 available, 20.7% used)
Used static IRAM:   62344 bytes (  68728 available, 47.6% used)
      Flash code:  368546 bytes
    Flash rodata:   65916 bytes
Total image size:~ 511006 bytes (.bin may be padded larger)
Symbols within the archive: libsoc.a (Not all symbols may be reported)__Symbols from section: .dram0.data__ str1.4(605) __func__$3446(23) __func__$3425(21) rtc_clk_cpu_freq_value(20)
Section total: 669__Symbols from section: .dram0.bss__ 
s_cur_pll(4) s_cur_freq(4)
Section total: 8__Symbols from section: .iram0.text__ 
rtc_init(1020) rtc_clk_cpu_freq_set(472) rtc_clk_bbpll_set(380) rtc_clk_cal_internal(369) .iram1(282) rtc_clk_cpu_freq_get(172) rtc_clk_32k_bootstrap(170) rtc_clk_32k_enable_internal(149) rtc_clk_wait_for_slow_cycle(129) rtc_time_get(96) rtc_clk_cpu_freq_value(96) rtc_clk_cal(78) rtc_clk_xtal_freq_get(68) rtc_clk_slow_freq_get_hz(51) rtc_clk_apb_freq_get(50) rtc_clk_32k_enable(49) rtc_clk_fast_freq_set(46) rtc_clk_slow_freq_set(43) clk_val_is_valid(32) .iram1.literal(28) rtc_clk_apb_freq_update(23) rtc_clk_slow_freq_get(16) clk_val_to_reg_val(14) reg_val_to_clk_val(8)
Section total: 3841Symbols from section: .iram0.vectorsSection total: 0Symbols from section: .flash.textSection total: 0__Symbols from section: .flash.rodata__ 
soc_memory_regions(704) soc_memory_types(320) str1.4(159) soc_reserved_regions(48) soc_reserved_region_count(4) soc_memory_region_count(4)
Section total: 1239

Notice that we pass an additional parameter COMPONENT=<component_name> in the make command line to get per symbol information of this component. In the example above, we requested information for the component ‘soc’.

This caused the tool to display how much every symbol (function or variable/object) from this component contributed to the firmware’s footprint. Notice how information about how much size every function contributed to .iram0.text is shown in the output above. Also, because the arrays soc_memory_types and soc_memory_regions (defined in soc_memory_layout.c) are defined as ‘const’ are put into the flash since it is read-only data.

This information can be effectively used to identify exactly what parts of your components are contributing to the firmware footprint and then help you focus on optimizing these parts effectively.

Related

Creating Unique Factory Data Images
·5 mins
Building Products
A common requirement while building a device is to have some unique information programmed into the device at the time of manufacturing.
Espressif Receives Investment from Intel Capital and Beijing Singularity Power Investment Fund
·4 mins
Announcements
Espressif Systems (or “Espressif”), a leading global IoT semiconductor company, announced today that it has received investment co-led by Intel Capital and Beijing Singularity Power Investment Fund L.
April 2018
·4 mins
Newsletter
Hi everyone, The month of April is an exciting one for Espressif, since it is our birthday month.