From c2636559c26007da30bf084eb6bbe725d6d96c0b Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Mon, 21 Dec 2020 15:20:39 -0800 Subject: [PATCH 1/4] Add inline always option to HeapSelect --- cores/esp8266/umm_malloc/umm_heap_select.h | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cores/esp8266/umm_malloc/umm_heap_select.h b/cores/esp8266/umm_malloc/umm_heap_select.h index 4c9150819f..c0ddc31d9d 100644 --- a/cores/esp8266/umm_malloc/umm_heap_select.h +++ b/cores/esp8266/umm_malloc/umm_heap_select.h @@ -3,6 +3,18 @@ #include +#ifndef ALWAYS_INLINE +#define ALWAYS_INLINE inline __attribute__ ((always_inline)) +#endif + +// Use FORCE_ALWAYS_INLINE to ensure HeapSelect... construtor/deconstructor +// are placed in IRAM +#ifdef FORCE_ALWAYS_INLINE +#define MAYBE_ALWAYS_INLINE ALWAYS_INLINE +#else +#define MAYBE_ALWAYS_INLINE +#endif + /* This class is modeled after interrupts.h @@ -20,13 +32,17 @@ class HeapSelect { public: #if (UMM_NUM_HEAPS == 1) + MAYBE_ALWAYS_INLINE HeapSelect(size_t id) { (void)id; } + MAYBE_ALWAYS_INLINE ~HeapSelect() {} #else + MAYBE_ALWAYS_INLINE HeapSelect(size_t id) : _heap_id(umm_get_current_heap_id()) { umm_set_heap_by_id(id); } + MAYBE_ALWAYS_INLINE ~HeapSelect() { umm_set_heap_by_id(_heap_id); } @@ -39,10 +55,12 @@ class HeapSelect { class HeapSelectIram { public: #ifdef UMM_HEAP_IRAM + MAYBE_ALWAYS_INLINE HeapSelectIram() : _heap_id(umm_get_current_heap_id()) { umm_set_heap_by_id(UMM_HEAP_IRAM); } + MAYBE_ALWAYS_INLINE ~HeapSelectIram() { umm_set_heap_by_id(_heap_id); } @@ -51,7 +69,9 @@ class HeapSelectIram { size_t _heap_id; #else + MAYBE_ALWAYS_INLINE HeapSelectIram() {} + MAYBE_ALWAYS_INLINE ~HeapSelectIram() {} #endif }; @@ -59,13 +79,17 @@ class HeapSelectIram { class HeapSelectDram { public: #if (UMM_NUM_HEAPS == 1) + MAYBE_ALWAYS_INLINE HeapSelectDram() {} + MAYBE_ALWAYS_INLINE ~HeapSelectDram() {} #else + MAYBE_ALWAYS_INLINE HeapSelectDram() : _heap_id(umm_get_current_heap_id()) { umm_set_heap_by_id(UMM_HEAP_DRAM); } + MAYBE_ALWAYS_INLINE ~HeapSelectDram() { umm_set_heap_by_id(_heap_id); } From d1c4c4dfcded7f1ba89f678f0140f78dca6048d2 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Mon, 21 Dec 2020 15:22:29 -0800 Subject: [PATCH 2/4] Add option to force DRAM for pvPort... APIs --- cores/esp8266/heap.cpp | 71 ++++++++++++++++++++--- cores/esp8266/umm_malloc/umm_malloc_cfg.h | 27 ++++----- 2 files changed, 77 insertions(+), 21 deletions(-) diff --git a/cores/esp8266/heap.cpp b/cores/esp8266/heap.cpp index 3f549716f4..c2473a0e45 100644 --- a/cores/esp8266/heap.cpp +++ b/cores/esp8266/heap.cpp @@ -5,6 +5,11 @@ #include #include "umm_malloc/umm_malloc.h" + +// Need FORCE_ALWAYS_INLINE to put HeapSelect class constructor/deconstructor in IRAM +#define FORCE_ALWAYS_INLINE +#include "umm_malloc/umm_heap_select.h" + #include #include #include @@ -16,6 +21,7 @@ extern "C" { #define UMM_CALLOC(n,s) umm_poison_calloc(n,s) #define UMM_REALLOC_FL(p,s,f,l) umm_poison_realloc_fl(p,s,f,l) #define UMM_FREE_FL(p,f,l) umm_poison_free_fl(p,f,l) +#define STATIC_ALWAYS_INLINE #undef realloc #undef free @@ -25,6 +31,7 @@ extern "C" { #define UMM_CALLOC(n,s) umm_calloc(n,s) #define UMM_REALLOC_FL(p,s,f,l) umm_realloc(p,s) #define UMM_FREE_FL(p,f,l) umm_free(p) +#define STATIC_ALWAYS_INLINE #undef realloc #undef free @@ -34,6 +41,10 @@ extern "C" { #define UMM_CALLOC(n,s) calloc(n,s) #define UMM_REALLOC_FL(p,s,f,l) realloc(p,s) #define UMM_FREE_FL(p,f,l) free(p) + +// STATIC_ALWAYS_INLINE only applys to the non-debug build path, +// it must not be enabled on the debug build path. +#define STATIC_ALWAYS_INLINE static ALWAYS_INLINE #endif @@ -164,8 +175,8 @@ void ICACHE_RAM_ATTR print_loc(size_t size, const char* file, int line) if (inISR && (uint32_t)file >= 0x40200000) { DEBUG_HEAP_PRINTF("File: %p", file); } else if (!inISR && (uint32_t)file >= 0x40200000) { - char buf[ets_strlen(file) + 1] __attribute__((aligned(4))); - ets_strcpy(buf, file); + char buf[strlen_P(file) + 1]; + strcpy_P(buf, file); DEBUG_HEAP_PRINTF(buf); } else { DEBUG_HEAP_PRINTF(file); @@ -259,8 +270,8 @@ void ICACHE_RAM_ATTR free(void* p) } #endif - -void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line) +STATIC_ALWAYS_INLINE +void* ICACHE_RAM_ATTR heap_pvPortMalloc(size_t size, const char* file, int line) { INTEGRITY_CHECK__PANIC_FL(file, line); POISON_CHECK__PANIC_FL(file, line); @@ -270,7 +281,8 @@ void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line) return ret; } -void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line) +STATIC_ALWAYS_INLINE +void* ICACHE_RAM_ATTR heap_pvPortCalloc(size_t count, size_t size, const char* file, int line) { INTEGRITY_CHECK__PANIC_FL(file, line); POISON_CHECK__PANIC_FL(file, line); @@ -280,7 +292,8 @@ void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, return ret; } -void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line) +STATIC_ALWAYS_INLINE +void* ICACHE_RAM_ATTR heap_pvPortRealloc(void *ptr, size_t size, const char* file, int line) { INTEGRITY_CHECK__PANIC_FL(file, line); void* ret = UMM_REALLOC_FL(ptr, size, file, line); @@ -290,7 +303,8 @@ void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, in return ret; } -void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line) +STATIC_ALWAYS_INLINE +void* ICACHE_RAM_ATTR heap_pvPortZalloc(size_t size, const char* file, int line) { INTEGRITY_CHECK__PANIC_FL(file, line); POISON_CHECK__PANIC_FL(file, line); @@ -300,7 +314,8 @@ void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line) return ret; } -void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line) +STATIC_ALWAYS_INLINE +void ICACHE_RAM_ATTR heap_vPortFree(void *ptr, const char* file, int line) { INTEGRITY_CHECK__PANIC_FL(file, line); UMM_FREE_FL(ptr, file, line); @@ -314,7 +329,47 @@ size_t ICACHE_RAM_ATTR xPortWantedSizeAlign(size_t size) void system_show_malloc(void) { + HeapSelectDram ephemeral; umm_info(NULL, true); } +/* + NONOS SDK and lwIP do not handle IRAM heap well. Since they also use portable + malloc calls pvPortMalloc, ... we can leverage that for this solution. + Force pvPortMalloc, ... APIs to serve DRAM only. +*/ +void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line) +{ + HeapSelectDram ephemeral; + return heap_pvPortMalloc(size, file, line);; +} + +void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line) +{ + HeapSelectDram ephemeral; + return heap_pvPortCalloc(count, size, file, line); +} + +void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line) +{ + HeapSelectDram ephemeral; + return heap_pvPortRealloc(ptr, size, file, line); +} + +void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line) +{ + HeapSelectDram ephemeral; + return heap_pvPortZalloc(size, file, line); +} + +void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line) +{ +#if defined(DEBUG_ESP_OOM) || defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE) || defined(UMM_INTEGRITY_CHECK) + // This is only needed for debug checks to ensure they are performed in + // correct context. umm_malloc free internally determines the correct heap. + HeapSelectDram ephemeral; +#endif + return heap_vPortFree(ptr, file, line); +} + }; diff --git a/cores/esp8266/umm_malloc/umm_malloc_cfg.h b/cores/esp8266/umm_malloc/umm_malloc_cfg.h index 1e5d7f8003..4fc059a49c 100644 --- a/cores/esp8266/umm_malloc/umm_malloc_cfg.h +++ b/cores/esp8266/umm_malloc/umm_malloc_cfg.h @@ -792,28 +792,29 @@ extern "C" { // Arduino.h recall us to redefine them #include // Reuse pvPort* calls, since they already support passing location information. -void* ICACHE_RAM_ATTR pvPortMalloc(size_t size, const char* file, int line); -void* ICACHE_RAM_ATTR pvPortCalloc(size_t count, size_t size, const char* file, int line); -void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line); -void* ICACHE_RAM_ATTR pvPortZalloc(size_t size, const char* file, int line); -void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line); +// Specificly the debug version (heap_...) that does not force DRAM heap. +void* ICACHE_RAM_ATTR heap_pvPortMalloc(size_t size, const char* file, int line); +void* ICACHE_RAM_ATTR heap_pvPortCalloc(size_t count, size_t size, const char* file, int line); +void* ICACHE_RAM_ATTR heap_pvPortRealloc(void *ptr, size_t size, const char* file, int line); +void* ICACHE_RAM_ATTR heap_pvPortZalloc(size_t size, const char* file, int line); +void ICACHE_RAM_ATTR heap_vPortFree(void *ptr, const char* file, int line); -#define malloc(s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; pvPortMalloc(s, mem_debug_file, __LINE__); }) -#define calloc(n,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; pvPortCalloc(n, s, mem_debug_file, __LINE__); }) -#define realloc(p,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; pvPortRealloc(p, s, mem_debug_file, __LINE__); }) +#define malloc(s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; heap_pvPortMalloc(s, mem_debug_file, __LINE__); }) +#define calloc(n,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; heap_pvPortCalloc(n, s, mem_debug_file, __LINE__); }) +#define realloc(p,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; heap_pvPortRealloc(p, s, mem_debug_file, __LINE__); }) #if defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE) -#define dbg_heap_free(p) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; vPortFree(p, mem_debug_file, __LINE__); }) +#define dbg_heap_free(p) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; heap_vPortFree(p, mem_debug_file, __LINE__); }) #else #define dbg_heap_free(p) free(p) #endif #elif defined(UMM_POISON_CHECK) || defined(UMM_POISON_CHECK_LITE) #include -void* ICACHE_RAM_ATTR pvPortRealloc(void *ptr, size_t size, const char* file, int line); -#define realloc(p,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; pvPortRealloc(p, s, mem_debug_file, __LINE__); }) +void* ICACHE_RAM_ATTR heap_pvPortRealloc(void *ptr, size_t size, const char* file, int line); +#define realloc(p,s) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; heap_pvPortRealloc(p, s, mem_debug_file, __LINE__); }) -void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line); +void ICACHE_RAM_ATTR heap_vPortFree(void *ptr, const char* file, int line); //C - to be discussed /* Problem, I would like to report the file and line number with the umm poison @@ -828,7 +829,7 @@ void ICACHE_RAM_ATTR vPortFree(void *ptr, const char* file, int line); Create dbg_heap_free() as an alternative for free() when you need a little more help in debugging the more challenging problems. */ -#define dbg_heap_free(p) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; vPortFree(p, mem_debug_file, __LINE__); }) +#define dbg_heap_free(p) ({ static const char mem_debug_file[] PROGMEM STORE_ATTR = __FILE__; heap_vPortFree(p, mem_debug_file, __LINE__); }) #else #define dbg_heap_free(p) free(p) From 4777cfa5021502696f28535e777e504b7c4033a7 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Tue, 22 Dec 2020 14:51:34 -0800 Subject: [PATCH 3/4] revert print_loc premature change --- cores/esp8266/heap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/heap.cpp b/cores/esp8266/heap.cpp index c2473a0e45..2be2499ea0 100644 --- a/cores/esp8266/heap.cpp +++ b/cores/esp8266/heap.cpp @@ -175,8 +175,8 @@ void ICACHE_RAM_ATTR print_loc(size_t size, const char* file, int line) if (inISR && (uint32_t)file >= 0x40200000) { DEBUG_HEAP_PRINTF("File: %p", file); } else if (!inISR && (uint32_t)file >= 0x40200000) { - char buf[strlen_P(file) + 1]; - strcpy_P(buf, file); + char buf[ets_strlen(file) + 1] __attribute__((aligned(4))); + ets_strcpy(buf, file); DEBUG_HEAP_PRINTF(buf); } else { DEBUG_HEAP_PRINTF(file); From 0e80628ed096ff573ecf45401dab5029c6f853b2 Mon Sep 17 00:00:00 2001 From: M Hightower <27247790+mhightower83@users.noreply.github.com> Date: Wed, 23 Dec 2020 08:50:23 -0800 Subject: [PATCH 4/4] Renamed macro to be more specific, FORCE_ALWAYS_INLINE to FORCE_ALWAYS_INLINE_HEAP_SELECT --- cores/esp8266/heap.cpp | 2 +- cores/esp8266/umm_malloc/umm_heap_select.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/heap.cpp b/cores/esp8266/heap.cpp index 2be2499ea0..4821f9b772 100644 --- a/cores/esp8266/heap.cpp +++ b/cores/esp8266/heap.cpp @@ -7,7 +7,7 @@ #include "umm_malloc/umm_malloc.h" // Need FORCE_ALWAYS_INLINE to put HeapSelect class constructor/deconstructor in IRAM -#define FORCE_ALWAYS_INLINE +#define FORCE_ALWAYS_INLINE_HEAP_SELECT #include "umm_malloc/umm_heap_select.h" #include diff --git a/cores/esp8266/umm_malloc/umm_heap_select.h b/cores/esp8266/umm_malloc/umm_heap_select.h index c0ddc31d9d..1a3728d7aa 100644 --- a/cores/esp8266/umm_malloc/umm_heap_select.h +++ b/cores/esp8266/umm_malloc/umm_heap_select.h @@ -9,7 +9,7 @@ // Use FORCE_ALWAYS_INLINE to ensure HeapSelect... construtor/deconstructor // are placed in IRAM -#ifdef FORCE_ALWAYS_INLINE +#ifdef FORCE_ALWAYS_INLINE_HEAP_SELECT #define MAYBE_ALWAYS_INLINE ALWAYS_INLINE #else #define MAYBE_ALWAYS_INLINE