Add define USE_ESP8266_DEBUG_HEAP to control (#24777)

This commit is contained in:
Theo Arends
2026-05-25 17:27:32 +02:00
parent ba88358ed6
commit 6300b542ee
5 changed files with 87 additions and 57 deletions
+1
View File
@@ -1354,6 +1354,7 @@
//#define DEBUG_TASMOTA_DRIVER // Enable driver debug messages
//#define DEBUG_TASMOTA_SENSOR // Enable sensor debug messages
//#define USE_DEBUG_DRIVER // Use xdrv_99_debug.ino providing commands CpuChk, CfgXor, CfgDump, CfgPeek and CfgPoke
//#define USE_ESP8266_DEBUG_HEAP // Add heap fragmentation display support. Needs build_flags -DUMM_STATS_FULL and -DUMM_INLINE_METRICS too (+2k5 code)
/*********************************************************************************************\
* Profiling features
+10 -1
View File
@@ -2804,12 +2804,21 @@ void AddLogData(uint32_t loglevel, const char* log_data, const char* log_data_pa
TasAutoMutex mutex((SemaphoreHandle_t *)&TasmotaGlobal.log_buffer_mutex);
#endif // ESP32
char mxtime[25]; // "13:45:21.999-123/12 " or with fragmentation suffix
char mxtime[21]; // "13:45:21.999-123/12 "
snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d.%03d"),
RtcTime.hour, RtcTime.minute, RtcTime.second, RtcMillis());
if (Settings->flag5.show_heap_with_timestamp) {
#ifdef ESP8266
snprintf_P(mxtime, sizeof(mxtime), PSTR("%s-%03d"),
mxtime, ESP_getFreeHeap1024());
#ifdef USE_ESP8266_DEBUG_HEAP
snprintf_P(mxtime, sizeof(mxtime), PSTR("%s/%02d"),
mxtime, ESP_getHeapFragmentation());
#endif // USE_ESP8266_DEBUG_HEAP
#else // ESP32
snprintf_P(mxtime, sizeof(mxtime), PSTR("%s-%03d/%02d"),
mxtime, ESP_getFreeHeap1024(), ESP_getHeapFragmentation());
#endif // ESP8266 or ESP32
}
strcat(mxtime, " ");
+33 -44
View File
@@ -17,10 +17,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef ESP8266
#include <umm_malloc/umm_malloc_cfg.h>
#endif
const char kTasmotaCommands[] PROGMEM = "|" // No prefix
// SetOptions synonyms
D_SO_WIFINOSLEEP "|"
@@ -905,11 +901,15 @@ void CmndStatus(void)
if (0 == XdrvMailbox.index) { payload = 0; } // All status messages in one MQTT message (status0)
while (payload > MAX_STATUS) {
#ifdef ESP8266
if (payload > MAX_STATUS && 44 != payload) { return; } // {"Command":"Error"}
#else
if (payload > MAX_STATUS) { return; } // {"Command":"Error"}
#endif
#ifdef USE_ESP8266_DEBUG_HEAP
if (44 == payload) { break; }
#endif // USE_ESP8266_DEBUG_HEAP
#endif // ESP8266
return; // {"Command":"Error"}
}
if (!Settings->flag.mqtt_enabled && (6 == payload)) { return; } // SetOption3 - Enable MQTT
if (!TasmotaGlobal.energy_driver && (9 == payload)) { return; }
#ifndef FIRMWARE_MINIMAL
@@ -1027,37 +1027,28 @@ void CmndStatus(void)
// Status 4 - StatusMEM
if ((0 == payload) || (4 == payload)) {
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_JSON_PROGRAMSIZE "\":%d,\"" D_JSON_FREEMEMORY "\":%d,\"" D_JSON_HEAPSIZE "\":%d,\""
#ifdef ESP32
D_JSON_STACKLOWMARK "\":%d,\"" D_JSON_PSRMAXMEMORY "\":%d,\"" D_JSON_PSRFREEMEMORY "\":%d,\""
#endif // ESP32
D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d"
",\"" D_JSON_FLASHCHIPID "\":\"%06X\""
",\"FlashFrequency\":%d,\"" D_JSON_FLASHMODE "\":\"" D_TASMOTA_FLASHMODE "\""),
ESP_getSketchSize()/1024, ESP_getFreeSketchSpace()/1024, ESP_getFreeHeap1024(),
#ifdef ESP32
uxTaskGetStackHighWaterMark(nullptr) / 1024, ESP.getPsramSize()/1024, ESP.getFreePsram()/1024,
ESP_getFlashChipMagicSize()/1024, ESP.getFlashChipSize()/1024
#endif // ESP32
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS4_MEMORY "\":{\"" D_JSON_PROGRAMSIZE "\":%d,\"" D_JSON_FREEMEMORY "\":%d,\"" D_JSON_HEAPSIZE "\":%d"),
ESP_getSketchSize()/1024, ESP_getFreeSketchSpace()/1024, ESP_getFreeHeap1024());
#ifdef ESP8266
#ifdef USE_ESP8266_DEBUG_HEAP
ResponseAppendHeapInfo();
#endif // USE_ESP8266_DEBUG_HEAP
#else // ESP32
ResponseAppend_P(PSTR(",\"" D_JSON_STACKLOWMARK "\":%d,\"" D_JSON_PSRMAXMEMORY "\":%d,\"" D_JSON_PSRFREEMEMORY "\":%d"),
uxTaskGetStackHighWaterMark(nullptr) / 1024, ESP.getPsramSize()/1024, ESP.getFreePsram()/1024);
#endif // ESP8266 or ESP32
ResponseAppend_P(PSTR(",\"" D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d"
",\"" D_JSON_FLASHCHIPID "\":\"%06X\",\"FlashFrequency\":%d"
",\"" D_JSON_FLASHMODE "\":\"" D_TASMOTA_FLASHMODE "\""),
#ifdef ESP8266
ESP_getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024
#endif // ESP8266
, ESP_getFlashChipId()
, ESP_getFlashChipSpeed()/1000000);
#ifdef ESP8266
ESP_UpdateHeapMetrics();
ResponseAppend_P(PSTR(",\"MaxFreeBlock\":%d,\"Frag\":%d"),
(uint32_t)ESP_getMaxAllocHeap()/1024,
(int32_t)ESP_getHeapFragmentation());
#if defined(UMM_INLINE_METRICS) || defined(UMM_STATS_FULL)
ResponseAppend_P(PSTR(",\"OomCount\":%d"), (uint32_t)umm_get_oom_count());
#endif
#ifdef UMM_STATS_FULL
ResponseAppend_P(PSTR(",\"HeapLwm\":%d,\"MaxAllocSz\":%d"),
(uint32_t)umm_free_heap_size_lw_min()/1024,
(uint32_t)umm_get_max_alloc_size());
#endif // UMM_STATS_FULL
#endif // ESP8266
#else // ESP32
ESP_getFlashChipMagicSize()/1024, ESP.getFlashChipSize()/1024
#endif // ESP8266 or ESP32
, ESP_getFlashChipId(), ESP_getFlashChipSpeed()/1000000);
ResponseAppendFeatures();
XsnsDriverState();
ResponseAppend_P(PSTR(",\"Sensors\":"));
@@ -1207,16 +1198,14 @@ void CmndStatus(void)
#endif
#ifdef ESP8266
// Status 44 - trigger umm heap dump to serial + OOM test
// ESP8266-only heap diagnostic. Chosen above the standard range
// (0-MAX_STATUS = 0-13) and below the reserved value 99 (full status dump).
#ifdef USE_ESP8266_DEBUG_HEAP
// Status 44 - Trigger umm heap dump to serial + OOM test
if (44 == payload) {
umm_info(nullptr, true);
ESP_HeapOomTest();
Response_P(PSTR("{\"" D_CMND_STATUS "44\":{\"HeapDump\":\"serial\"}}"));
SerialHeapDump();
Response_P(PSTR("{\"" D_CMND_STATUS "44\":{\"HeapDump\":\"Serial output only\"}}"));
CmndStatusResponse(44);
return;
}
#endif // USE_ESP8266_DEBUG_HEAP
#endif // ESP8266
CmndStatusResponse(99);
+39 -7
View File
@@ -106,20 +106,28 @@ float ESP_getFreeHeap1024(void) {
}
*/
#ifndef USE_ESP8266_DEBUG_HEAP
uint32_t ESP_getMaxAllocHeap(void) {
return ESP.getFreeHeap();
}
#else
// umm_max_block_size() requires a heap walk (ICACHE_FLASH_ATTR, IRQs disabled).
// Cache the result; refresh once per second via ESP_UpdateHeapMetrics().
// umm_max_block_size() and umm_free_heap_size_lw() are available unconditionally
// (UMM_INFO and UMM_STATS are hardcoded active in umm_malloc_cfg.h).
static uint32_t s_umm_max_free_block = 0;
void ESP_UpdateHeapMetrics(void) {
s_umm_max_free_block = umm_max_block_size();
}
uint32_t ESP_getMaxAllocHeap(void) {
return s_umm_max_free_block ? s_umm_max_free_block : ESP.getFreeHeap();
}
void ESP_UpdateHeapMetrics(void) {
s_umm_max_free_block = umm_max_block_size(); // ESP.getMaxFreeBlockSize();
}
int32_t ESP_getHeapFragmentation(void) {
// Same formula as ESP32: 100 - (largestFreeBlock * 100 / totalFree)
uint32_t free_heap = umm_free_heap_size_lw(); // ISR-safe, no heap walk
@@ -128,7 +136,10 @@ int32_t ESP_getHeapFragmentation(void) {
return (frag < 0) ? 0 : frag;
}
void ESP_HeapOomCheck(void) {
void ESP_HeapUsageUpdate(void) {
if (Settings->flag5.show_heap_with_timestamp) {
ESP_UpdateHeapMetrics();
}
#if defined(UMM_INLINE_METRICS) || defined(UMM_STATS_FULL)
static size_t oom_prev = 0;
size_t oom = UMM_OOM_COUNT;
@@ -139,12 +150,33 @@ void ESP_HeapOomCheck(void) {
#endif
}
void ESP_HeapOomTest(void) {
void ResponseAppendHeapInfo(void) {
ESP_UpdateHeapMetrics();
ResponseAppend_P(PSTR(",\"MaxFree\":%d,\"Frag\":%d"),
(uint32_t)ESP_getMaxAllocHeap()/1024,
(int32_t)ESP_getHeapFragmentation());
#if defined(UMM_INLINE_METRICS) || defined(UMM_STATS_FULL)
ResponseAppend_P(PSTR(",\"OomCount\":%d"), (uint32_t)umm_get_oom_count());
#endif
#ifdef UMM_STATS_FULL
ResponseAppend_P(PSTR(",\"HeapLwm\":%d,\"MaxAllocSz\":%d"),
(uint32_t)umm_free_heap_size_lw_min()/1024,
(uint32_t)umm_get_max_alloc_size());
#endif // UMM_STATS_FULL
}
void SerialHeapDump(void) {
// Status 44 - trigger umm heap dump to serial + OOM test
// ESP8266-only heap diagnostic. Chosen above the standard range
// (0-MAX_STATUS = 0-13) and below the reserved value 99 (full status dump).
umm_info(nullptr, true);
#if defined(UMM_INLINE_METRICS) || defined(UMM_STATS_FULL)
AddLog(LOG_LEVEL_INFO, PSTR("OOM: count %u (test-trigger)"), (uint32_t)umm_get_oom_count());
#endif
}
#endif // USE_ESP8266_DEBUG_HEAP
uint32_t ESP_getFlashChipId(void) {
return ESP.getFlashChipId();
}
@@ -349,4 +381,4 @@ extern "C" void __wrap_sntp_stop(void) {
// Prevent lwIP SNTP client from stopping on WiFi disconnects and causing timeout list corruption
}
#endif // ESP8266
#endif // ESP8266
+4 -5
View File
@@ -1128,11 +1128,10 @@ void PerformEverySecond(void)
TasmotaGlobal.uptime++;
#ifdef ESP8266
if (Settings->flag5.show_heap_with_timestamp) {
ESP_UpdateHeapMetrics();
}
ESP_HeapOomCheck();
#endif
#ifdef USE_ESP8266_DEBUG_HEAP
ESP_HeapUsageUpdate();
#endif // USE_ESP8266_DEBUG_HEAP
#endif // ESP8266
if (POWER_CYCLE_TIME == TasmotaGlobal.uptime) {
UpdateQuickPowerCycle(false);