From 2a9a41886cd82f6ab4b708c90a84500c7c2ba7f3 Mon Sep 17 00:00:00 2001 From: Guillaume Souchere Date: Tue, 17 Sep 2024 12:23:59 +0200 Subject: [PATCH] feat(heap): Sort list of registered heap by increasing size For a given group of heaps sharing the same capabilities, it is best to use smaller heaps first when performing "small" allocations to keep the bigger heaps untouched. This prevents the scenario where a series of small allocations would crowd the bigger heaps making any bigger allocation fail for lack of space. Closes https://github.com/espressif/esp-idf/issues/13588 --- .../test_apps/dma/main/test_app_main.c | 2 +- .../test_apps/psram/main/test_app_main.c | 2 +- components/heap/heap_caps_init.c | 49 +++++++++++++++++-- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/components/esp_hw_support/test_apps/dma/main/test_app_main.c b/components/esp_hw_support/test_apps/dma/main/test_app_main.c index 311f7bbb72..6235df9f3d 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_app_main.c +++ b/components/esp_hw_support/test_apps/dma/main/test_app_main.c @@ -9,7 +9,7 @@ #include "esp_heap_caps.h" // Some resources are lazy allocated in pulse_cnt driver, the threshold is left for that case -#define TEST_MEMORY_LEAK_THRESHOLD (-300) +#define TEST_MEMORY_LEAK_THRESHOLD (-400) static size_t before_free_8bit; static size_t before_free_32bit; diff --git a/components/esp_psram/test_apps/psram/main/test_app_main.c b/components/esp_psram/test_apps/psram/main/test_app_main.c index e19a4c2c37..8ca8bacf7e 100644 --- a/components/esp_psram/test_apps/psram/main/test_app_main.c +++ b/components/esp_psram/test_apps/psram/main/test_app_main.c @@ -8,7 +8,7 @@ #include "unity_test_runner.h" #include "esp_heap_caps.h" -#define TEST_MEMORY_LEAK_THRESHOLD (-600) +#define TEST_MEMORY_LEAK_THRESHOLD (-700) static size_t before_free_8bit; static size_t before_free_32bit; diff --git a/components/heap/heap_caps_init.c b/components/heap/heap_caps_init.c index 22e0b2436d..67c6d911bb 100644 --- a/components/heap/heap_caps_init.c +++ b/components/heap/heap_caps_init.c @@ -27,6 +27,43 @@ ESP_SYSTEM_INIT_FN(init_heap, CORE, BIT(0), 100) return ESP_OK; } +/** + * @brief This helper function adds a new heap to list of registered + * heaps making sure to keep the heaps sorted by ascending size. + * + * @param new_heap heap to be inserted in the list of registered + * heaps + */ +static void sorted_add_to_registered_heaps(heap_t *new_heap) +{ + // if list empty, insert head and return + if (SLIST_EMPTY(®istered_heaps)) { + SLIST_INSERT_HEAD(®istered_heaps, new_heap, next); + return; + } + + // else, go through the registered heaps and add the new one + // so the registered heaps are sorted by increasing heap size. + heap_t *cur_heap = NULL; + heap_t *prev_heap = NULL; + const size_t new_heap_size = new_heap->end - new_heap->start; + SLIST_FOREACH(cur_heap, ®istered_heaps, next) { + const size_t cur_heap_size = cur_heap->end - cur_heap->start; + if (cur_heap_size >= new_heap_size) { + if (prev_heap != NULL) { + SLIST_INSERT_AFTER(prev_heap, new_heap, next); + } else { + SLIST_INSERT_HEAD(®istered_heaps, new_heap, next); + } + return; + } + prev_heap = cur_heap; + } + + // new heap size if the biggest so far, insert it at the end + SLIST_INSERT_AFTER(prev_heap, new_heap, next); +} + static void register_heap(heap_t *region) { size_t heap_size = region->end - region->start; @@ -154,11 +191,13 @@ void heap_caps_init(void) if (heaps_array[i].heap != NULL) { multi_heap_set_lock(heaps_array[i].heap, &heaps_array[i].heap_mux); } - if (i == 0) { - SLIST_INSERT_HEAD(®istered_heaps, &heaps_array[0], next); - } else { - SLIST_INSERT_AFTER(&heaps_array[i-1], &heaps_array[i], next); - } + /* Since the registered heaps list is always traversed from head + * to tail when looking for a suitable heap when allocating memory, it is + * best to place smaller heap first. In that way, if several heaps share + * the same set of capabilities, the smallest heaps will be used first when + * processing small allocation requests, leaving the bigger heaps untouched + * until the smaller heaps are full. */ + sorted_add_to_registered_heaps(&heaps_array[i]); } }