Trim task stacks and buffers by measurement: +15 KB with IRC up

Peak stack use was measured through each task's worst case (an
ECDSA-checked install over Wi-Fi and from SD, get/put, a core dump
fetch, an IRC TLS handshake); stacks are now peak plus about 2 KB: loop
8 -> 6 KB, update 8 -> 5, storage 10 -> 6, irc 8 -> 6. The Debug Build's
console ring goes 6 -> 4 KB, serial TX 2 -> 1 KB, the GNSS UART buffer
1 KB -> 512 B.

On the device, with IRC on TLS: 46 KB free (was 31), an 18 KB low (was
9.4). The re-run of every worst case left at least 1.6 KB of stack free
in each task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-04 23:02:35 +02:00
co-authored by Claude Opus 5.5
parent 578a39d3c1
commit db265fb757
9 changed files with 14 additions and 11 deletions
+4 -1
View File
@@ -120,6 +120,9 @@ static StatusInfo currentStatus() {
// (UpdateService::tick) decides instead, and an unconfirmed image stays PENDING_VERIFY.
extern "C" bool verifyRollbackLater() { return true; } // C linkage, or the weak default wins
// The main loop's stack: Arduino's default is 8 KB; the measured peak is 3 KB (M2).
size_t getArduinoLoopTaskStackSize() { return 6144; }
static void setupSafeMode(int crashes);
void setup() {
@@ -128,7 +131,7 @@ void setup() {
int crashes = crash_report::noteBoot(nvs);
safeMode = SafeMode::active(crashes);
Serial.setRxBufferSize(2 * FileReceiver::kChunk); // before the port opens; sd put sends 1 chunk at a time
Serial.setTxBufferSize(2048); // the console skips Serial when it's full: room for a burst like `tasks`
Serial.setTxBufferSize(1024); // the console skips Serial when it's full: room for a burst like `tasks`
auto cfg = M5.config();
M5Cardputer.begin(cfg, true);
+1 -1
View File
@@ -17,7 +17,7 @@ class Console : public Print {
using Print::write;
#ifdef RORO_DEBUG
static constexpr size_t kRingBytes = 6144;
static constexpr size_t kRingBytes = 4096;
// Also copies ESP-IDF's own log lines into the ring (they still reach the serial port).
void captureEspLogs();
+1 -1
View File
@@ -32,7 +32,7 @@ void GnssService::start() {
void GnssService::stop() { close(); }
void GnssService::open(uint32_t nowMs) {
Serial1.setRxBufferSize(1024); // before begin(): over 2 s of NMEA
Serial1.setRxBufferSize(512); // before begin(): over a second of NMEA, read every 50 ms
Serial1.begin(kBaud, SERIAL_8N1, kRxPin, kTxPin);
open_ = true;
active_ = false; // tick() wakes it or puts it to sleep, per the setting
+1 -1
View File
@@ -15,7 +15,7 @@
namespace roro {
// The GNSS receiver on the Cap LoRa-1262 (see CONTEXT.md and docs/milestones/M2.md): reads its
// NMEA from the main loop's tick (about 450 bytes/s, so a 1 KB UART buffer covers any stall),
// NMEA from the main loop's tick (about 450 bytes/s, so a 512-byte UART buffer covers a second),
// holds the current Fix, and sets the clock from it. Settings → GNSS switches it on and off.
class GnssService : public Service {
public:
+1 -1
View File
@@ -33,7 +33,7 @@ IrcService::IrcService(KeyValueStore& store, const std::string& defaultNick, Wif
void IrcService::start() {
if (task_) return;
lock_ = xSemaphoreCreateMutex();
xTaskCreate(taskEntry, "irc", 8192, this, 1, &task_);
xTaskCreate(taskEntry, "irc", 6144, this, 1, &task_); // peak 4.0 KB (TLS handshake, M2)
}
void IrcService::connect() {
+1 -1
View File
@@ -14,7 +14,7 @@ namespace roro {
void StorageService::start() {
if (task_) return;
xTaskCreate(taskEntry, "storage", 10240, this, 1, &task_); // room for a signature check
xTaskCreate(taskEntry, "storage", 6144, this, 1, &task_); // peak 3.9 KB (SD install with its signature check, M2)
}
void StorageService::stop() {
+1 -1
View File
@@ -90,7 +90,7 @@ void UpdateService::start() {
store_.putString("ota_pending", "");
}
if (!task_) xTaskCreate(taskEntry, "update", 8192, this, 1, &task_);
if (!task_) xTaskCreate(taskEntry, "update", 5120, this, 1, &task_); // peak 3.4 KB (ECDSA check, M2)
}
void UpdateService::bootGuard(KeyValueStore& store) {