ESP8266: fix heap metric functions and add OOM diagnostics#24777
Open
joluxer wants to merge 2 commits into
Open
ESP8266: fix heap metric functions and add OOM diagnostics#24777joluxer wants to merge 2 commits into
joluxer wants to merge 2 commits into
Conversation
Both functions returned wrong values: ESP_getMaxAllocHeap() returned ESP.getFreeHeap() (total free, not largest contiguous block); ESP_getHeapFragmentation() read ummHeapInfo.maxFreeContiguousBlocks, which is only valid immediately after a umm_info() heap walk. Fix: cache the result of umm_max_block_size() in ESP_UpdateHeapMetrics(). The cache is refreshed once per second when SetOption130 is active, and on demand in CmndStatus() before Status 4 is output. Both getter functions read the cached value; the call site overhead is a single integer read. umm_max_block_size() is unconditionally available (UMM_INFO is hardcoded in the Arduino ESP8266 umm_malloc_cfg.h), so no build flags are required. Status 4 (StatusMEM) gains two ESP8266-specific fields: MaxFreeBlock (KB) and Frag (%).
OOM event monitoring (requires UMM_INLINE_METRICS or UMM_STATS_FULL):
- ESP_HeapOomCheck(): called once per second; logs the OOM counter delta
when the counter changes ("OOM: count N (+M)")
- ESP_HeapOomTest(): logs current OOM count on demand
Status 4 (StatusMEM) gains additional ESP8266-specific fields when the
corresponding build flags are active:
- OomCount: cumulative out-of-memory events (UMM_INLINE_METRICS or
UMM_STATS_FULL)
- HeapLwm (KB): heap low-watermark since boot (UMM_STATS_FULL)
- MaxAllocSz (bytes): peak single allocation size (UMM_STATS_FULL)
Status 44 (ESP8266-only diagnostic command):
- Triggers umm_info(nullptr, true) to print a full heap block map to
the serial console
- Calls ESP_HeapOomTest() to log the current OOM count
- Returns {"Status44":{"HeapDump":"serial"}}
- Status 44 is accepted regardless of MAX_STATUS
Build flags UMM_STATS_FULL and UMM_INLINE_METRICS can be enabled via
platformio_override.ini build_flags; documented in
platformio_override_sample.ini.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description:
Checklist:
Summary
Two commits addressing ESP8266 heap observability. Commit 1 is self-contained
and useful independently; Commit 2 builds on the corrected metric functions.
Commit 1 - Adapt ESP_getMaxAllocHeap() and ESP_getHeapFragmentation()
Problem:
ESP_getMaxAllocHeap()returnedESP.getFreeHeap()(total free heap, not thelargest contiguous allocatable block).
ESP_getHeapFragmentation()readummHeapInfo.maxFreeContiguousBlocks, whichis only valid immediately after a
umm_info()heap walk - stale or zero otherwise.Fix:
Both functions now align with their ESP32 equivalents, returning accurate live
values derived from
umm_max_block_size()andumm_free_heap_size_lw().A new
ESP_UpdateHeapMetrics()caches the result ofumm_max_block_size()(heap walk, brief IRQ disable). The cache is refreshed:
PerformEverySecond()when SetOption130 is activeCmndStatus()before Status 4 outputumm_max_block_size()andumm_free_heap_size_lw()are unconditionallyavailable (UMM_INFO and UMM_STATS are hardcoded in
umm_malloc_cfg.h);no additional build flags are required.
Observable changes:
percentage. Format changes from
HH:MM:SS.mmm-FreeKBtoHH:MM:SS.mmm-FreeKB/Frag%. Log parsers using the ESP8266-specificsingle-field format will need updating. The new format matches ESP32 behavior.
MaxFreeBlock(KB) andFrag(%).Commit 2 - OOM diagnostics, Status 4 extensions, Status 44 heap dump
Opt-in heap diagnostics gated on
UMM_INLINE_METRICSorUMM_STATS_FULLbuild flags. Without these flags: no runtime behavior change.
OOM event monitoring (requires
UMM_INLINE_METRICSorUMM_STATS_FULL):ESP_HeapOomCheck(): called once per second; logs OOM counter delta onchange (
OOM: count N (+M))ESP_HeapOomTest(): logs current OOM count on demandAdditional Status 4 fields:
OomCount- cumulative OOM events (UMM_INLINE_METRICSorUMM_STATS_FULL)HeapLwm(KB) - heap low-watermark since boot (UMM_STATS_FULL)MaxAllocSz(bytes) - peak single allocation size (UMM_STATS_FULL)Status 44 (ESP8266-only):
umm_info(nullptr, true): prints full heap block map to serial{"Status44":{"HeapDump":"serial"}}and below the reserved value 99 (full status dump)
Enabling the diagnostic flags:
The flags must reach the ESP8266 Arduino framework's
umm_mallocallocator,which is compiled separately from the Tasmota sketch.
user_config_override.haffects only sketch compilation units and cannot reach the framework.
The required mechanism is
build_flagsinplatformio_override.ini:Example lines are added to
platformio_override_sample.ini.Memory impact (ESP8266, tasmota release build)
UMM_*flagsThe +300 B IRAM with flags is attributable to OOM monitoring functions
compiled IRAM-resident. This applies only to explicit diagnostic builds;
standard release builds are unaffected (0 IRAM impact).
Tested
Developed and initially tested on Tasmota v15.4.0, ESP-12F.
Build-tested and target-tested on the development branch.
SetOption130 active in both captures below.
Before (upstream development, no flags):
After (this PR,
UMM_STATS_FULL+UMM_INLINE_METRICSactive):Visible changes:
-024→-023/02(FreeKB → FreeKB/Frag%)MaxFreeBlock,Frag,OomCount,HeapLwm,MaxAllocSzProgramSizedelta: 659 → 662 KB (+3 KB, consistent with measured flash impact)Status 44 (heap block map printed to serial, excerpt;
heap map format reference:
source - umm_info.c in ESP8266 Arduino core /
docs - rhempel/umm_malloc):