From a60f98a4c6a4a2270e8a03c36e6d777be354e263 Mon Sep 17 00:00:00 2001 From: chenjintao Date: Fri, 21 Aug 2026 17:46:19 +0800 Subject: [PATCH] fix(control-plane): optimize task monitoring and worker stacks --- .../control_plane_multimodal_runtime.c | 6 +- .../src/runtime/control_plane_factory_cli.c | 6 +- .../runtime/control_plane_runtime_workers.c | 120 ++++++++++++++---- .../src/runtime/control_plane_system_events.c | 2 +- main/Kconfig.projbuild | 35 ++++- sdkconfig.defaults | 7 +- 6 files changed, 139 insertions(+), 37 deletions(-) diff --git a/components/control_plane/src/multimodal/control_plane_multimodal_runtime.c b/components/control_plane/src/multimodal/control_plane_multimodal_runtime.c index 2031d08..4581efb 100644 --- a/components/control_plane/src/multimodal/control_plane_multimodal_runtime.c +++ b/components/control_plane/src/multimodal/control_plane_multimodal_runtime.c @@ -36,10 +36,14 @@ #define CONFIG_MULTIMODAL_AUDIO_PREWARM_OPUS_BEFORE_WS 1 #endif +#ifndef CONFIG_TQ_MULTIMODAL_WATCHDOG_TASK_STACK_BYTES +#define CONFIG_TQ_MULTIMODAL_WATCHDOG_TASK_STACK_BYTES (6U * 1024U) +#endif + #define CONTROL_PLANE_DOWNSTREAM_PLAYBACK_GUARD_MS 220 #define CONTROL_PLANE_DOWNSTREAM_STALL_STOP_GRACE_MS 2000 #define CONTROL_PLANE_IDLE_TRANSPORT_SHUTDOWN_MS 30000 -#define CONTROL_PLANE_WATCHDOG_TASK_STACK_SIZE 8192 +#define CONTROL_PLANE_WATCHDOG_TASK_STACK_SIZE CONFIG_TQ_MULTIMODAL_WATCHDOG_TASK_STACK_BYTES #define CONTROL_PLANE_SERVER_SUCCESS_PROMPT_FILE "/littlefs/audio_prompts/server_connect_success.opus" #define CONTROL_PLANE_CLIENT_LIFECYCLE_WAIT_MS 30000U #define CONTROL_PLANE_SERVER_SUCCESS_PROMPT_RETRY_MS 1000U diff --git a/components/control_plane/src/runtime/control_plane_factory_cli.c b/components/control_plane/src/runtime/control_plane_factory_cli.c index 6370729..cabf7e2 100644 --- a/components/control_plane/src/runtime/control_plane_factory_cli.c +++ b/components/control_plane/src/runtime/control_plane_factory_cli.c @@ -30,7 +30,11 @@ #define FACTORY_CLI_SERIAL_MAX_LEN 64 #define FACTORY_CLI_JSON_MAX_LEN 640 #define FACTORY_CLI_READ_TIMEOUT_MS 100 -#define FACTORY_CLI_WORKER_STACK_BYTES (12U * 1024U) +#ifndef CONFIG_TQ_FACTORY_CLI_TASK_STACK_BYTES +#define CONFIG_TQ_FACTORY_CLI_TASK_STACK_BYTES (10U * 1024U) +#endif + +#define FACTORY_CLI_WORKER_STACK_BYTES CONFIG_TQ_FACTORY_CLI_TASK_STACK_BYTES #define FACTORY_CLI_WORKER_PRIORITY 4 #define FACTORY_CLI_STOP_WAIT_STEPS 100 #define FACTORY_CLI_STOP_WAIT_STEP_MS 20 diff --git a/components/control_plane/src/runtime/control_plane_runtime_workers.c b/components/control_plane/src/runtime/control_plane_runtime_workers.c index 51c3fed..444c207 100644 --- a/components/control_plane/src/runtime/control_plane_runtime_workers.c +++ b/components/control_plane/src/runtime/control_plane_runtime_workers.c @@ -20,10 +20,16 @@ #include "freertos/task.h" #include "sdkconfig.h" +#ifndef CONFIG_TQ_LCD_RENDER_TASK_STACK_BYTES +#define CONFIG_TQ_LCD_RENDER_TASK_STACK_BYTES (10U * 1024U) +#endif + #define CONTROL_PLANE_MODEL_CMD_TASK_STACK_SIZE (1024 * 4) -#define CONTROL_PLANE_LCD_RENDER_LOOP_TASK_STACK_SIZE (1024 * 12) +#define CONTROL_PLANE_LCD_RENDER_LOOP_TASK_STACK_SIZE CONFIG_TQ_LCD_RENDER_TASK_STACK_BYTES #define CONTROL_PLANE_WIFI_STATE_TASK_STACK_SIZE (1024 * 10) #define CONTROL_PLANE_TASK_MONITOR_TASK_STACK_SIZE (1024 * 4) +#define CONTROL_PLANE_TASK_MONITOR_STACK_WARN_BYTES 1024U +#define CONTROL_PLANE_TASK_MONITOR_FULL_REPORT_PERIOD 5U #define CONTROL_PLANE_REMOTE_LOG_STOP_WAIT_MS 1500 #define CONTROL_PLANE_MODEL_CMD_QUEUE_LEN 4 #define CONTROL_PLANE_MODEL_CMD_RECV_TIMEOUT_MS 200 @@ -1404,7 +1410,39 @@ static const char *control_plane_task_core_name(BaseType_t core_id, return buffer; } -static void control_plane_log_task_table(void) +static void control_plane_log_task_status(const TaskStatus_t *task, bool warn) +{ + if (task == NULL) { + return; + } + + char core_buf[12] = {0}; + const char *name = task->pcTaskName != NULL ? task->pcTaskName : "?"; + const char *state = control_plane_task_state_name(task->eCurrentState); + const char *core = control_plane_task_core_name( + xTaskGetCoreID(task->xHandle), core_buf, sizeof(core_buf)); + if (warn) { + ESP_LOGW(TAG, + "Task stack headroom low: name=%s state=%s priority=%u headroom=%uB core=%s", + name, + state, + (unsigned int)task->uxCurrentPriority, + (unsigned int)task->usStackHighWaterMark, + core); + return; + } + + ESP_LOGI(TAG, + "%-16s %-5s %-4u %-10u %-4s %-10lu", + name, + state, + (unsigned int)task->uxCurrentPriority, + (unsigned int)task->usStackHighWaterMark, + core, + (unsigned long)task->ulRunTimeCounter); +} + +static void control_plane_log_task_table(bool full_report) { #if !configUSE_TRACE_FACILITY ESP_LOGW(TAG, "Task monitor requires CONFIG_FREERTOS_USE_TRACE_FACILITY"); @@ -1422,42 +1460,61 @@ static void control_plane_log_task_table(void) return; } - TaskStatus_t *tasks = (TaskStatus_t *)calloc(capture_count, sizeof(TaskStatus_t)); + TaskStatus_t *tasks = (TaskStatus_t *)heap_caps_calloc( + capture_count, + sizeof(TaskStatus_t), + MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); if (tasks == NULL) { - ESP_LOGW(TAG, "Task monitor allocation failed: entries=%u", + ESP_LOGW(TAG, "Task monitor PSRAM snapshot allocation failed: entries=%u", (unsigned int)capture_count); return; } uint32_t total_runtime = 0; UBaseType_t captured = uxTaskGetSystemState(tasks, capture_count, &total_runtime); + const TaskStatus_t *lowest = NULL; + UBaseType_t low_count = 0U; + for (UBaseType_t i = 0; i < captured; ++i) { + if (lowest == NULL || + tasks[i].usStackHighWaterMark < lowest->usStackHighWaterMark) { + lowest = &tasks[i]; + } + if (tasks[i].usStackHighWaterMark < + CONTROL_PLANE_TASK_MONITOR_STACK_WARN_BYTES) { + low_count++; + } + } ESP_LOGI(TAG, - "Task monitor: total=%u captured=%u runtime=%lu", + "Task monitor summary: total=%u captured=%u runtime=%lu lowest=%s/%uB low=%u snapshot=PSRAM full=%d", (unsigned int)task_count, (unsigned int)captured, - (unsigned long)total_runtime); - ESP_LOGI(TAG, "%-16s %-5s %-4s %-7s %-4s %-10s", + (unsigned long)total_runtime, + lowest != NULL && lowest->pcTaskName != NULL ? lowest->pcTaskName : "?", + lowest != NULL ? (unsigned int)lowest->usStackHighWaterMark : 0U, + (unsigned int)low_count, + full_report ? 1 : 0); + if (!full_report) { + heap_caps_free(tasks); + return; + } + + ESP_LOGI(TAG, "%-16s %-5s %-4s %-10s %-4s %-10s", "name", "state", "prio", - "stack", + "headroom", "core", "runtime"); for (UBaseType_t i = 0; i < captured; ++i) { - char core_buf[12] = {0}; - ESP_LOGI(TAG, - "%-16s %-5s %-4u %-7u %-4s %-10lu", - tasks[i].pcTaskName != NULL ? tasks[i].pcTaskName : "?", - control_plane_task_state_name(tasks[i].eCurrentState), - (unsigned int)tasks[i].uxCurrentPriority, - (unsigned int)tasks[i].usStackHighWaterMark, - control_plane_task_core_name(xTaskGetCoreID(tasks[i].xHandle), core_buf, sizeof(core_buf)), - (unsigned long)tasks[i].ulRunTimeCounter); + control_plane_log_task_status( + &tasks[i], + tasks[i].usStackHighWaterMark < + CONTROL_PLANE_TASK_MONITOR_STACK_WARN_BYTES); } - free(tasks); + heap_caps_free(tasks); #endif } @@ -1466,9 +1523,11 @@ static void control_plane_task_monitor_task(void *arg) (void)arg; ESP_LOGI(TAG, - "Task monitor started interval=%dms max_tasks=%d", + "Task monitor started interval=%dms max_tasks=%d stack=PSRAM-preferred snapshot=PSRAM full_period=%u warn=%uB", CONFIG_TQ_TASK_MONITOR_INTERVAL_MS, - CONFIG_TQ_TASK_MONITOR_MAX_TASKS); + CONFIG_TQ_TASK_MONITOR_MAX_TASKS, + (unsigned)CONTROL_PLANE_TASK_MONITOR_FULL_REPORT_PERIOD, + (unsigned)CONTROL_PLANE_TASK_MONITOR_STACK_WARN_BYTES); TickType_t interval_ticks = pdMS_TO_TICKS(CONFIG_TQ_TASK_MONITOR_INTERVAL_MS); if (interval_ticks == 0) { @@ -1478,8 +1537,12 @@ static void control_plane_task_monitor_task(void *arg) interval_ticks = 1; } + uint32_t report_count = 0U; while (!control_plane_runtime_stop_requested()) { - control_plane_log_task_table(); + bool full_report = + (report_count % CONTROL_PLANE_TASK_MONITOR_FULL_REPORT_PERIOD) == 0U; + control_plane_log_task_table(full_report); + report_count++; vTaskDelay(interval_ticks); } @@ -2549,12 +2612,13 @@ esp_err_t control_plane_start_runtime_workers(void) #if CONFIG_TQ_TASK_MONITOR_ENABLE if (control_plane_get_task_handle(&s_task_monitor_task) == NULL) { - esp_err_t task_err = control_plane_create_task(control_plane_task_monitor_task, - "cp_task_monitor", - CONTROL_PLANE_TASK_MONITOR_TASK_STACK_SIZE, - 3, - CONTROL_PLANE_LOCAL_TASK_CORE, - &s_task_monitor_task); + esp_err_t task_err = control_plane_create_task_psram_first( + control_plane_task_monitor_task, + "cp_task_monitor", + CONTROL_PLANE_TASK_MONITOR_TASK_STACK_SIZE, + 3, + CONTROL_PLANE_LOCAL_TASK_CORE, + &s_task_monitor_task); if (task_err != ESP_OK) { control_plane_stop_runtime_workers(); return task_err; @@ -2703,7 +2767,7 @@ void control_plane_stop_runtime_workers(void) } #if CONFIG_TQ_TASK_MONITOR_ENABLE if (!control_plane_wait_task_exit(&s_task_monitor_task, CONTROL_PLANE_TASK_STOP_WAIT_MS)) { - control_plane_force_delete_task(&s_task_monitor_task, "cp_task_monitor"); + control_plane_force_delete_task_with_caps(&s_task_monitor_task, "cp_task_monitor"); } #endif #if CONFIG_FORTUNE_ENABLE diff --git a/components/control_plane/src/runtime/control_plane_system_events.c b/components/control_plane/src/runtime/control_plane_system_events.c index 3989583..05daa10 100644 --- a/components/control_plane/src/runtime/control_plane_system_events.c +++ b/components/control_plane/src/runtime/control_plane_system_events.c @@ -27,7 +27,7 @@ #endif #ifndef CONFIG_TQ_SYSTEM_EVENT_TASK_STACK -#define CONFIG_TQ_SYSTEM_EVENT_TASK_STACK 4096 +#define CONFIG_TQ_SYSTEM_EVENT_TASK_STACK 6144 #endif #if !defined(CONFIG_TQ_PTT_MODE_HOLD_TO_TALK) && !defined(CONFIG_TQ_PTT_MODE_CLICK_TO_TALK) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 5728860..27dde33 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -211,15 +211,18 @@ menu "Example Configuration" bool "Enable periodic FreeRTOS task monitor log" default y help - Periodically print a compact FreeRTOS task table to the log. + Run a low-impact task monitor with a PSRAM-preferred worker + stack and PSRAM-only snapshots. Periodic summaries report the + lowest stack headroom; a full task table is emitted less often. config TQ_TASK_MONITOR_INTERVAL_MS int "Task monitor log interval (ms)" - default 10000 + default 30000 range 1000 600000 depends on TQ_TASK_MONITOR_ENABLE help - Interval for periodic task table logging. + Interval for task summaries. The complete table is emitted on + the first sample and every five samples after that. config TQ_TASK_MONITOR_MAX_TASKS int "Task monitor max task entries" @@ -317,7 +320,7 @@ menu "Example Configuration" config TQ_SYSTEM_EVENT_TASK_STACK int "System event task stack size" - default 4096 + default 6144 range 2048 8192 depends on TQ_SYSTEM_EVENT_ENABLE help @@ -680,6 +683,14 @@ menu "Example Configuration" Disable when the connected display hardware does not match this firmware's LCD driver. + config TQ_LCD_RENDER_TASK_STACK_BYTES + int "LCD render task stack (bytes)" + default 10240 + range 8192 16384 + depends on TQ_SCREEN_ENABLE + help + Stack size in bytes for the control-plane LCD render worker. + config TQ_SCREEN_COLOR_ORDER_BGR bool "Use BGR color order" default n @@ -1154,6 +1165,14 @@ menu "Example Configuration" help Master switch for multimodal WebSocket interaction features. + config TQ_MULTIMODAL_WATCHDOG_TASK_STACK_BYTES + int "Multimodal watchdog task stack (bytes)" + default 6144 + range 4096 12288 + depends on ENABLE_MULTIMODAL_INTERACTION + help + Stack size in bytes for the multimodal session watchdog task. + config MULTIMODAL_USE_STATIC_CREDENTIALS bool "Use static WebSocket credentials (skip token request)" default n @@ -1230,6 +1249,14 @@ menu "Example Configuration" device identity provisioning, public-key retrieval, and on-device challenge signing. + config TQ_FACTORY_CLI_TASK_STACK_BYTES + int "Factory CLI task stack (bytes)" + default 10240 + range 8192 16384 + depends on TQ_FACTORY_CLI_ENABLE + help + Stack size in bytes for the serial factory provisioning worker. + config AUTH_REGISTER_BASE_URL string "Auth V2 registration base URL" depends on AUTH_V2_ENABLE diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 9946604..06b622f 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -37,7 +37,8 @@ CONFIG_TQ_BOOT_SOUND_TIMEOUT_MS=3000 CONFIG_TQ_BOOT_SOUND_FILE="boot.opus" CONFIG_TQ_NETWORK_TASK_CORE=0 CONFIG_TQ_LOCAL_TASK_CORE=1 -CONFIG_TQ_TASK_MONITOR_INTERVAL_MS=10000 +CONFIG_TQ_LCD_RENDER_TASK_STACK_BYTES=10240 +CONFIG_TQ_TASK_MONITOR_INTERVAL_MS=30000 CONFIG_TQ_TASK_MONITOR_MAX_TASKS=64 CONFIG_TQ_MEMORY_MONITOR_ENABLE=y CONFIG_TQ_MEMORY_MONITOR_SAMPLE_INTERVAL_MS=1000 @@ -49,7 +50,7 @@ CONFIG_TQ_MULTIMODAL_DIAGNOSTICS_ENABLE=y CONFIG_TQ_NETWORK_AUTO_REASSOCIATION_ENABLE=y CONFIG_TQ_SYSTEM_EVENT_ENABLE=y CONFIG_TQ_SYSTEM_EVENT_QUEUE_LEN=32 -CONFIG_TQ_SYSTEM_EVENT_TASK_STACK=4096 +CONFIG_TQ_SYSTEM_EVENT_TASK_STACK=6144 CONFIG_TQ_LIGHT_STANDBY_ENABLE=y CONFIG_TQ_LIGHT_STANDBY_IDLE_TIMEOUT_MS=300000 CONFIG_TQ_LIGHT_STANDBY_DIM_BACKLIGHT=y @@ -190,10 +191,12 @@ CONFIG_FORTUNE_USER_CONFIG_HTTP_PORT=80 CONFIG_FORTUNE_USER_CONFIG_MDNS_HOSTNAME="tq-cat" # CONFIG_FORTUNE_USE_DEVICE_JWT is not set CONFIG_ENABLE_MULTIMODAL_INTERACTION=y +CONFIG_TQ_MULTIMODAL_WATCHDOG_TASK_STACK_BYTES=6144 # CONFIG_MULTIMODAL_USE_STATIC_CREDENTIALS is not set # CONFIG_MULTIMODAL_AUTH_BYPASS_TOKEN_SERVICE is not set CONFIG_AUTH_V2_ENABLE=y CONFIG_TQ_FACTORY_CLI_ENABLE=y +CONFIG_TQ_FACTORY_CLI_TASK_STACK_BYTES=10240 CONFIG_MULTIMODAL_UPSTREAM_MODE="push2talk" CONFIG_MULTIMODAL_PTT_BUTTON_GPIO=13 CONFIG_MULTIMODAL_PTT_BUTTON_ACTIVE_LEVEL=0