7
7
//! malloc/free implementation to track last allocations with callsite
8
8
//! information.
9
9
10
- #include "memfault/core/heap_stats.h"
11
- #include "memfault/core/heap_stats_impl.h"
12
-
13
10
#include <stdbool.h>
14
11
#include <stddef.h>
15
12
#include <stdint.h>
18
15
#include "memfault/config.h"
19
16
#include "memfault/core/compiler.h"
20
17
#include "memfault/core/debug_log.h"
18
+ #include "memfault/core/heap_stats.h"
19
+ #include "memfault/core/heap_stats_impl.h"
21
20
#include "memfault/core/math.h"
22
21
#include "memfault/core/platform/debug_log.h"
23
22
#include "memfault/core/platform/overrides.h"
24
23
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" );
26
28
27
29
sMfltHeapStats g_memfault_heap_stats = {
28
30
.version = MEMFAULT_HEAP_STATS_VERSION ,
31
+ .stats_pool_head = MEMFAULT_HEAP_STATS_LIST_END ,
29
32
};
30
33
sMfltHeapStatEntry g_memfault_heap_stats_pool [MEMFAULT_HEAP_STATS_MAX_COUNT ];
31
34
@@ -43,7 +46,10 @@ static void prv_heap_stats_unlock(void) {
43
46
44
47
void memfault_heap_stats_reset (void ) {
45
48
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
+ };
47
53
memset (g_memfault_heap_stats_pool , 0 , sizeof (g_memfault_heap_stats_pool ));
48
54
prv_heap_stats_unlock ();
49
55
}
@@ -54,13 +60,43 @@ bool memfault_heap_stats_empty(void) {
54
60
return g_memfault_heap_stats_pool [0 ].info .size == 0 ;
55
61
}
56
62
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 );
64
100
}
65
101
66
102
void 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) {
71
107
if (g_memfault_heap_stats .in_use_block_count > g_memfault_heap_stats .max_in_use_block_count ) {
72
108
g_memfault_heap_stats .max_in_use_block_count = g_memfault_heap_stats .in_use_block_count ;
73
109
}
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 ){
76
113
.lr = lr ,
77
114
.ptr = ptr ,
78
115
.info =
@@ -81,6 +118,19 @@ void memfault_heap_stats_malloc(const void *lr, const void *ptr, size_t size) {
81
118
.in_use = 1u ,
82
119
},
83
120
};
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
+ }
84
134
}
85
135
86
136
prv_heap_stats_unlock ();
@@ -92,9 +142,26 @@ void memfault_heap_stats_free(const void *ptr) {
92
142
g_memfault_heap_stats .in_use_block_count -- ;
93
143
94
144
// 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 ;
98
165
break ;
99
166
}
100
167
}
0 commit comments