diff --git a/components/heap/heap_caps.c b/components/heap/heap_caps.c index 95d721af47..1f3292f36c 100644 --- a/components/heap/heap_caps.c +++ b/components/heap/heap_caps.c @@ -31,7 +31,8 @@ possible. This should optimize the amount of RAM accessible to the code without */ static esp_alloc_failed_hook_t alloc_failed_callback; - +static esp_heap_trace_alloc_hook_t trace_alloc_callback; +static esp_heap_trace_free_hook_t trace_free_callback; #ifdef CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS IRAM_ATTR static void hex_to_str(char buf[8], uint32_t n) @@ -99,6 +100,28 @@ esp_err_t heap_caps_register_failed_alloc_callback(esp_alloc_failed_hook_t callb return ESP_OK; } +esp_err_t heap_caps_register_trace_alloc_callback(esp_heap_trace_alloc_hook_t callback) +{ + if (callback == NULL) { + return ESP_ERR_INVALID_ARG; + } + + trace_alloc_callback = callback; + + return ESP_OK; +} + +esp_err_t heap_caps_register_trace_free_callback(esp_heap_trace_free_hook_t callback) +{ + if (callback == NULL) { + return ESP_ERR_INVALID_ARG; + } + + trace_free_callback = callback; + + return ESP_OK; +} + bool heap_caps_match(const heap_t *heap, uint32_t caps) { return heap->heap != NULL && ((get_all_caps(heap) & caps) == caps); @@ -188,6 +211,10 @@ IRAM_ATTR void *heap_caps_malloc( size_t size, uint32_t caps){ void* ptr = heap_caps_malloc_base(size, caps); + if (trace_alloc_callback) { + trace_alloc_callback(ptr, size); + } + if (!ptr && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } @@ -228,6 +255,11 @@ IRAM_ATTR void *heap_caps_malloc_default( size_t size ) r=heap_caps_malloc_base( size, MALLOC_CAP_DEFAULT ); } + // trace allocation + if (trace_alloc_callback) { + trace_alloc_callback(r, size); + } + // allocation failure? if (r==NULL && size > 0){ heap_caps_alloc_failed(size, MALLOC_CAP_DEFAULT, __func__); @@ -262,6 +294,11 @@ IRAM_ATTR void *heap_caps_realloc_default( void *ptr, size_t size ) r=heap_caps_realloc_base( ptr, size, MALLOC_CAP_DEFAULT); } + // trace allocation + if (trace_alloc_callback) { + trace_alloc_callback(r, size); + } + // allocation failure? if (r==NULL && size>0){ heap_caps_alloc_failed(size, MALLOC_CAP_DEFAULT, __func__); @@ -286,6 +323,9 @@ IRAM_ATTR void *heap_caps_malloc_prefer( size_t size, size_t num, ... ) break; } } + if (trace_alloc_callback) { + trace_alloc_callback(r, size); + } if (r == NULL && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } @@ -309,6 +349,9 @@ IRAM_ATTR void *heap_caps_realloc_prefer( void *ptr, size_t size, size_t num, .. break; } } + if (trace_alloc_callback) { + trace_alloc_callback(r, size); + } if (r == NULL && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } @@ -332,6 +375,9 @@ IRAM_ATTR void *heap_caps_calloc_prefer( size_t n, size_t size, size_t num, ... break; } } + if (trace_alloc_callback) { + trace_alloc_callback(r, size); + } if (r == NULL && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } @@ -374,6 +420,10 @@ IRAM_ATTR void heap_caps_free( void *ptr) heap_t *heap = find_containing_heap(ptr); assert(heap != NULL && "free() target pointer is outside heap areas"); multi_heap_free(heap->heap, ptr); + + if (trace_free_callback) { + trace_free_callback(ptr); + } } /* @@ -458,6 +508,9 @@ IRAM_ATTR void *heap_caps_realloc( void *ptr, size_t size, uint32_t caps) { ptr = heap_caps_realloc_base(ptr, size, caps); + if (trace_alloc_callback) { + trace_alloc_callback(ptr, size); + } if (ptr == NULL && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } @@ -489,6 +542,9 @@ IRAM_ATTR void *heap_caps_calloc( size_t n, size_t size, uint32_t caps) { void* ptr = heap_caps_calloc_base(n, size, caps); + if (trace_alloc_callback) { + trace_alloc_callback(ptr, size); + } if (!ptr && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } @@ -640,7 +696,7 @@ size_t heap_caps_get_allocated_size( void *ptr ) IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t caps) { - void *ret = NULL; + void *ptr = NULL; if(!alignment) { return NULL; @@ -675,19 +731,24 @@ IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t //doesn't cover, see if they're available in other prios. if ((get_all_caps(heap) & caps) == caps) { //Just try to alloc, nothing special. - ret = multi_heap_aligned_alloc(heap->heap, size, alignment); - if (ret != NULL) { - return ret; + ptr = multi_heap_aligned_alloc(heap->heap, size, alignment); + if (ptr != NULL) { + break; } } } } } - heap_caps_alloc_failed(size, caps, __func__); + if (trace_alloc_callback) { + trace_alloc_callback(ptr, size); + } - //Nothing usable found. - return NULL; + if (size > 0 && ptr != NULL) { + heap_caps_alloc_failed(size, caps, __func__); + } + + return ptr; } IRAM_ATTR void heap_caps_aligned_free(void *ptr) diff --git a/components/heap/include/esp_heap_caps.h b/components/heap/include/esp_heap_caps.h index e5adf162b8..6b0f96074d 100644 --- a/components/heap/include/esp_heap_caps.h +++ b/components/heap/include/esp_heap_caps.h @@ -53,6 +53,37 @@ typedef void (*esp_alloc_failed_hook_t) (size_t size, uint32_t caps, const char */ esp_err_t heap_caps_register_failed_alloc_callback(esp_alloc_failed_hook_t callback); +/** + * @brief callback called after every allocation + * @param ptr the allocated memory + * @param size in bytes of the allocation + * @note this hook is called on the same thread as the allocation, which may be within a low level operation. + * You should refrain from doing heavy work, logging, flash writes, or any locking. + */ +typedef void (*esp_heap_trace_alloc_hook_t) (void* ptr, size_t size); + +/** + * @brief registers a callback function to be invoked after every heap allocation + * @param callback caller defined callback to be invoked + * @return ESP_OK if callback was registered. + */ +esp_err_t heap_caps_register_trace_alloc_callback(esp_heap_trace_alloc_hook_t callback); + +/** + * @brief callback called after every free + * @param ptr the memory that was freed + * @note this hook is called on the same thread as the allocation, which may be within a low level operation. + * You should refrain from doing heavy work, logging, flash writes, or any locking. + */ +typedef void (*esp_heap_trace_free_hook_t) (void* ptr); + +/** + * @brief registers a callback function to be invoked after every heap allocation + * @param callback caller defined callback to be invoked + * @return ESP_OK if callback was registered. + */ +esp_err_t heap_caps_register_trace_free_callback(esp_heap_trace_free_hook_t callback); + /** * @brief Allocate a chunk of memory which has the given capabilities *