Skip to content

Commit 83523c0

Browse files
authored
umm_malloc manual merge with upstream (#7337)
* umm_malloc manual merge with upstream * Fix divide by zero, case when heap is 100% allocated. * Removed extra line. * Fixed block count for debug build. This resolves OOM events for debug build. Correct overstepping array when freeing. * Handle another corner case in example HeapMetric.ino. Comment corrections. * Revert - ESP.getMaxFreeBlockSize() is back to indicating the size of a contiguous block of memory before the umm_malloc overhead is removed. * Stale code cleanup and comment improvements
1 parent 0d04124 commit 83523c0

File tree

12 files changed

+573
-246
lines changed

12 files changed

+573
-246
lines changed

cores/esp8266/Esp-frag.cpp

+14-6
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,28 @@ void EspClass::getHeapStats(uint32_t* hfree, uint16_t* hmax, uint8_t* hfrag)
2929
// Having getFreeHeap()=sum(hole-size), fragmentation is given by
3030
// 100 * (1 - sqrt(sum(hole-size²)) / sum(hole-size))
3131

32-
umm_info(NULL, 0);
32+
umm_info(NULL, false);
3333
uint8_t block_size = umm_block_size();
34-
uint32_t fh = ummHeapInfo.freeBlocks * block_size;
3534
if (hfree)
36-
*hfree = fh;
35+
*hfree = ummHeapInfo.freeBlocks * block_size;
3736
if (hmax)
38-
*hmax = ummHeapInfo.maxFreeContiguousBlocks * block_size;
39-
if (hfrag)
40-
*hfrag = 100 - (sqrt32(ummHeapInfo.freeSize2) * 100) / fh;
37+
*hmax = (uint16_t)ummHeapInfo.maxFreeContiguousBlocks * block_size;
38+
if (hfrag) {
39+
if (ummHeapInfo.freeBlocks) {
40+
*hfrag = 100 - (sqrt32(ummHeapInfo.freeBlocksSquared) * 100) / ummHeapInfo.freeBlocks;
41+
} else {
42+
*hfrag = 0;
43+
}
44+
}
4145
}
4246

4347
uint8_t EspClass::getHeapFragmentation()
4448
{
49+
#ifdef UMM_INLINE_METRICS
50+
return (uint8_t)umm_fragmentation_metric();
51+
#else
4552
uint8_t hfrag;
4653
getHeapStats(nullptr, nullptr, &hfrag);
4754
return hfrag;
55+
#endif
4856
}

cores/esp8266/heap.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ size_t ICACHE_RAM_ATTR xPortWantedSizeAlign(size_t size)
314314

315315
void system_show_malloc(void)
316316
{
317-
umm_info(NULL, 1);
317+
umm_info(NULL, true);
318318
}
319319

320320
};

cores/esp8266/umm_malloc/dbglog/dbglog.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* ----------------------------------------------------------------------------
1212
* NOTE WELL that this file may be included multiple times - this allows you
1313
* to set the trace level #define DBGLOG_LEVEL x
14-
*
14+
*
1515
* To update which of the DBGLOG macros are compiled in, you must redefine the
1616
* DBGLOG_LEVEL macro and the inlcude the dbglog.h file again, like this:
1717
*
@@ -57,6 +57,8 @@
5757
# define DBGLOG_FUNCTION printf
5858
#endif
5959

60+
#define DBGLOG_32_BIT_PTR(x) ((uint32_t)(((uintptr_t)(x)) & 0xffffffff))
61+
6062
/* ------------------------------------------------------------------------- */
6163

6264
#if DBGLOG_LEVEL >= 6

cores/esp8266/umm_malloc/umm_info.c

+88-29
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
#ifdef UMM_INFO
44

5+
#include <stdint.h>
6+
#include <stddef.h>
7+
#include <stdbool.h>
8+
9+
#include <math.h>
10+
511
/* ----------------------------------------------------------------------------
612
* One of the coolest things about this little library is that it's VERY
713
* easy to get debug information about the memory heap by simply iterating
@@ -19,15 +25,15 @@
1925

2026
UMM_HEAP_INFO ummHeapInfo;
2127

22-
void *umm_info( void *ptr, int force ) {
28+
void *umm_info( void *ptr, bool force ) {
2329
UMM_CRITICAL_DECL(id_info);
2430

25-
unsigned short int blockNo = 0;
26-
27-
if (umm_heap == NULL) {
31+
if(umm_heap == NULL) {
2832
umm_init();
2933
}
3034

35+
uint16_t blockNo = 0;
36+
3137
/* Protect the critical section... */
3238
UMM_CRITICAL_ENTRY(id_info);
3339

@@ -40,7 +46,7 @@ void *umm_info( void *ptr, int force ) {
4046
DBGLOG_FORCE( force, "\n" );
4147
DBGLOG_FORCE( force, "+----------+-------+--------+--------+-------+--------+--------+\n" );
4248
DBGLOG_FORCE( force, "|0x%08lx|B %5d|NB %5d|PB %5d|Z %5d|NF %5d|PF %5d|\n",
43-
(unsigned long)(&UMM_BLOCK(blockNo)),
49+
DBGLOG_32_BIT_PTR(&UMM_BLOCK(blockNo)),
4450
blockNo,
4551
UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK,
4652
UMM_PBLOCK(blockNo),
@@ -67,21 +73,18 @@ void *umm_info( void *ptr, int force ) {
6773
if( UMM_NBLOCK(blockNo) & UMM_FREELIST_MASK ) {
6874
++ummHeapInfo.freeEntries;
6975
ummHeapInfo.freeBlocks += curBlocks;
70-
ummHeapInfo.freeSize2 += (unsigned int)curBlocks
71-
* (unsigned int)sizeof(umm_block)
72-
* (unsigned int)curBlocks
73-
* (unsigned int)sizeof(umm_block);
76+
ummHeapInfo.freeBlocksSquared += (curBlocks * curBlocks);
7477

7578
if (ummHeapInfo.maxFreeContiguousBlocks < curBlocks) {
7679
ummHeapInfo.maxFreeContiguousBlocks = curBlocks;
7780
}
7881

7982
DBGLOG_FORCE( force, "|0x%08lx|B %5d|NB %5d|PB %5d|Z %5u|NF %5d|PF %5d|\n",
80-
(unsigned long)(&UMM_BLOCK(blockNo)),
83+
DBGLOG_32_BIT_PTR(&UMM_BLOCK(blockNo)),
8184
blockNo,
8285
UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK,
8386
UMM_PBLOCK(blockNo),
84-
(unsigned int)curBlocks,
87+
(uint16_t)curBlocks,
8588
UMM_NFREE(blockNo),
8689
UMM_PFREE(blockNo) );
8790

@@ -99,33 +102,25 @@ void *umm_info( void *ptr, int force ) {
99102
ummHeapInfo.usedBlocks += curBlocks;
100103

101104
DBGLOG_FORCE( force, "|0x%08lx|B %5d|NB %5d|PB %5d|Z %5u|\n",
102-
(unsigned long)(&UMM_BLOCK(blockNo)),
105+
DBGLOG_32_BIT_PTR(&UMM_BLOCK(blockNo)),
103106
blockNo,
104107
UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK,
105108
UMM_PBLOCK(blockNo),
106-
(unsigned int)curBlocks );
109+
(uint16_t)curBlocks );
107110
}
108111

109112
blockNo = UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK;
110113
}
111114

112115
/*
113-
* Update the accounting totals with information from the last block, the
114-
* rest must be free!
116+
* The very last block is used as a placeholder to indicate that
117+
* there are no more blocks in the heap, so it cannot be used
118+
* for anything - at the same time, the size of this block must
119+
* ALWAYS be exactly 1 !
115120
*/
116121

117-
{
118-
size_t curBlocks = UMM_NUMBLOCKS-blockNo;
119-
ummHeapInfo.freeBlocks += curBlocks;
120-
ummHeapInfo.totalBlocks += curBlocks;
121-
122-
if (ummHeapInfo.maxFreeContiguousBlocks < curBlocks) {
123-
ummHeapInfo.maxFreeContiguousBlocks = curBlocks;
124-
}
125-
}
126-
127122
DBGLOG_FORCE( force, "|0x%08lx|B %5d|NB %5d|PB %5d|Z %5d|NF %5d|PF %5d|\n",
128-
(unsigned long)(&UMM_BLOCK(blockNo)),
123+
DBGLOG_32_BIT_PTR(&UMM_BLOCK(blockNo)),
129124
blockNo,
130125
UMM_NBLOCK(blockNo) & UMM_BLOCKNO_MASK,
131126
UMM_PBLOCK(blockNo),
@@ -147,7 +142,13 @@ void *umm_info( void *ptr, int force ) {
147142

148143
DBGLOG_FORCE( force, "+--------------------------------------------------------------+\n" );
149144

145+
DBGLOG_FORCE( force, "Usage Metric: %5d\n", umm_usage_metric());
146+
DBGLOG_FORCE( force, "Fragmentation Metric: %5d\n", umm_fragmentation_metric());
147+
148+
DBGLOG_FORCE( force, "+--------------------------------------------------------------+\n" );
149+
150150
#if defined(UMM_STATS) || defined(UMM_STATS_FULL)
151+
#if !defined(UMM_INLINE_METRICS)
151152
if (ummHeapInfo.freeBlocks == ummStats.free_blocks) {
152153
DBGLOG_FORCE( force, "heap info Free blocks and heap statistics Free blocks match.\n");
153154
} else {
@@ -156,6 +157,7 @@ void *umm_info( void *ptr, int force ) {
156157
ummStats.free_blocks );
157158
}
158159
DBGLOG_FORCE( force, "+--------------------------------------------------------------+\n" );
160+
#endif
159161

160162
print_stats(force);
161163
#endif
@@ -169,17 +171,74 @@ void *umm_info( void *ptr, int force ) {
169171
/* ------------------------------------------------------------------------ */
170172

171173
size_t umm_free_heap_size( void ) {
172-
umm_info(NULL, 0);
174+
#ifndef UMM_INLINE_METRICS
175+
umm_info(NULL, false);
176+
#endif
173177
return (size_t)ummHeapInfo.freeBlocks * sizeof(umm_block);
174178
}
175179

180+
//C Breaking change in upstream umm_max_block_size() was changed to
181+
//C umm_max_free_block_size() keeping old function name for (dot) releases.
182+
//C TODO: update at next major release.
183+
//C size_t umm_max_free_block_size( void ) {
176184
size_t umm_max_block_size( void ) {
177-
umm_info(NULL, 0);
185+
umm_info(NULL, false);
178186
return ummHeapInfo.maxFreeContiguousBlocks * sizeof(umm_block);
179187
}
180188

181-
/* ------------------------------------------------------------------------ */
189+
/*
190+
Without build option UMM_INLINE_METRICS, calls to umm_usage_metric() or
191+
umm_fragmentation_metric() must to be preceeded by a call to umm_info(NULL, false)
192+
for updated results.
193+
*/
194+
int umm_usage_metric( void ) {
195+
#ifndef UMM_INLINE_METRICS
196+
umm_info(NULL, false);
197+
#endif
198+
DBGLOG_DEBUG( "usedBlocks %d totalBlocks %d\n", umm_metrics.usedBlocks, ummHeapInfo.totalBlocks);
199+
if (ummHeapInfo.freeBlocks)
200+
return (int)((ummHeapInfo.usedBlocks * 100)/(ummHeapInfo.freeBlocks));
182201

202+
return -1; // no freeBlocks
203+
}
204+
205+
uint32_t sqrt32 (uint32_t n);
206+
207+
int umm_fragmentation_metric( void ) {
208+
#ifndef UMM_INLINE_METRICS
209+
umm_info(NULL, false);
210+
#endif
211+
DBGLOG_DEBUG( "freeBlocks %d freeBlocksSquared %d\n", umm_metrics.freeBlocks, ummHeapInfo.freeBlocksSquared);
212+
if (0 == ummHeapInfo.freeBlocks) {
213+
return 0;
214+
} else {
215+
//upstream version: return (100 - (((uint32_t)(sqrtf(ummHeapInfo.freeBlocksSquared)) * 100)/(ummHeapInfo.freeBlocks)));
216+
return (100 - (((uint32_t)(sqrt32(ummHeapInfo.freeBlocksSquared)) * 100)/(ummHeapInfo.freeBlocks)));
217+
}
218+
}
219+
220+
#ifdef UMM_INLINE_METRICS
221+
static void umm_fragmentation_metric_init( void ) {
222+
ummHeapInfo.freeBlocks = UMM_NUMBLOCKS - 2;
223+
ummHeapInfo.freeBlocksSquared = ummHeapInfo.freeBlocks * ummHeapInfo.freeBlocks;
224+
}
225+
226+
static void umm_fragmentation_metric_add( uint16_t c ) {
227+
uint16_t blocks = (UMM_NBLOCK(c) & UMM_BLOCKNO_MASK) - c;
228+
DBGLOG_DEBUG( "Add block %d size %d to free metric\n", c, blocks);
229+
ummHeapInfo.freeBlocks += blocks;
230+
ummHeapInfo.freeBlocksSquared += (blocks * blocks);
231+
}
232+
233+
static void umm_fragmentation_metric_remove( uint16_t c ) {
234+
uint16_t blocks = (UMM_NBLOCK(c) & UMM_BLOCKNO_MASK) - c;
235+
DBGLOG_DEBUG( "Remove block %d size %d from free metric\n", c, blocks);
236+
ummHeapInfo.freeBlocks -= blocks;
237+
ummHeapInfo.freeBlocksSquared -= (blocks * blocks);
238+
}
239+
#endif // UMM_INLINE_METRICS
240+
241+
/* ------------------------------------------------------------------------ */
183242
#endif
184243

185244
#endif // defined(BUILD_UMM_MALLOC_C)

cores/esp8266/umm_malloc/umm_integrity.c

+23-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#if defined(BUILD_UMM_MALLOC_C)
22
/* integrity check (UMM_INTEGRITY_CHECK) {{{ */
33
#if defined(UMM_INTEGRITY_CHECK)
4+
5+
#include <stdint.h>
6+
#include <stdbool.h>
7+
48
/*
59
* Perform integrity check of the whole heap data. Returns 1 in case of
610
* success, 0 otherwise.
@@ -23,11 +27,11 @@
2327
* This way, we ensure that the free flag is in sync with the free pointers
2428
* chain.
2529
*/
26-
int umm_integrity_check(void) {
30+
bool umm_integrity_check(void) {
2731
UMM_CRITICAL_DECL(id_integrity);
28-
int ok = 1;
29-
unsigned short int prev;
30-
unsigned short int cur;
32+
bool ok = true;
33+
uint16_t prev;
34+
uint16_t cur;
3135

3236
if (umm_heap == NULL) {
3337
umm_init();
@@ -42,9 +46,9 @@ int umm_integrity_check(void) {
4246
/* Check that next free block number is valid */
4347
if (cur >= UMM_NUMBLOCKS) {
4448
DBGLOG_FUNCTION("heap integrity broken: too large next free num: %d "
45-
"(in block %d, addr 0x%lx)\n", cur, prev,
46-
(unsigned long)&UMM_NBLOCK(prev));
47-
ok = 0;
49+
"(in block %d, addr 0x%08x)\n", cur, prev,
50+
DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev)));
51+
ok = false;
4852
goto clean;
4953
}
5054
if (cur == 0) {
@@ -57,7 +61,7 @@ int umm_integrity_check(void) {
5761
DBGLOG_FUNCTION("heap integrity broken: free links don't match: "
5862
"%d -> %d, but %d -> %d\n",
5963
prev, cur, cur, UMM_PFREE(cur));
60-
ok = 0;
64+
ok = false;
6165
goto clean;
6266
}
6367

@@ -74,9 +78,9 @@ int umm_integrity_check(void) {
7478
/* Check that next block number is valid */
7579
if (cur >= UMM_NUMBLOCKS) {
7680
DBGLOG_FUNCTION("heap integrity broken: too large next block num: %d "
77-
"(in block %d, addr 0x%lx)\n", cur, prev,
78-
(unsigned long)&UMM_NBLOCK(prev));
79-
ok = 0;
81+
"(in block %d, addr 0x%08x)\n", cur, prev,
82+
DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev)));
83+
ok = false;
8084
goto clean;
8185
}
8286
if (cur == 0) {
@@ -88,21 +92,20 @@ int umm_integrity_check(void) {
8892
if ((UMM_NBLOCK(cur) & UMM_FREELIST_MASK)
8993
!= (UMM_PBLOCK(cur) & UMM_FREELIST_MASK))
9094
{
91-
DBGLOG_FUNCTION("heap integrity broken: mask wrong at addr 0x%lx: n=0x%x, p=0x%x\n",
92-
(unsigned long)&UMM_NBLOCK(cur),
95+
DBGLOG_FUNCTION("heap integrity broken: mask wrong at addr 0x%08x: n=0x%x, p=0x%x\n",
96+
DBGLOG_32_BIT_PTR(&UMM_NBLOCK(cur)),
9397
(UMM_NBLOCK(cur) & UMM_FREELIST_MASK),
94-
(UMM_PBLOCK(cur) & UMM_FREELIST_MASK)
95-
);
96-
ok = 0;
98+
(UMM_PBLOCK(cur) & UMM_FREELIST_MASK));
99+
ok = false;
97100
goto clean;
98101
}
99102

100103
/* make sure the block list is sequential */
101104
if (cur <= prev ) {
102105
DBGLOG_FUNCTION("heap integrity broken: next block %d is before prev this one "
103-
"(in block %d, addr 0x%lx)\n", cur, prev,
104-
(unsigned long)&UMM_NBLOCK(prev));
105-
ok = 0;
106+
"(in block %d, addr 0x%08x)\n", cur, prev,
107+
DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev)));
108+
ok = false;
106109
goto clean;
107110
}
108111

@@ -114,7 +117,7 @@ int umm_integrity_check(void) {
114117
DBGLOG_FUNCTION("heap integrity broken: block links don't match: "
115118
"%d -> %d, but %d -> %d\n",
116119
prev, cur, cur, UMM_PBLOCK(cur));
117-
ok = 0;
120+
ok = false;
118121
goto clean;
119122
}
120123

0 commit comments

Comments
 (0)