DEV Community

Cover image for Why Core-Aware Logging Matters: The Architecture Behind LHOS_LOGx
Francisco Prado
Francisco Prado

Posted on

Why Core-Aware Logging Matters: The Architecture Behind LHOS_LOGx

In the world of mission-critical embedded systems, especially when developing for the ESP32-S3, debugging is no longer about finding "where" the code failed, but "on which core" and "under what concurrency state."

As we move toward ISO 12207 compliance for lhOS, we have redefined our logging strategy. We didn't just wrap the standard ESP_LOG functions; we evolved them into a diagnostic tool for Symmetric Multiprocessing (SMP).

The Macro Definition

#define LHOS_LOGI(tag, fmt, ...) ESP_LOGI(tag, "(core %d) >>> " fmt, xPortGetCoreID(), ##__VA_ARGS__)
#define LHOS_LOGE(tag, fmt, ...) ESP_LOGE(tag, "(core %d) >>> " fmt, xPortGetCoreID(), ##__VA_ARGS__)
// ... applied to all log levels (W, D, V, F)

Enter fullscreen mode Exit fullscreen mode

The Silent Challenge of Dual-Core Systems

The ESP32-S3 features a dual-core Xtensa LX7 architecture. In a standard FreeRTOS environment, tasks can migrate between Core 0 and Core 1. A race condition might trigger a memory corruption that is only reproducible when a specific interrupt fires on Core 1 while a background task is writing on Core 0.

Standard logs often mask this complexity. By the time you see an error message, you’ve lost the execution context. lhOS solves this by making the CPU ID a first-class citizen in every log entry.

Technical Advantages of the LHOS_LOG System

1. Instant Core Affinity Visualization

By automatically injecting xPortGetCoreID(), the developer gets an immediate visual map of the system's workload distribution.

  • Architecture Validation: If a high-priority task assigned to Core 0 suddenly logs from Core 1, the system has detected a task-pinning failure or a scheduler misconfiguration before it becomes a production crash.

2. Streamlining Automated Log Analysis

The use of the unique delimiter ">>>" is a strategic choice for DevOps and CI/CD.

  • PowerShell Integration: Our Windows-based testing scripts use these tokens to parse serial output, calculate delta-time between cores, and generate performance heatmaps. It separates the "noise" of the underlying IDF from the "signals" of the lhOS kernel.

3. Debugging Race Conditions and Deadlocks

In a multi-core environment, two tasks might attempt to lock the same Mutex simultaneously. With LHOS_LOGx, your console output becomes a chronological timeline of core contention:

  • (core 0) >>> Attempting to take SEM_WIFI
  • (core 1) >>> SEM_WIFI already held by Task_BLE This level of transparency reduces the "Mean Time to Repair" (MTTR) by providing a clear trace of execution overlap.

Performance Considerations (Overhead vs. Value)

A common concern for Senior Engineers is the overhead of calling xPortGetCoreID() inside a log. In the Xtensa LX7, retrieving the Core ID is an extremely cheap operation—it involves reading a specialized processor register.

Compared to the overhead of the UART transmission or the string formatting itself, the cost is negligible. However, the value provided during the FMEA (Failure Mode and Effects Analysis) phase is immeasurable. For production builds, lhOS allows these tags to be stripped via pre-processor flags to reclaim every microsecond of performance.

Conclusion: Observability as a Pillar of Safety

In lhOS, we believe that "if you can't see it, you can't secure it." These macros are more than just text formatting; they are a commitment to observability. By forcing the system to declare its physical execution context, we transform a simple debug port into a powerful window into the silicon's behavior.

Top comments (0)