Add memory diagnostics and optimize PSRAM usage

This commit is contained in:
2026-08-25 11:08:02 +02:00
parent f6a275c543
commit d779fb046e
7 changed files with 106 additions and 14 deletions
+31 -3
View File
@@ -2,6 +2,7 @@
#include <string.h>
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
@@ -16,6 +17,9 @@
#define SESSION_BROKER_SLOT_BITS 3U
#define SESSION_BROKER_SLOT_MASK ((1U << SESSION_BROKER_SLOT_BITS) - 1U)
#define SESSION_BROKER_MAX_GENERATION (UINT32_MAX >> SESSION_BROKER_SLOT_BITS)
#define SESSION_BROKER_OUTPUT_STORAGE_SIZE (SESSION_BROKER_OUTPUT_SIZE + 1U)
#define SESSION_BROKER_EVENT_STORAGE_SIZE \
(SESSION_BROKER_EVENT_QUEUE_LENGTH * sizeof(session_broker_event_t))
_Static_assert(
SESSION_BROKER_MAX_CLIENTS == (1U << SESSION_BROKER_SLOT_BITS),
@@ -24,6 +28,10 @@ _Static_assert(
typedef struct {
StreamBufferHandle_t output;
QueueHandle_t events;
StaticStreamBuffer_t output_control;
StaticQueue_t events_control;
uint8_t *output_storage;
uint8_t *event_storage;
session_broker_client_id_t id;
uint32_t generation;
session_broker_client_type_t type;
@@ -183,6 +191,10 @@ static void cleanup_allocations(void)
vStreamBufferDelete(s_slots[i].output);
s_slots[i].output = NULL;
}
heap_caps_free(s_slots[i].event_storage);
s_slots[i].event_storage = NULL;
heap_caps_free(s_slots[i].output_storage);
s_slots[i].output_storage = NULL;
}
if (s_mutex != NULL) {
vSemaphoreDelete(s_mutex);
@@ -209,9 +221,25 @@ esp_err_t session_broker_init(void)
}
for (size_t i = 0; i < SESSION_BROKER_MAX_CLIENTS; ++i) {
s_slots[i].output = xStreamBufferCreate(SESSION_BROKER_OUTPUT_SIZE, 1U);
s_slots[i].events = xQueueCreate(SESSION_BROKER_EVENT_QUEUE_LENGTH,
sizeof(session_broker_event_t));
s_slots[i].output_storage = heap_caps_calloc_prefer(
1U, SESSION_BROKER_OUTPUT_STORAGE_SIZE, 2,
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT,
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
s_slots[i].event_storage = heap_caps_calloc_prefer(
1U, SESSION_BROKER_EVENT_STORAGE_SIZE, 2,
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT,
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (s_slots[i].output_storage != NULL) {
s_slots[i].output = xStreamBufferCreateStatic(
SESSION_BROKER_OUTPUT_STORAGE_SIZE, 1U,
s_slots[i].output_storage, &s_slots[i].output_control);
}
if (s_slots[i].event_storage != NULL) {
s_slots[i].events = xQueueCreateStatic(
SESSION_BROKER_EVENT_QUEUE_LENGTH,
sizeof(session_broker_event_t),
s_slots[i].event_storage, &s_slots[i].events_control);
}
if (s_slots[i].output == NULL || s_slots[i].events == NULL) {
cleanup_allocations();
return ESP_ERR_NO_MEM;
+4
View File
@@ -94,6 +94,10 @@ static int show_status(bool sessions_only)
esp_err_to_name(username_error));
}
printf("Admission: shell/PTY only; exec, subsystem, forwarding, SCP, and SFTP disabled\n");
printf("Owner task: core=%" PRId32 " stack=%" PRIu32
" minimum-free=%" PRIu32 " bytes\n",
snapshot.task_core_id, snapshot.task_stack_size,
snapshot.task_stack_free_minimum);
}
return print_sessions(&snapshot);
}
+11 -3
View File
@@ -28,6 +28,7 @@
#define SSH_TRANSPORT_TASK_STACK_SIZE 20480U
#define SSH_TRANSPORT_TASK_PRIORITY 5U
#define SSH_TRANSPORT_TASK_CORE 1
#define SSH_TRANSPORT_LOOP_DELAY_MS 10U
#define SSH_TRANSPORT_COMMAND_TIMEOUT_MS 10000U
#define SSH_TRANSPORT_RECONCILE_INTERVAL_US 250000LL
@@ -984,9 +985,9 @@ esp_err_t ssh_transport_init(void)
s_session_snapshots[index].socket_fd = -1;
s_session_snapshots[index].state = SSH_TRANSPORT_SESSION_FREE;
}
BaseType_t created = xTaskCreate(transport_task, "ssh_transport",
SSH_TRANSPORT_TASK_STACK_SIZE, NULL,
SSH_TRANSPORT_TASK_PRIORITY, &s_task);
BaseType_t created = xTaskCreatePinnedToCore(
transport_task, "ssh_transport", SSH_TRANSPORT_TASK_STACK_SIZE, NULL,
SSH_TRANSPORT_TASK_PRIORITY, &s_task, SSH_TRANSPORT_TASK_CORE);
if (created != pdPASS) {
s_task = NULL;
vSemaphoreDelete(command_mutex);
@@ -1127,12 +1128,15 @@ esp_err_t ssh_transport_get_snapshot(ssh_transport_snapshot_t *snapshot)
taskEXIT_CRITICAL(&s_lock);
return ESP_ERR_INVALID_STATE;
}
TaskHandle_t task = s_task;
memset(snapshot, 0, sizeof(*snapshot));
snapshot->initialized = s_initialized;
snapshot->running = s_running;
snapshot->transitioning = s_transitioning;
snapshot->port = SSH_TRANSPORT_PORT;
snapshot->last_error = s_last_error;
snapshot->task_core_id = SSH_TRANSPORT_TASK_CORE;
snapshot->task_stack_size = SSH_TRANSPORT_TASK_STACK_SIZE;
snapshot->counters = s_counters;
for (size_t index = 0U; index < SSH_TRANSPORT_MAX_SESSIONS; ++index) {
snapshot->sessions[index] = s_session_snapshots[index];
@@ -1141,6 +1145,10 @@ esp_err_t ssh_transport_get_snapshot(ssh_transport_snapshot_t *snapshot)
}
}
taskEXIT_CRITICAL(&s_lock);
if (task != NULL) {
snapshot->task_stack_free_minimum =
(uint32_t)uxTaskGetStackHighWaterMark(task);
}
return ESP_OK;
}
+3
View File
@@ -75,6 +75,9 @@ typedef struct {
uint16_t port;
esp_err_t last_error;
uint32_t active_sessions;
int32_t task_core_id;
uint32_t task_stack_size;
uint32_t task_stack_free_minimum;
ssh_transport_session_snapshot_t sessions[SSH_TRANSPORT_MAX_SESSIONS];
ssh_transport_counters_t counters;
} ssh_transport_snapshot_t;
+43 -2
View File
@@ -3,13 +3,42 @@
#include "system_console.h"
#include <stdint.h>
#include <stdio.h>
#include "esp_console.h"
#include "esp_heap_caps.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static void print_heap_region(const char *name, uint32_t capabilities)
{
printf("%s: free=%u minimum-free=%u largest-block=%u bytes\n",
name,
(unsigned int)heap_caps_get_free_size(capabilities),
(unsigned int)heap_caps_get_minimum_free_size(capabilities),
(unsigned int)heap_caps_get_largest_free_block(capabilities));
}
static int command_memory(int argc, char **argv)
{
(void)argv;
if (argc != 1) {
printf("Usage: memory\n");
return 1;
}
print_heap_region("Internal 8-bit heap",
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
print_heap_region("Internal DMA heap",
MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
print_heap_region("External PSRAM",
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
printf("Minimum-free is a conservative sum of each matching heap region's lifetime minimum.\n");
return 0;
}
static int command_reboot(int argc, char **argv)
{
(void)argv;
@@ -28,12 +57,24 @@ static int command_reboot(int argc, char **argv)
esp_err_t system_console_register_commands(void)
{
const esp_console_cmd_t command = {
const esp_console_cmd_t reboot_command = {
.command = "reboot",
.help = "Restart the ESP32; unsaved RAM-only configuration is lost",
.hint = NULL,
.func = &command_reboot,
.argtable = NULL,
};
return esp_console_cmd_register(&command);
esp_err_t error = esp_console_cmd_register(&reboot_command);
if (error != ESP_OK) {
return error;
}
const esp_console_cmd_t memory_command = {
.command = "memory",
.help = "Show internal and PSRAM heap availability/low-water marks",
.hint = NULL,
.func = &command_memory,
.argtable = NULL,
};
return esp_console_cmd_register(&memory_command);
}