Add heap tracing capability to API component

- Add heap tracing configuration options to API component
- Implement periodic heap trace dumping (every 30 seconds)
- Configure ESP-IDF settings for heap tracing
- Add sample YAML configuration
- Useful for debugging memory reallocation overhead issues
This commit is contained in:
J. Nick Koston 2025-05-08 15:25:06 -05:00
parent 8e29437900
commit 35238c1437
No known key found for this signature in database
3 changed files with 135 additions and 1 deletions

View File

@ -1,8 +1,10 @@
import base64
import logging
from esphome import automation
from esphome.automation import Condition
import esphome.codegen as cg
from esphome.components.esp32 import add_idf_sdkconfig_option
import esphome.config_validation as cv
from esphome.const import (
CONF_ACTION,
@ -23,12 +25,14 @@ from esphome.const import (
CONF_TRIGGER_ID,
CONF_VARIABLES,
)
from esphome.core import coroutine_with_priority
from esphome.core import CORE, coroutine_with_priority
DEPENDENCIES = ["network"]
AUTO_LOAD = ["socket"]
CODEOWNERS = ["@OttoWinter"]
_LOGGER = logging.getLogger(__name__)
api_ns = cg.esphome_ns.namespace("api")
APIServer = api_ns.class_("APIServer", cg.Component, cg.Controller)
HomeAssistantServiceCallAction = api_ns.class_(
@ -49,6 +53,9 @@ SERVICE_ARG_NATIVE_TYPES = {
"string[]": cg.std_vector.template(cg.std_string),
}
CONF_ENCRYPTION = "encryption"
CONF_HEAP_TRACING = "heap_tracing"
CONF_HEAP_TRACING_STANDALONE = "standalone" # vs SYSTEM
CONF_HEAP_TRACING_RECORDS = "num_records"
def validate_encryption_key(value):
@ -95,6 +102,20 @@ def _encryption_schema(config):
return ENCRYPTION_SCHEMA(config)
HEAP_TRACING_SCHEMA = cv.Schema(
{
cv.Optional(CONF_HEAP_TRACING_STANDALONE, default=True): cv.boolean,
cv.Optional(CONF_HEAP_TRACING_RECORDS, default=100): cv.positive_int,
}
)
def _heap_tracing_schema(config):
if config is None:
config = {}
return HEAP_TRACING_SCHEMA(config)
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
@ -109,6 +130,7 @@ CONFIG_SCHEMA = cv.All(
): ACTIONS_SCHEMA,
cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA,
cv.Optional(CONF_ENCRYPTION): _encryption_schema,
cv.Optional(CONF_HEAP_TRACING): _heap_tracing_schema,
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
single=True
),
@ -176,6 +198,59 @@ async def to_code(config):
else:
cg.add_define("USE_API_PLAINTEXT")
# Handle heap tracing configuration if ESP32 platform and using ESP-IDF
if (heap_tracing_config := config.get(CONF_HEAP_TRACING, None)) is not None:
if CORE.using_esp_idf:
# Enable heap tracing in sdkconfig
add_idf_sdkconfig_option("CONFIG_HEAP_TRACING", True)
# Set tracing mode (standalone or system)
if heap_tracing_config[CONF_HEAP_TRACING_STANDALONE]:
add_idf_sdkconfig_option("CONFIG_HEAP_TRACING_STANDALONE", True)
else:
add_idf_sdkconfig_option("CONFIG_HEAP_TRACING_SYSTEM", True)
# Generate code to implement heap tracing
cg.add_global(cg.RawStatement('#include "esp_heap_trace.h"'))
# Define the trace record buffer
num_records = heap_tracing_config[CONF_HEAP_TRACING_RECORDS]
cg.add_global(
cg.RawStatement(
f"static heap_trace_record_t trace_record[{num_records}];"
)
)
# Add helper functions for heap tracing
cg.add_global(
cg.RawStatement(
"""
void start_heap_trace() {
heap_trace_init_standalone(trace_record, """
+ str(num_records)
+ """);
heap_trace_start(HEAP_TRACE_LEAKS);
}
void stop_and_dump_heap_trace() {
heap_trace_stop();
heap_trace_dump();
}
"""
)
)
# Add periodic heap trace dumping to the api_server.cpp file
# This will be added in C++ code
cg.add_define("USE_API_HEAP_TRACE")
else:
# Not using ESP-IDF, so we can't use heap tracing
_LOGGER.warning(
"Heap tracing is only available when using ESP-IDF. "
"Disabling heap tracing configuration."
)
cg.add_define("USE_API")
cg.add_global(api_ns.using)

View File

@ -30,6 +30,11 @@ void APIServer::setup() {
ESP_LOGCONFIG(TAG, "Setting up Home Assistant API server...");
this->setup_controller();
#ifdef USE_API_HEAP_TRACE
ESP_LOGI(TAG, "Initializing heap tracing");
start_heap_trace();
#endif
#ifdef USE_API_NOISE
uint32_t hash = 88491486UL;
@ -154,6 +159,21 @@ void APIServer::loop() {
this->status_clear_warning();
}
}
#ifdef USE_API_HEAP_TRACE
// Periodically dump heap trace information (every 30 seconds)
static uint32_t last_heap_trace_dump = 0;
const uint32_t now = millis();
if (now - last_heap_trace_dump > 30000) { // 30 seconds
ESP_LOGI(TAG, "Dumping heap trace information");
stop_and_dump_heap_trace();
// Start a new trace for the next period
start_heap_trace();
last_heap_trace_dump = now;
}
#endif
}
void APIServer::dump_config() {
@ -466,6 +486,12 @@ void APIServer::on_shutdown() {
c->send_disconnect_request(DisconnectRequest());
}
delay(10);
#ifdef USE_API_HEAP_TRACE
// Make sure to stop tracing on shutdown to get final results
ESP_LOGI(TAG, "Final heap trace dump on shutdown");
stop_and_dump_heap_trace();
#endif
}
} // namespace api

33
heap_trace_example.yaml Normal file
View File

@ -0,0 +1,33 @@
esphome:
name: esp32-heap-trace
platform: ESP32
board: esp32dev
# Use ESP-IDF framework which is required for heap tracing
framework:
type: esp-idf
version: recommended
# Enable logging
logger:
level: INFO
# Enable Home Assistant API
api:
# Enable heap tracing with the following configuration
heap_tracing:
# Use standalone tracing (vs system tracing)
standalone: true
# Number of trace records to keep (more records = more memory usage)
num_records: 100
# Enable OTA updates
ota:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot in case wifi connection fails
ap:
ssid: "Esp32-Heap-Trace"
password: "12345678"