| 
									
										
										
										
											2022-07-20 13:59:14 +02:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |  * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD | 
					
						
							| 
									
										
										
										
											2022-07-20 13:59:14 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: Apache-2.0 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <sdkconfig.h>
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | #include <inttypes.h>
 | 
					
						
							| 
									
										
										
										
											2023-05-25 22:05:07 -07:00
										 |  |  | #include "esp_log.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define HEAP_TRACE_SRCFILE /* don't warn on inclusion here */
 | 
					
						
							|  |  |  | #include "esp_heap_trace.h"
 | 
					
						
							|  |  |  | #undef HEAP_TRACE_SRCFILE
 | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | #include "esp_heap_caps.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | #include "esp_attr.h"
 | 
					
						
							|  |  |  | #include "freertos/FreeRTOS.h"
 | 
					
						
							|  |  |  | #include "freertos/task.h"
 | 
					
						
							| 
									
										
										
										
											2022-12-09 13:21:37 +01:00
										 |  |  | #include "esp_memory_utils.h"
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | #include "sys/queue.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-30 11:40:17 +08:00
										 |  |  | static __attribute__((unused)) const char* TAG = "heaptrace"; | 
					
						
							| 
									
										
										
										
											2023-05-25 22:05:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | #define STACK_DEPTH CONFIG_HEAP_TRACING_STACK_DEPTH
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-12 20:29:47 +03:00
										 |  |  | #if CONFIG_HEAP_TRACING_STANDALONE
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | static portMUX_TYPE trace_mux = portMUX_INITIALIZER_UNLOCKED; | 
					
						
							|  |  |  | static bool tracing; | 
					
						
							|  |  |  | static heap_trace_mode_t mode; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | /* Define struct: linked list of records */ | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  | TAILQ_HEAD(heap_trace_record_list_struct_t, heap_trace_record_t); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | typedef struct heap_trace_record_list_struct_t heap_trace_record_list_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Linked List of Records */ | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |     /* Buffer used for records. */ | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     heap_trace_record_t *buffer; | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |     /* Linked list of recorded allocations */ | 
					
						
							|  |  |  |     heap_trace_record_list_t list; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Linked list of available record objects */ | 
					
						
							|  |  |  |     heap_trace_record_list_t unused; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-13 12:33:43 -08:00
										 |  |  |     /* capacity of 'buffer' */ | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     size_t capacity; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-13 12:33:43 -08:00
										 |  |  |     /* Count of entries in 'list' */ | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     size_t count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* During execution, we remember the maximum
 | 
					
						
							|  |  |  |        value of 'count'. This can help you | 
					
						
							|  |  |  |        choose the right size for your buffer capacity.*/ | 
					
						
							|  |  |  |     size_t high_water_mark; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Has the buffer overflowed and lost trace entries? */ | 
					
						
							|  |  |  |     bool has_overflowed; | 
					
						
							|  |  |  | } records_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Forward Defines
 | 
					
						
							|  |  |  | static void heap_trace_dump_base(bool internal_ram, bool psram); | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  | static void record_deep_copy(heap_trace_record_t *r_dest, const heap_trace_record_t *r_src); | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  | static void list_setup(void); | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  | static void list_remove(heap_trace_record_t *r_remove); | 
					
						
							|  |  |  | static heap_trace_record_t* list_add(const heap_trace_record_t *r_append); | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  | static heap_trace_record_t* list_pop_unused(void); | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  | static heap_trace_record_t* list_find(void *p); | 
					
						
							|  |  |  | static void list_find_and_remove(void* p); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* The actual records. */ | 
					
						
							|  |  |  | static records_t records; | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Actual number of allocations logged */ | 
					
						
							|  |  |  | static size_t total_allocations; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Actual number of frees logged */ | 
					
						
							|  |  |  | static size_t total_frees; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-13 12:33:43 -08:00
										 |  |  | /* Used to speed up heap_trace_get */ | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  | static heap_trace_record_t* r_get; | 
					
						
							|  |  |  | static size_t r_get_idx; | 
					
						
							| 
									
										
										
										
											2023-01-13 12:33:43 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | #if CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-25 22:05:07 -07:00
										 |  |  | // We use a hash_map to make locating a record by memory address very fast.
 | 
					
						
							|  |  |  | //   Key: addr                  // the memory address returned by malloc, calloc, realloc
 | 
					
						
							|  |  |  | //   Value: hash_map[hash(key)] // a list of records ptrs, which contains the relevant record.
 | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  | SLIST_HEAD(heap_trace_hash_list_struct_t, heap_trace_record_t); | 
					
						
							|  |  |  | typedef struct heap_trace_hash_list_struct_t heap_trace_hash_list_t; | 
					
						
							|  |  |  | static heap_trace_hash_list_t* hash_map; // array of lists
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | static size_t total_hashmap_hits; | 
					
						
							|  |  |  | static size_t total_hashmap_miss; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | static HEAP_IRAM_ATTR size_t hash_idx(void* p) | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |     static const uint32_t fnv_prime = 16777619UL; // expression 2^24 + 2^8 + 0x93 (32 bits size)
 | 
					
						
							|  |  |  |     // since all the addresses are 4 bytes aligned, computing address * fnv_prime always gives
 | 
					
						
							|  |  |  |     // a modulo 4 number. The bit shift goal is to distribute more evenly the hashes in the
 | 
					
						
							|  |  |  |     // given range [0 , CONFIG_HEAP_TRACE_HASH_MAP_SIZE - 1].
 | 
					
						
							|  |  |  |     return ((((uint32_t)p >> 3) + | 
					
						
							|  |  |  |              ((uint32_t)p >> 5) + | 
					
						
							|  |  |  |              ((uint32_t)p >> 7)) * fnv_prime) % (uint32_t)CONFIG_HEAP_TRACE_HASH_MAP_SIZE; | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | static HEAP_IRAM_ATTR void map_add(heap_trace_record_t *r_add) | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     size_t idx = hash_idx(r_add->address); | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |     SLIST_INSERT_HEAD(&hash_map[idx], r_add, slist_hashmap); | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | static HEAP_IRAM_ATTR void map_remove(heap_trace_record_t *r_remove) | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |     size_t idx = hash_idx(r_remove->address); | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |     SLIST_REMOVE(&hash_map[idx], r_remove, heap_trace_record_t, slist_hashmap); | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | static HEAP_IRAM_ATTR heap_trace_record_t* map_find(void *p) | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     size_t idx = hash_idx(p); | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |     heap_trace_record_t *r_cur = NULL; | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |     SLIST_FOREACH(r_cur, &hash_map[idx], slist_hashmap) { | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |         if (r_cur->address == p) { | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |             total_hashmap_hits++; | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |             return r_cur; | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     total_hashmap_miss++; | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static HEAP_IRAM_ATTR heap_trace_record_t* map_find_and_remove(void *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     size_t idx = hash_idx(p); | 
					
						
							|  |  |  |     heap_trace_record_t *r_cur = NULL; | 
					
						
							| 
									
										
										
										
											2023-12-18 12:33:59 +01:00
										 |  |  |     heap_trace_record_t *r_prev = NULL; | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |     SLIST_FOREACH(r_cur, &hash_map[idx], slist_hashmap) { | 
					
						
							|  |  |  |         if (r_cur->address == p) { | 
					
						
							|  |  |  |             total_hashmap_hits++; | 
					
						
							| 
									
										
										
										
											2023-12-18 12:33:59 +01:00
										 |  |  |             if (r_prev) { | 
					
						
							|  |  |  |                 SLIST_REMOVE_AFTER(r_prev, slist_hashmap); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 SLIST_REMOVE_HEAD(&hash_map[idx], slist_hashmap); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |             return r_cur; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-12-18 12:33:59 +01:00
										 |  |  |         r_prev = r_cur; | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     total_hashmap_miss++; | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | #endif // CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | esp_err_t heap_trace_init_standalone(heap_trace_record_t *record_buffer, size_t num_records) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (tracing) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |     if (record_buffer == NULL || num_records == 0) { | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |         return ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-25 22:05:07 -07:00
										 |  |  | #if CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							|  |  |  |     if (hash_map == NULL) { | 
					
						
							|  |  |  |         uint32_t map_size = sizeof(heap_trace_record_list_t) * CONFIG_HEAP_TRACE_HASH_MAP_SIZE; | 
					
						
							|  |  |  | #if CONFIG_HEAP_TRACE_HASH_MAP_IN_EXT_RAM
 | 
					
						
							|  |  |  |         ESP_LOGI(TAG, "hashmap: allocating %" PRIu32 " bytes (PSRAM)\n", map_size); | 
					
						
							|  |  |  |         hash_map = heap_caps_calloc(1, map_size, MALLOC_CAP_SPIRAM); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |         ESP_LOGI(TAG, "hashmap: allocating %" PRIu32 " bytes (Internal RAM)\n", map_size); | 
					
						
							|  |  |  |         hash_map = heap_caps_calloc(1, map_size, MALLOC_CAP_INTERNAL); | 
					
						
							|  |  |  | #endif // CONFIG_HEAP_TRACE_HASH_MAP_IN_EXT_RAM
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif // CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     records.buffer = record_buffer; | 
					
						
							|  |  |  |     records.capacity = num_records; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | static esp_err_t set_tracing(bool enable) | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     if (tracing == enable) { | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         return ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     tracing = enable; | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | esp_err_t heap_trace_start(heap_trace_mode_t mode_param) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     if (records.buffer == NULL || records.capacity == 0) { | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |         return ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-12-12 20:29:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 21:41:58 +08:00
										 |  |  |     portENTER_CRITICAL(&trace_mux); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     set_tracing(false); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     mode = mode_param; | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     // clear buffers
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |     memset(records.buffer, 0, sizeof(heap_trace_record_t) * records.capacity); | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |     for (size_t i = 0; i < (size_t)CONFIG_HEAP_TRACE_HASH_MAP_SIZE; i++) { | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |         SLIST_INIT(&hash_map[i]); | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     total_hashmap_hits = 0; | 
					
						
							|  |  |  |     total_hashmap_miss = 0; | 
					
						
							|  |  |  | #endif // CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     records.count = 0; | 
					
						
							|  |  |  |     records.has_overflowed = false; | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |     list_setup(); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     total_allocations = 0; | 
					
						
							|  |  |  |     total_frees = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     const esp_err_t ret_val = set_tracing(true); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     portEXIT_CRITICAL(&trace_mux); | 
					
						
							|  |  |  |     return ret_val; | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t heap_trace_stop(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     portENTER_CRITICAL(&trace_mux); | 
					
						
							|  |  |  |     const esp_err_t ret_val = set_tracing(false); | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&trace_mux); | 
					
						
							|  |  |  |     return ret_val; | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t heap_trace_resume(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     portENTER_CRITICAL(&trace_mux); | 
					
						
							|  |  |  |     const esp_err_t ret_val = set_tracing(true); | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&trace_mux); | 
					
						
							|  |  |  |     return ret_val; | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | size_t heap_trace_get_count(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     return records.count; | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  | esp_err_t heap_trace_get(size_t index, heap_trace_record_t *r_out) | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |     if (r_out == NULL) { | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |         return ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     esp_err_t result = ESP_OK; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 21:41:58 +08:00
										 |  |  |     portENTER_CRITICAL(&trace_mux); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (index >= records.count) { | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |         result = ESP_ERR_INVALID_ARG; /* out of range for 'count' */ | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-13 12:33:43 -08:00
										 |  |  |         // Perf: speed up sequential access
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |         if (r_get && r_get_idx == index - 1) { | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |             r_get = TAILQ_NEXT(r_get, tailq_list); | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |             r_get_idx = index; | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-13 12:33:43 -08:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-13 12:33:43 -08:00
										 |  |  |             // Iterate through through the linked list
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |             r_get = TAILQ_FIRST(&records.list); | 
					
						
							| 
									
										
										
										
											2023-01-13 12:33:43 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             for (int i = 0; i < index; i++) { | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |                 if (r_get == NULL) { | 
					
						
							| 
									
										
										
										
											2023-01-13 12:33:43 -08:00
										 |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |                 r_get = TAILQ_NEXT(r_get, tailq_list); | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |                 r_get_idx = i + 1; | 
					
						
							| 
									
										
										
										
											2023-01-13 12:33:43 -08:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         // We already checked that index < records.count,
 | 
					
						
							|  |  |  |         // This could be indicative of memory corruption.
 | 
					
						
							|  |  |  |         assert(r_get != NULL); | 
					
						
							|  |  |  |         memcpy(r_out, r_get, sizeof(heap_trace_record_t)); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 21:41:58 +08:00
										 |  |  |     portEXIT_CRITICAL(&trace_mux); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | esp_err_t heap_trace_summary(heap_trace_summary_t *summary) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (summary == NULL) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     portENTER_CRITICAL(&trace_mux); | 
					
						
							|  |  |  |     summary->mode = mode; | 
					
						
							|  |  |  |     summary->total_allocations = total_allocations; | 
					
						
							|  |  |  |     summary->total_frees = total_frees; | 
					
						
							|  |  |  |     summary->count = records.count; | 
					
						
							|  |  |  |     summary->capacity = records.capacity; | 
					
						
							|  |  |  |     summary->high_water_mark = records.high_water_mark; | 
					
						
							|  |  |  |     summary->has_overflowed = records.has_overflowed; | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | #if CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     summary->total_hashmap_hits = total_hashmap_hits; | 
					
						
							|  |  |  |     summary->total_hashmap_miss = total_hashmap_miss; | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | #endif // CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     portEXIT_CRITICAL(&trace_mux); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 13:21:37 +01:00
										 |  |  | void heap_trace_dump(void) { | 
					
						
							|  |  |  |     heap_trace_dump_caps(MALLOC_CAP_INTERNAL | MALLOC_CAP_SPIRAM); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 13:21:37 +01:00
										 |  |  | void heap_trace_dump_caps(const uint32_t caps) { | 
					
						
							|  |  |  |     heap_trace_dump_base(caps & MALLOC_CAP_INTERNAL, caps & MALLOC_CAP_SPIRAM); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void heap_trace_dump_base(bool internal_ram, bool psram) | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |     portENTER_CRITICAL(&trace_mux); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     size_t delta_size = 0; | 
					
						
							|  |  |  |     size_t delta_allocs = 0; | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     size_t start_count = records.count; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     esp_rom_printf("====== Heap Trace: %"PRIu32" records (%"PRIu32" capacity) ======\n", | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |         records.count, records.capacity); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |     // Iterate through through the linked list
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     heap_trace_record_t *r_cur = TAILQ_FIRST(&records.list); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     for (int i = 0; i < records.count; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |         // check corruption
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         if (r_cur == NULL) { | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |             esp_rom_printf("\nError: heap trace linked list is corrupt. expected more records.\n"); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         bool should_print = r_cur->address != NULL && | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |             ((psram && internal_ram) || | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |              (internal_ram && esp_ptr_internal(r_cur->address)) || | 
					
						
							|  |  |  |              (psram && esp_ptr_external_ram(r_cur->address))); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (should_print) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const char* label = ""; | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |             if (esp_ptr_internal(r_cur->address)) { | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |                 label = ", Internal"; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |             if (esp_ptr_external_ram(r_cur->address)) { | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |                 label = ",    PSRAM"; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |             esp_rom_printf("%6d bytes (@ %p%s) allocated CPU %d ccount 0x%08x caller ", | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |                    r_cur->size, r_cur->address, label, r_cur->ccount & 1, r_cur->ccount & ~3); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |             for (int j = 0; j < STACK_DEPTH && r_cur->alloced_by[j] != 0; j++) { | 
					
						
							|  |  |  |                 esp_rom_printf("%p%s", r_cur->alloced_by[j], | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |                        (j < STACK_DEPTH - 1) ? ":" : ""); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |             if (mode != HEAP_TRACE_ALL || STACK_DEPTH == 0 || r_cur->freed_by[0] == NULL) { | 
					
						
							|  |  |  |                 delta_size += r_cur->size; | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |                 delta_allocs++; | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |                 esp_rom_printf("\n"); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |                 esp_rom_printf("\nfreed by "); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |                 for (int j = 0; j < STACK_DEPTH; j++) { | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |                     esp_rom_printf("%p%s", r_cur->freed_by[j], | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |                            (j < STACK_DEPTH - 1) ? ":" : "\n"); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |         r_cur = TAILQ_NEXT(r_cur, tailq_list); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |     esp_rom_printf("====== Heap Trace Summary ======\n"); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     if (mode == HEAP_TRACE_ALL) { | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |         esp_rom_printf("Mode: Heap Trace All\n"); | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |         esp_rom_printf("%"PRIu32" bytes alive in trace (%"PRIu32"/%"PRIu32" allocations)\n", | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |                delta_size, delta_allocs, heap_trace_get_count()); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |         esp_rom_printf("Mode: Heap Trace Leaks\n"); | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |         esp_rom_printf("%"PRIu32" bytes 'leaked' in trace (%"PRIu32" allocations)\n", delta_size, delta_allocs); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     esp_rom_printf("records: %"PRIu32" (%"PRIu32" capacity, %"PRIu32" high water mark)\n", | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |         records.count, records.capacity, records.high_water_mark); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  | #if CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							|  |  |  |     esp_rom_printf("hashmap: %"PRIu32" capacity (%"PRIu32" hits, %"PRIu32" misses)\n", | 
					
						
							|  |  |  |         (size_t)CONFIG_HEAP_TRACE_HASH_MAP_SIZE, total_hashmap_hits, total_hashmap_miss); | 
					
						
							|  |  |  | #endif // CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     esp_rom_printf("total allocations: %"PRIu32"\n", total_allocations); | 
					
						
							|  |  |  |     esp_rom_printf("total frees: %"PRIu32"\n", total_frees); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (start_count != records.count) { // only a problem if trace isn't stopped before dumping
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |         esp_rom_printf("(NB: New entries were traced while dumping, so trace dump may have duplicate entries.)\n"); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |     if (records.has_overflowed) { | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |         esp_rom_printf("(NB: Internal Buffer has overflowed, so trace data is incomplete.)\n"); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |     esp_rom_printf("================================\n"); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     portEXIT_CRITICAL(&trace_mux); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Add a new allocation to the heap trace records */ | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | static HEAP_IRAM_ATTR void record_allocation(const heap_trace_record_t *r_allocation) | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     if (!tracing || r_allocation->address == NULL) { | 
					
						
							| 
									
										
										
										
											2018-12-12 20:29:47 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 21:41:58 +08:00
										 |  |  |     portENTER_CRITICAL(&trace_mux); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     if (tracing) { | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |         // If buffer is full, pop off the oldest
 | 
					
						
							|  |  |  |         // record to make more space
 | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |         if (records.count == records.capacity) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             records.has_overflowed = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |             heap_trace_record_t *r_first = TAILQ_FIRST(&records.list); | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |             // always remove from hashmap first since list_remove is setting address field
 | 
					
						
							|  |  |  |             // of the record to 0x00
 | 
					
						
							|  |  |  | #if CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							|  |  |  |             map_remove(r_first); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |             list_remove(r_first); | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         // push onto end of list
 | 
					
						
							|  |  |  |         list_add(r_allocation); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |         total_allocations++; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 21:41:58 +08:00
										 |  |  |     portEXIT_CRITICAL(&trace_mux); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* record a free event in the heap trace log
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    For HEAP_TRACE_ALL, this means filling in the freed_by pointer. | 
					
						
							|  |  |  |    For HEAP_TRACE_LEAKS, this means removing the record from the log. | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |    callers is an array of  STACK_DEPTH function pointer from the call stack | 
					
						
							|  |  |  |    leading to the call of record_free. | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | */ | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | static HEAP_IRAM_ATTR void record_free(void *p, void **callers) | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |        if (!tracing || p == NULL) { | 
					
						
							| 
									
										
										
										
											2018-12-12 20:29:47 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 21:41:58 +08:00
										 |  |  |     portENTER_CRITICAL(&trace_mux); | 
					
						
							| 
									
										
										
										
											2023-03-01 12:42:14 +01:00
										 |  |  |     // return directly if records.count == 0. In case of hashmap being used
 | 
					
						
							|  |  |  |     // this prevents the hashmap to return an item that is no longer in the
 | 
					
						
							|  |  |  |     // records list.
 | 
					
						
							|  |  |  |     if (records.count == 0) { | 
					
						
							|  |  |  |         portEXIT_CRITICAL(&trace_mux); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (tracing) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |         total_frees++; | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |         if (mode == HEAP_TRACE_ALL) { | 
					
						
							|  |  |  |             heap_trace_record_t *r_found = list_find(p); | 
					
						
							|  |  |  |             if (r_found != NULL) { | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  |                 // add 'freed_by' info to the record
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |                 memcpy(r_found->freed_by, callers, sizeof(void *) * STACK_DEPTH); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  |         } else { // HEAP_TRACE_LEAKS
 | 
					
						
							|  |  |  |             // Leak trace mode, once an allocation is freed
 | 
					
						
							|  |  |  |             // we remove it from the list & hashmap
 | 
					
						
							|  |  |  |             list_find_and_remove(p); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-29 21:41:58 +08:00
										 |  |  |     portEXIT_CRITICAL(&trace_mux); | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | // connect all records into a linked list of 'unused' records
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  | static void list_setup(void) | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |     TAILQ_INIT(&records.list); | 
					
						
							|  |  |  |     TAILQ_INIT(&records.unused); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int i = 0; i < records.capacity; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         heap_trace_record_t *r_cur = &records.buffer[i]; | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |         TAILQ_INSERT_TAIL(&records.unused, r_cur, tailq_list); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  | /* 1. removes record r_remove from records.list,
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |    2. places it into records.unused */ | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | static HEAP_IRAM_ATTR void list_remove(heap_trace_record_t* r_remove) | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(records.count > 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // remove from records.list
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |     TAILQ_REMOVE(&records.list, r_remove, tailq_list); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // set as unused
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  |     r_remove->address = 0; | 
					
						
							|  |  |  |     r_remove->size = 0; | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // add to records.unused
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |     TAILQ_INSERT_HEAD(&records.unused, r_remove, tailq_list); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // decrement
 | 
					
						
							|  |  |  |     records.count--; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // pop record from unused list
 | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | static HEAP_IRAM_ATTR heap_trace_record_t* list_pop_unused(void) | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | { | 
					
						
							|  |  |  |     // no records left?
 | 
					
						
							|  |  |  |     if (records.count >= records.capacity) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // get from records.unused
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     heap_trace_record_t *r_unused = TAILQ_FIRST(&records.unused); | 
					
						
							|  |  |  |     assert(r_unused->address == NULL); | 
					
						
							|  |  |  |     assert(r_unused->size == 0); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // remove from records.unused
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |     TAILQ_REMOVE(&records.unused, r_unused, tailq_list); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     return r_unused; | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // deep copy a record.
 | 
					
						
							|  |  |  | // Note: only copies the *allocation data*, not the next & prev ptrs
 | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | static HEAP_IRAM_ATTR void record_deep_copy(heap_trace_record_t *r_dest, const heap_trace_record_t *r_src) | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     r_dest->ccount  = r_src->ccount; | 
					
						
							|  |  |  |     r_dest->address = r_src->address; | 
					
						
							|  |  |  |     r_dest->size    = r_src->size; | 
					
						
							|  |  |  |     memcpy(r_dest->freed_by,   r_src->freed_by,   sizeof(void *) * STACK_DEPTH); | 
					
						
							|  |  |  |     memcpy(r_dest->alloced_by, r_src->alloced_by, sizeof(void *) * STACK_DEPTH); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Append a record to records.list
 | 
					
						
							| 
									
										
										
										
											2023-02-14 09:48:14 +01:00
										 |  |  | // Note: This deep copies r_append
 | 
					
						
							| 
									
										
										
										
											2023-04-03 15:16:55 +02:00
										 |  |  | static HEAP_IRAM_ATTR heap_trace_record_t* list_add(const heap_trace_record_t *r_append) | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | { | 
					
						
							|  |  |  |     if (records.count < records.capacity) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // get unused record
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         heap_trace_record_t *r_dest = list_pop_unused(); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // we checked that there is capacity, so this
 | 
					
						
							|  |  |  |         // should never be null.
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         assert(r_dest != NULL); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // copy allocation data
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         record_deep_copy(r_dest, r_append); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // append to records.list
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |         TAILQ_INSERT_TAIL(&records.list, r_dest, tailq_list); | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // increment
 | 
					
						
							|  |  |  |         records.count++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // high water mark
 | 
					
						
							|  |  |  |         if (records.count > records.high_water_mark) { | 
					
						
							|  |  |  |             records.high_water_mark = records.count; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  | #if CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							|  |  |  |         map_add(r_dest); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         return r_dest; | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |         records.has_overflowed = true; | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  | // search records.list for the allocation record matching this address
 | 
					
						
							|  |  |  | static HEAP_IRAM_ATTR heap_trace_record_t* list_find(void* p) | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     heap_trace_record_t *r_found = NULL; | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  | #if CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							|  |  |  |         // check the hashmap
 | 
					
						
							|  |  |  |         r_found = map_find(p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (r_found != NULL) { | 
					
						
							|  |  |  |             return r_found; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |     // to the end of the list and most allocations are short lived.
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     heap_trace_record_t *r_cur = NULL; | 
					
						
							| 
									
										
										
										
											2023-03-30 12:37:51 +02:00
										 |  |  |     TAILQ_FOREACH(r_cur, &records.list, tailq_list) { | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |         if (r_cur->address == p) { | 
					
						
							|  |  |  |             r_found = r_cur; | 
					
						
							| 
									
										
										
										
											2023-01-10 15:36:33 -08:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 14:22:17 -08:00
										 |  |  |     return r_found; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-12 12:24:15 +02:00
										 |  |  | static HEAP_IRAM_ATTR void list_find_and_remove(void* p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #if CONFIG_HEAP_TRACE_HASH_MAP
 | 
					
						
							|  |  |  |     heap_trace_record_t *r_found = map_find_and_remove(p); | 
					
						
							|  |  |  |     if (r_found != NULL) { | 
					
						
							|  |  |  |         list_remove(r_found); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     heap_trace_record_t *r_cur = NULL; | 
					
						
							|  |  |  |     TAILQ_FOREACH(r_cur, &records.list, tailq_list) { | 
					
						
							|  |  |  |         if (r_cur->address == p) { | 
					
						
							|  |  |  |             list_remove(r_cur); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-12 20:29:47 +03:00
										 |  |  | #include "heap_trace.inc"
 | 
					
						
							| 
									
										
										
										
											2017-05-11 17:56:17 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 00:47:02 -08:00
										 |  |  | #endif // CONFIG_HEAP_TRACING_STANDALONE
 |