esp32/modesp32: Add idf_heap_info(capabilities) to esp32 module.
This commit adds an idf_heap_info(capabilities) method to the esp32 module which returns info about the ESP-IDF heaps. It's useful to get a bit of a picture of what's going on when code fails because ESP-IDF can't allocate memory anymore. Includes documentation and a test.
This commit is contained in:
parent
6a1c7ea815
commit
a177831c46
|
@ -38,6 +38,30 @@ Functions
|
||||||
|
|
||||||
Read the raw value of the internal Hall sensor, returning an integer.
|
Read the raw value of the internal Hall sensor, returning an integer.
|
||||||
|
|
||||||
|
.. function:: idf_heap_info(capabilities)
|
||||||
|
|
||||||
|
Returns information about the ESP-IDF heap memory regions. One of them contains
|
||||||
|
the MicroPython heap and the others are used by ESP-IDF, e.g., for network
|
||||||
|
buffers and other data. This data is useful to get a sense of how much memory
|
||||||
|
is available to ESP-IDF and the networking stack in particular. It may shed
|
||||||
|
some light on situations where ESP-IDF operations fail due to allocation failures.
|
||||||
|
The information returned is *not* useful to troubleshoot Python allocation failures,
|
||||||
|
use `micropython.mem_info()` instead.
|
||||||
|
|
||||||
|
The capabilities parameter corresponds to ESP-IDF's ``MALLOC_CAP_XXX`` values but the
|
||||||
|
two most useful ones are predefined as `esp32.HEAP_DATA` for data heap regions and
|
||||||
|
`esp32.HEAP_EXEC` for executable regions as used by the native code emitter.
|
||||||
|
|
||||||
|
The return value is a list of 4-tuples, where each 4-tuple corresponds to one heap
|
||||||
|
and contains: the total bytes, the free bytes, the largest free block, and
|
||||||
|
the minimum free seen over time.
|
||||||
|
|
||||||
|
Example after booting::
|
||||||
|
|
||||||
|
>>> import esp32; esp32.idf_heap_info(esp32.HEAP_DATA)
|
||||||
|
[(240, 0, 0, 0), (7288, 0, 0, 0), (16648, 4, 4, 4), (79912, 35712, 35512, 35108),
|
||||||
|
(15072, 15036, 15036, 15036), (113840, 0, 0, 0)]
|
||||||
|
|
||||||
Flash partitions
|
Flash partitions
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
@ -88,6 +112,10 @@ Constants
|
||||||
|
|
||||||
Used in `Partition.find` to specify the partition type.
|
Used in `Partition.find` to specify the partition type.
|
||||||
|
|
||||||
|
.. data:: HEAP_DATA
|
||||||
|
HEAP_EXEC
|
||||||
|
|
||||||
|
Used in `idf_heap_info`.
|
||||||
|
|
||||||
.. _esp32.RMT:
|
.. _esp32.RMT:
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,9 @@
|
||||||
#include "soc/sens_reg.h"
|
#include "soc/sens_reg.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "driver/adc.h"
|
#include "driver/adc.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "multi_heap.h"
|
||||||
|
#include "../heap_private.h"
|
||||||
|
|
||||||
#include "py/nlr.h"
|
#include "py/nlr.h"
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
|
@ -145,6 +148,28 @@ STATIC mp_obj_t esp32_hall_sensor(void) {
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_hall_sensor_obj, esp32_hall_sensor);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_hall_sensor_obj, esp32_hall_sensor);
|
||||||
|
|
||||||
|
STATIC mp_obj_t esp32_idf_heap_info(const mp_obj_t cap_in) {
|
||||||
|
mp_int_t cap = mp_obj_get_int(cap_in);
|
||||||
|
multi_heap_info_t info;
|
||||||
|
heap_t *heap;
|
||||||
|
mp_obj_t heap_list = mp_obj_new_list(0, 0);
|
||||||
|
SLIST_FOREACH(heap, ®istered_heaps, next) {
|
||||||
|
if (heap_caps_match(heap, cap)) {
|
||||||
|
multi_heap_get_info(heap->heap, &info);
|
||||||
|
mp_obj_t data[] = {
|
||||||
|
MP_OBJ_NEW_SMALL_INT(heap->end - heap->start), // total heap size
|
||||||
|
MP_OBJ_NEW_SMALL_INT(info.total_free_bytes), // total free bytes
|
||||||
|
MP_OBJ_NEW_SMALL_INT(info.largest_free_block), // largest free contiguous
|
||||||
|
MP_OBJ_NEW_SMALL_INT(info.minimum_free_bytes), // minimum free seen
|
||||||
|
};
|
||||||
|
mp_obj_t this_heap = mp_obj_new_tuple(4, data);
|
||||||
|
mp_obj_list_append(heap_list, this_heap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return heap_list;
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_idf_heap_info_obj, esp32_idf_heap_info);
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = {
|
STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp32) },
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp32) },
|
||||||
|
|
||||||
|
@ -153,6 +178,7 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_wake_on_ext1), MP_ROM_PTR(&esp32_wake_on_ext1_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_wake_on_ext1), MP_ROM_PTR(&esp32_wake_on_ext1_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_raw_temperature), MP_ROM_PTR(&esp32_raw_temperature_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_raw_temperature), MP_ROM_PTR(&esp32_raw_temperature_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_idf_heap_info), MP_ROM_PTR(&esp32_idf_heap_info_obj) },
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) },
|
{ MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_RMT), MP_ROM_PTR(&esp32_rmt_type) },
|
{ MP_ROM_QSTR(MP_QSTR_RMT), MP_ROM_PTR(&esp32_rmt_type) },
|
||||||
|
@ -160,6 +186,9 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = {
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_FALSE },
|
{ MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_FALSE },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), MP_ROM_TRUE },
|
{ MP_ROM_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), MP_ROM_TRUE },
|
||||||
|
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_HEAP_DATA), MP_ROM_INT(MALLOC_CAP_8BIT) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_HEAP_EXEC), MP_ROM_INT(MALLOC_CAP_EXEC) },
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_DICT(esp32_module_globals, esp32_module_globals_table);
|
STATIC MP_DEFINE_CONST_DICT(esp32_module_globals, esp32_module_globals_table);
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Test the esp32's esp32.idf_heap_info to return sane data
|
||||||
|
try:
|
||||||
|
import esp32
|
||||||
|
except ImportError:
|
||||||
|
print("SKIP")
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
# region tuple is: (size, free, largest free, min free)
|
||||||
|
# we check that each region's size is > 0 and that the free amounts are smaller than the size
|
||||||
|
def chk_heap(kind, regions):
|
||||||
|
chk = [True, True, True, True]
|
||||||
|
for r in regions:
|
||||||
|
chk = [
|
||||||
|
chk[0] and r[0] > 0,
|
||||||
|
chk[1] and r[1] <= r[0],
|
||||||
|
chk[2] and r[2] <= r[0],
|
||||||
|
chk[3] and r[3] <= r[0],
|
||||||
|
]
|
||||||
|
print(kind, chk)
|
||||||
|
|
||||||
|
|
||||||
|
# try getting heap regions
|
||||||
|
regions = esp32.idf_heap_info(esp32.HEAP_DATA)
|
||||||
|
print("HEAP_DATA >2:", len(regions) > 2)
|
||||||
|
chk_heap("HEAP_DATA", regions)
|
||||||
|
|
||||||
|
# try getting code regions
|
||||||
|
regions = esp32.idf_heap_info(esp32.HEAP_EXEC)
|
||||||
|
print("HEAP_EXEC >2:", len(regions) > 2)
|
||||||
|
chk_heap("HEAP_EXEC", regions)
|
||||||
|
|
||||||
|
# try invalid param
|
||||||
|
print(esp32.idf_heap_info(-1))
|
|
@ -0,0 +1,5 @@
|
||||||
|
HEAP_DATA >2: True
|
||||||
|
HEAP_DATA [True, True, True, True]
|
||||||
|
HEAP_EXEC >2: True
|
||||||
|
HEAP_EXEC [True, True, True, True]
|
||||||
|
[]
|
Loading…
Reference in New Issue