77//! malloc/free implementation to track last allocations with callsite
88//! information.
99
10- #include "memfault/core/heap_stats.h"
11- #include "memfault/core/heap_stats_impl.h"
12-
1310#include <stdbool.h>
1411#include <stddef.h>
1512#include <stdint.h>
1815#include "memfault/config.h"
1916#include "memfault/core/compiler.h"
2017#include "memfault/core/debug_log.h"
18+ #include "memfault/core/heap_stats.h"
19+ #include "memfault/core/heap_stats_impl.h"
2120#include "memfault/core/math.h"
2221#include "memfault/core/platform/debug_log.h"
2322#include "memfault/core/platform/overrides.h"
2423
25- #define MEMFAULT_HEAP_STATS_VERSION 1
24+ #define MEMFAULT_HEAP_STATS_VERSION 2
25+
26+ MEMFAULT_STATIC_ASSERT (MEMFAULT_HEAP_STATS_MAX_COUNT < MEMFAULT_HEAP_STATS_LIST_END ,
27+ "Number of entries in heap stats exceeds limits" );
2628
2729sMfltHeapStats g_memfault_heap_stats = {
2830 .version = MEMFAULT_HEAP_STATS_VERSION ,
31+ .stats_pool_head = MEMFAULT_HEAP_STATS_LIST_END ,
2932};
3033sMfltHeapStatEntry g_memfault_heap_stats_pool [MEMFAULT_HEAP_STATS_MAX_COUNT ];
3134
@@ -43,7 +46,10 @@ static void prv_heap_stats_unlock(void) {
4346
4447void memfault_heap_stats_reset (void ) {
4548 prv_heap_stats_lock ();
46- g_memfault_heap_stats = (sMfltHeapStats ){0 };
49+ g_memfault_heap_stats = (sMfltHeapStats ){
50+ .version = MEMFAULT_HEAP_STATS_VERSION ,
51+ .stats_pool_head = MEMFAULT_HEAP_STATS_LIST_END ,
52+ };
4753 memset (g_memfault_heap_stats_pool , 0 , sizeof (g_memfault_heap_stats_pool ));
4854 prv_heap_stats_unlock ();
4955}
@@ -54,13 +60,43 @@ bool memfault_heap_stats_empty(void) {
5460 return g_memfault_heap_stats_pool [0 ].info .size == 0 ;
5561}
5662
57- //! Return the next slot to write
58- static sMfltHeapStatEntry * prv_get_next_entry (void ) {
59- sMfltHeapStatEntry * slot =
60- & g_memfault_heap_stats_pool [g_memfault_heap_stats .stats_pool_head ];
61- g_memfault_heap_stats .stats_pool_head = (g_memfault_heap_stats .stats_pool_head + 1 ) %
62- MEMFAULT_ARRAY_SIZE (g_memfault_heap_stats_pool );
63- return slot ;
63+ //! Get the previous entry index of the entry index to be found
64+ //!
65+ //! Iterates through the entry array checking if entry is in use and if the
66+ //! next entry index matches the search index. If the previous entry cannot be found,
67+ //! MEMFAULT_HEAP_STATS_LIST_END is returned
68+ static uint16_t prv_get_previous_entry (uint16_t search_entry_index ) {
69+ uint16_t index = MEMFAULT_HEAP_STATS_LIST_END ;
70+
71+ for (uint16_t i = 0 ; i < MEMFAULT_ARRAY_SIZE (g_memfault_heap_stats_pool ); i ++ ) {
72+ sMfltHeapStatEntry * entry = & g_memfault_heap_stats_pool [i ];
73+ if (entry -> info .in_use && entry -> info .next_entry_index == search_entry_index ) {
74+ index = i ;
75+ break ;
76+ }
77+ }
78+
79+ return index ;
80+ }
81+
82+ //! Return the next entry index to write new data to
83+ //!
84+ //! First searches for unused entries
85+ //! If none are found then traverses list to oldest (last) entry
86+ static uint16_t prv_get_new_entry_index (void ) {
87+ sMfltHeapStatEntry * entry ;
88+
89+ for (uint16_t i = 0 ; i < MEMFAULT_ARRAY_SIZE (g_memfault_heap_stats_pool ); i ++ ) {
90+ entry = & g_memfault_heap_stats_pool [i ];
91+
92+ if (!entry -> info .in_use ) {
93+ return i ; // favor unused entries
94+ }
95+ }
96+
97+ // No unused entry found, return the oldest (entry with next index of
98+ // MEMFAULT_HEAP_STATS_LIST_END)
99+ return prv_get_previous_entry (MEMFAULT_HEAP_STATS_LIST_END );
64100}
65101
66102void memfault_heap_stats_malloc (const void * lr , const void * ptr , size_t size ) {
@@ -71,8 +107,9 @@ void memfault_heap_stats_malloc(const void *lr, const void *ptr, size_t size) {
71107 if (g_memfault_heap_stats .in_use_block_count > g_memfault_heap_stats .max_in_use_block_count ) {
72108 g_memfault_heap_stats .max_in_use_block_count = g_memfault_heap_stats .in_use_block_count ;
73109 }
74- sMfltHeapStatEntry * slot = prv_get_next_entry ();
75- * slot = (sMfltHeapStatEntry ){
110+ uint16_t new_entry_index = prv_get_new_entry_index ();
111+ sMfltHeapStatEntry * new_entry = & g_memfault_heap_stats_pool [new_entry_index ];
112+ * new_entry = (sMfltHeapStatEntry ){
76113 .lr = lr ,
77114 .ptr = ptr ,
78115 .info =
@@ -81,6 +118,19 @@ void memfault_heap_stats_malloc(const void *lr, const void *ptr, size_t size) {
81118 .in_use = 1u ,
82119 },
83120 };
121+
122+ // Append new entry to head of the list
123+ new_entry -> info .next_entry_index = g_memfault_heap_stats .stats_pool_head ;
124+ g_memfault_heap_stats .stats_pool_head = new_entry_index ;
125+
126+ // Find next oldest entry (points to new entry)
127+ // Update next entry index to MEMFAULT_HEAP_STATS_LIST_END
128+ uint16_t next_oldest_entry_index = prv_get_previous_entry (new_entry_index );
129+
130+ if (next_oldest_entry_index != MEMFAULT_HEAP_STATS_LIST_END ) {
131+ g_memfault_heap_stats_pool [next_oldest_entry_index ].info .next_entry_index =
132+ MEMFAULT_HEAP_STATS_LIST_END ;
133+ }
84134 }
85135
86136 prv_heap_stats_unlock ();
@@ -92,9 +142,26 @@ void memfault_heap_stats_free(const void *ptr) {
92142 g_memfault_heap_stats .in_use_block_count -- ;
93143
94144 // if the pointer exists in the tracked stats, mark it as freed
95- for (size_t i = 0 ; i < MEMFAULT_ARRAY_SIZE (g_memfault_heap_stats_pool ); i ++ ) {
96- if ((g_memfault_heap_stats_pool [i ].ptr == ptr ) && g_memfault_heap_stats_pool [i ].info .in_use ) {
97- g_memfault_heap_stats_pool [i ].info .in_use = 0 ;
145+ for (uint16_t i = 0 ; i < MEMFAULT_ARRAY_SIZE (g_memfault_heap_stats_pool ); i ++ ) {
146+ sMfltHeapStatEntry * entry = & g_memfault_heap_stats_pool [i ];
147+ if ((entry -> ptr == ptr ) && entry -> info .in_use ) {
148+ entry -> info .in_use = 0 ;
149+
150+ // Find the entry previous to the removed entry
151+ uint16_t previous_entry_index = prv_get_previous_entry (i );
152+
153+ // If list head removed, set next entry as new list head
154+ if (g_memfault_heap_stats .stats_pool_head == i ) {
155+ g_memfault_heap_stats .stats_pool_head = entry -> info .next_entry_index ;
156+ }
157+
158+ // If there's a valid previous entry, set it's next index to removed entry's
159+ if (previous_entry_index != MEMFAULT_HEAP_STATS_LIST_END ) {
160+ g_memfault_heap_stats_pool [previous_entry_index ].info .next_entry_index =
161+ entry -> info .next_entry_index ;
162+ }
163+
164+ entry -> info .next_entry_index = MEMFAULT_HEAP_STATS_LIST_END ;
98165 break ;
99166 }
100167 }
0 commit comments