ESP32 fragmentation issue

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
connorkm
Posts: 4
Joined: Thu Jan 13, 2022 9:39 am

ESP32 fragmentation issue

Post by connorkm » Fri Jan 14, 2022 4:25 pm

I am currently running the latest release of Micropython V1.17 for the 'GENERIC' ESP32. My board in the NodeMCU ESP-32S, the engraving on the module states ESP-WROOM-32.

I have loaded the code and have a fairly simple boot.py, with no other files loaded on the board at this moment. When I load and run MicroPython.mem_info() I see that the max free sz: 6764. This seems to be very low and I only assumed this is due to fragmentation. But I have followed the guidance on this forum and the Micropython wiki to no avail.

Below I will attach my boot.py and the response from getting the men_info:

Code: Select all

def do_connect():
    import network
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('connecting to network...')
        wlan.connect('*****', '*****')
        while not wlan.isconnected():
            pass
    print('network config:', wlan.ifconfig())
do_connect()

import gc
gc.collect()

Code: Select all

>>> import micropython
>>> micropython.mem_info()

stack: 704 out of 15360
GC: total: 111168, used: 1760, free: 109408
 No. of 1-blocks: 29, 2-blocks: 10, max blk sz: 18, max free sz: 6764
 
>>> gc.collect()
>>> micropython.mem_info()

stack: 704 out of 15360
GC: total: 111168, used: 1552, free: 109616
 No. of 1-blocks: 19, 2-blocks: 10, max blk sz: 18, max free sz: 6764
Has anyone else experienced this? Does anyone have any solutions for this?

marcidy
Posts: 87
Joined: Sat Dec 12, 2020 11:07 pm

Re: ESP32 fragmentation issue

Post by marcidy » Fri Jan 14, 2022 7:32 pm

Code: Select all

>>> micropython.mem_info()
stack: 704 out of 15360                                                                                          
GC: total: 111168, used: 1040, free: 110128                                                                      
 No. of 1-blocks: 12, 2-blocks: 8, max blk sz: 18, max free sz: 6877                                             
>>> micropython.mem_info(1)
stack: 720 out of 15360                                                                                          
GC: total: 111168, used: 1136, free: 110032                                  
 No. of 1-blocks: 14, 2-blocks: 10, max blk sz: 18, max free sz: 6866
GC memory layout; from 3ffe4db0:
00000: h=hhhBMh=Dh=Bh=hhh=================hh=======h=======h=hh=h==Bh=B
00400: ..hh=h=.........h=..............................................
       (106 lines all free)
1b000: ....................................
max free sz is counting blocks, not bytes, so you have to multiply the max free sz with the block size, which from what i can tell is defined in py/mpconfig.h as sizeof(mp_unit_t).

Note the definition of gc_info in py/gc.c which produces that line:

Code: Select all

  void gc_info(gc_info_t *info) {
      GC_ENTER();
      info->total = MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start);
      info->used = 0;
      info->free = 0;
      info->max_free = 0;
      info->num_1block = 0;
      info->num_2block = 0;
      info->max_block = 0;
      bool finish = false;
      for (size_t block = 0, len = 0, len_free = 0; !finish;) {
          size_t kind = ATB_GET_KIND(block);
          switch (kind) {
              case AT_FREE:
                  info->free += 1;
                  len_free += 1;
                  len = 0;
                  break;
      
              case AT_HEAD:
                  info->used += 1;
                  len = 1;
                  break;
      
              case AT_TAIL:
                  info->used += 1;
                  len += 1;
                  break;
  
              case AT_MARK:
                  // shouldn't happen
                  break;
          }
  
          block++;
          finish = (block == MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB);
          // Get next block type if possible
          if (!finish) {
              kind = ATB_GET_KIND(block);
          }
  
          if (finish || kind == AT_FREE || kind == AT_HEAD) {
              if (len == 1) {
                  info->num_1block += 1;
              } else if (len == 2) {
                  info->num_2block += 1;
              }
              if (len > info->max_block) {
                  info->max_block = len;
              }
              if (finish || kind == AT_HEAD) {
                  if (len_free > info->max_free) {
                      info->max_free = len_free;
                  }
                  len_free = 0;
              }
          }
      }
  
      info->used *= BYTES_PER_BLOCK;
      info->free *= BYTES_PER_BLOCK;
      GC_EXIT();
  }
at the end there, the info->max_free isn't multiplied by BYTES_PER_BLOCK like the other info.

Post Reply