kopia lustrzana https://github.com/espressif/esp-idf
feat(heap): Allow tracking of minimum free size for a given time frame
Implement a function to start tracking the minimum free size from the moment the function is called. Implement a function to stop tracking the minimum free size and restore the minimum free size value calculated since startup. Implement the tests related to this new feature.pull/12863/head
rodzic
b2cc934b94
commit
bb9d5a8d51
|
@ -574,6 +574,65 @@ size_t heap_caps_get_largest_free_block( uint32_t caps )
|
|||
return info.largest_free_block;
|
||||
}
|
||||
|
||||
static struct {
|
||||
size_t *values; // Array of minimum_free_bytes used to keep the different values when starting monitoring
|
||||
size_t counter; // Keep count of registered heap when monitoring to prevent any added heap to create an out of bound access on values
|
||||
multi_heap_lock_t mux; // protect access to min_free_bytes_monitoring fields in start/stop monitoring functions
|
||||
} min_free_bytes_monitoring = {NULL, 0, MULTI_HEAP_LOCK_STATIC_INITIALIZER};
|
||||
|
||||
esp_err_t heap_caps_monitor_local_minimum_free_size_start(void)
|
||||
{
|
||||
// update minimum_free_bytes on all affected heap, and store the "old value"
|
||||
// as a snapshot of the heaps minimum_free_bytes state.
|
||||
heap_t *heap = NULL;
|
||||
MULTI_HEAP_LOCK(&min_free_bytes_monitoring.mux);
|
||||
if (min_free_bytes_monitoring.values == NULL) {
|
||||
SLIST_FOREACH(heap, ®istered_heaps, next) {
|
||||
min_free_bytes_monitoring.counter++;
|
||||
}
|
||||
min_free_bytes_monitoring.values = heap_caps_malloc(sizeof(size_t) * min_free_bytes_monitoring.counter, MALLOC_CAP_DEFAULT);
|
||||
assert(min_free_bytes_monitoring.values != NULL && "not enough memory to store min_free_bytes value");
|
||||
memset(min_free_bytes_monitoring.values, 0xFF, sizeof(size_t) * min_free_bytes_monitoring.counter);
|
||||
}
|
||||
|
||||
heap = SLIST_FIRST(®istered_heaps);
|
||||
for (size_t counter = 0; counter < min_free_bytes_monitoring.counter; counter++) {
|
||||
size_t old_minimum = multi_heap_reset_minimum_free_bytes(heap->heap);
|
||||
|
||||
if (min_free_bytes_monitoring.values[counter] > old_minimum) {
|
||||
min_free_bytes_monitoring.values[counter] = old_minimum;
|
||||
}
|
||||
|
||||
heap = SLIST_NEXT(heap, next);
|
||||
}
|
||||
MULTI_HEAP_UNLOCK(&min_free_bytes_monitoring.mux);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t heap_caps_monitor_local_minimum_free_size_stop(void)
|
||||
{
|
||||
if (min_free_bytes_monitoring.values == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
MULTI_HEAP_LOCK(&min_free_bytes_monitoring.mux);
|
||||
heap_t *heap = SLIST_FIRST(®istered_heaps);
|
||||
for (size_t counter = 0; counter < min_free_bytes_monitoring.counter; counter++) {
|
||||
multi_heap_restore_minimum_free_bytes(heap->heap, min_free_bytes_monitoring.values[counter]);
|
||||
|
||||
heap = SLIST_NEXT(heap, next);
|
||||
}
|
||||
|
||||
heap_caps_free(min_free_bytes_monitoring.values);
|
||||
min_free_bytes_monitoring.values = NULL;
|
||||
min_free_bytes_monitoring.counter = 0;
|
||||
MULTI_HEAP_UNLOCK(&min_free_bytes_monitoring.mux);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
void heap_caps_get_info( multi_heap_info_t *info, uint32_t caps )
|
||||
{
|
||||
memset(info, 0, sizeof(multi_heap_info_t));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -241,6 +241,27 @@ size_t heap_caps_get_minimum_free_size( uint32_t caps );
|
|||
*/
|
||||
size_t heap_caps_get_largest_free_block( uint32_t caps );
|
||||
|
||||
/**
|
||||
* @brief Start monitoring the value of minimum_free_bytes from the moment this
|
||||
* function is called instead of from startup.
|
||||
*
|
||||
* @note This allows to detect local lows of the minimum_free_bytes value
|
||||
* that wouldn't be detected otherwise.
|
||||
*
|
||||
* @return esp_err_t ESP_OK if the function executed properly
|
||||
* ESP_FAIL if called when monitoring already active
|
||||
*/
|
||||
esp_err_t heap_caps_monitor_local_minimum_free_size_start(void);
|
||||
|
||||
/**
|
||||
* @brief Stop monitoring the value of minimum_free_bytes. After this call
|
||||
* the minimum_free_bytes value calculated from startup will be returned in
|
||||
* heap_caps_get_info and heap_caps_get_minimum_free_size.
|
||||
*
|
||||
* @return esp_err_t ESP_OK if the function executed properly
|
||||
* ESP_FAIL if called when monitoring not active
|
||||
*/
|
||||
esp_err_t heap_caps_monitor_local_minimum_free_size_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Get heap info for all regions with the given capabilities.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -190,6 +190,23 @@ void multi_heap_get_info(multi_heap_handle_t heap, multi_heap_info_t *info);
|
|||
*/
|
||||
void *multi_heap_aligned_alloc_offs(multi_heap_handle_t heap, size_t size, size_t alignment, size_t offset);
|
||||
|
||||
/**
|
||||
* @brief Reset the minimum_free_bytes value (setting it to free_bytes) and return the former value
|
||||
*
|
||||
* @param heap The heap in which the reset is taking place
|
||||
* @return size_t the value of minimum_free_bytes before it is reset
|
||||
*/
|
||||
size_t multi_heap_reset_minimum_free_bytes(multi_heap_handle_t heap);
|
||||
|
||||
/**
|
||||
* @brief Set the value of minimum_free_bytes to new_minimum_free_bytes_value or keep
|
||||
* the current value of minimum_free_bytes if it is smaller than new_minimum_free_bytes_value
|
||||
*
|
||||
* @param heap The heap in which the restore is taking place
|
||||
* @param new_minimum_free_bytes_value The value to restore the minimum_free_bytes to
|
||||
*/
|
||||
void multi_heap_restore_minimum_free_bytes(multi_heap_handle_t heap, const size_t new_minimum_free_bytes_value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include "multi_heap.h"
|
||||
#include "multi_heap_internal.h"
|
||||
|
||||
|
@ -429,4 +430,22 @@ void multi_heap_get_info_impl(multi_heap_handle_t heap, multi_heap_info_t *info)
|
|||
info->largest_free_block = tlsf_fit_size(heap->heap_data, info->largest_free_block);
|
||||
multi_heap_internal_unlock(heap);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_HEAP_TLSF_USE_ROM_IMPL
|
||||
|
||||
size_t multi_heap_reset_minimum_free_bytes(multi_heap_handle_t heap)
|
||||
{
|
||||
multi_heap_internal_lock(heap);
|
||||
const size_t old_minimum = heap->minimum_free_bytes;
|
||||
heap->minimum_free_bytes = heap->free_bytes;
|
||||
multi_heap_internal_unlock(heap);
|
||||
return old_minimum;
|
||||
}
|
||||
|
||||
void multi_heap_restore_minimum_free_bytes(multi_heap_handle_t heap, const size_t new_minimum_free_bytes_value)
|
||||
{
|
||||
multi_heap_internal_lock(heap);
|
||||
// keep the value of minimum_free_bytes if it is lower than the value passed as parameter
|
||||
heap->minimum_free_bytes = MIN(heap->minimum_free_bytes, new_minimum_free_bytes_value);
|
||||
multi_heap_internal_unlock(heap);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
|
|
@ -171,6 +171,62 @@ TEST_CASE("heap_caps metadata test", "[heap]")
|
|||
TEST_ASSERT(after.minimum_free_bytes < original.total_free_bytes);
|
||||
}
|
||||
|
||||
TEST_CASE("heap caps minimum free bytes monitoring", "[heap]")
|
||||
{
|
||||
printf("heap caps minimum free bytes monitoring local minimum\n");
|
||||
|
||||
uint32_t caps = MALLOC_CAP_DEFAULT;
|
||||
size_t minimum_free_size_reference = heap_caps_get_minimum_free_size(caps);
|
||||
|
||||
// start monitoring the value of minimum free bytes
|
||||
esp_err_t ret_val = heap_caps_monitor_local_minimum_free_size_start();
|
||||
TEST_ASSERT_EQUAL(ret_val, ESP_OK);
|
||||
|
||||
// get the heap info and check that the value of minimum free bytes return
|
||||
// is different from the previous one (before monitoring)
|
||||
size_t local_minimum_free_size = heap_caps_get_minimum_free_size(caps);
|
||||
TEST_ASSERT(local_minimum_free_size >= minimum_free_size_reference);
|
||||
|
||||
// allocate and free 400 bytes of memory.
|
||||
size_t alloc_size = 400;
|
||||
void *ptr = heap_caps_malloc(400, caps);
|
||||
TEST_ASSERT(ptr != NULL);
|
||||
heap_caps_free(ptr);
|
||||
// Check the new value of minimum free bytes to make sure
|
||||
// it is now lower than the previous one.
|
||||
TEST_ASSERT(heap_caps_get_minimum_free_size(caps) <= local_minimum_free_size - alloc_size);
|
||||
|
||||
// stop monitoring
|
||||
ret_val = heap_caps_monitor_local_minimum_free_size_stop();
|
||||
TEST_ASSERT_EQUAL(ret_val, ESP_OK);
|
||||
|
||||
// get the heap info and check that the value of minimum free bytes is lower than
|
||||
// the local minimum (since the local minimum didn't create a new all time minimum)
|
||||
size_t free_size = heap_caps_get_minimum_free_size(caps);
|
||||
TEST_ASSERT(local_minimum_free_size >= free_size);
|
||||
}
|
||||
|
||||
TEST_CASE("heap caps minimum free bytes fault cases", "[heap]")
|
||||
{
|
||||
printf("heap caps minimum free bytes fault cases\n");
|
||||
|
||||
// start monitoring the value of minimum free bytes
|
||||
esp_err_t ret_val = heap_caps_monitor_local_minimum_free_size_start();
|
||||
TEST_ASSERT_EQUAL(ret_val, ESP_OK);
|
||||
|
||||
// calling start again should be allowed
|
||||
ret_val = heap_caps_monitor_local_minimum_free_size_start();
|
||||
TEST_ASSERT_EQUAL(ret_val, ESP_OK);
|
||||
|
||||
// stop the monitoring
|
||||
ret_val = heap_caps_monitor_local_minimum_free_size_stop();
|
||||
TEST_ASSERT_EQUAL(ret_val, ESP_OK);
|
||||
|
||||
// calling stop monitoring when monitoring is not active should fail
|
||||
ret_val = heap_caps_monitor_local_minimum_free_size_stop();
|
||||
TEST_ASSERT_NOT_EQUAL(ret_val, ESP_OK);
|
||||
}
|
||||
|
||||
/* Small function runs from IRAM to check that malloc/free/realloc
|
||||
all work OK when cache is disabled...
|
||||
*/
|
||||
|
|
Ładowanie…
Reference in New Issue