This commit is contained in:
Tomasz Duda
2026-02-11 10:10:47 +01:00
parent b79780f885
commit 9f46bed686
8 changed files with 33 additions and 58 deletions
+1 -18
View File
@@ -173,20 +173,9 @@ Logger::Logger(uint32_t baud_rate, size_t tx_buffer_size) : baud_rate_(baud_rate
}
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
void Logger::init_log_buffer(size_t total_buffer_size) {
#ifdef USE_HOST
// Host uses slot count instead of byte size
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - allocated once, never freed
this->log_buffer_ = new logger::TaskLogBufferHost(total_buffer_size);
#elif defined(USE_ESP32)
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - allocated once, never freed
this->log_buffer_ = new logger::TaskLogBuffer(total_buffer_size);
#elif defined(USE_LIBRETINY)
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - allocated once, never freed
this->log_buffer_ = new logger::TaskLogBufferLibreTiny(total_buffer_size);
#elif defined(USE_ZEPHYR)
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory) - allocated once, never freed
this->log_buffer_ = new logger::TaskLogBufferZephyr(total_buffer_size);
#endif
#if defined(USE_ESP32) || defined(USE_LIBRETINY) || (defined(USE_ZEPHYR) && !defined(USE_LOGGER_USB_CDC))
// Start with loop disabled when using task buffer (unless using USB CDC on ESP32)
@@ -210,7 +199,7 @@ void Logger::process_messages_() {
// Process any buffered messages when available
if (this->log_buffer_->has_messages()) {
#ifdef USE_HOST
logger::TaskLogBufferHost::LogMessage *message;
logger::TaskLogBuffer::LogMessage *message;
while (this->log_buffer_->get_message_main_loop(&message)) {
const char *thread_name = message->thread_name[0] != '\0' ? message->thread_name : nullptr;
LogBuffer buf{this->tx_buffer_, this->tx_buffer_size_};
@@ -220,13 +209,7 @@ void Logger::process_messages_() {
this->write_log_buffer_to_console_(buf);
}
#elif defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
#ifdef USE_ESP32
logger::TaskLogBuffer::LogMessage *message;
#elif defined(USE_LIBRETINY)
logger::TaskLogBufferLibreTiny::LogMessage *message;
#else
logger::TaskLogBufferZephyr::LogMessage *message;
#endif
const char *text;
while (this->log_buffer_->borrow_message_main_loop(&message, &text)) {
const char *thread_name = message->thread_name[0] != '\0' ? message->thread_name : nullptr;
-8
View File
@@ -346,15 +346,7 @@ class Logger : public Component {
std::vector<LoggerLevelListener *> level_listeners_; // Log level change listeners
#endif
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
#ifdef USE_HOST
logger::TaskLogBufferHost *log_buffer_{nullptr}; // Allocated once, never freed
#elif defined(USE_ESP32)
logger::TaskLogBuffer *log_buffer_{nullptr}; // Allocated once, never freed
#elif defined(USE_LIBRETINY)
logger::TaskLogBufferLibreTiny *log_buffer_{nullptr}; // Allocated once, never freed
#elif defined(USE_ZEPHYR)
logger::TaskLogBufferZephyr *log_buffer_{nullptr}; // Allocated once, never freed
#endif
#endif
// Group smaller types together at the end
@@ -10,16 +10,16 @@
namespace esphome::logger {
TaskLogBufferHost::TaskLogBufferHost(size_t slot_count) : slot_count_(slot_count) {
TaskLogBuffer::TaskLogBuffer(size_t slot_count) : slot_count_(slot_count) {
// Allocate message slots
this->slots_ = std::make_unique<LogMessage[]>(slot_count);
}
TaskLogBufferHost::~TaskLogBufferHost() {
TaskLogBuffer::~TaskLogBuffer() {
// unique_ptr handles cleanup automatically
}
int TaskLogBufferHost::acquire_write_slot_() {
int TaskLogBuffer::acquire_write_slot_() {
// Try to reserve a slot using compare-and-swap
size_t current_reserve = this->reserve_index_.load(std::memory_order_relaxed);
@@ -43,7 +43,7 @@ int TaskLogBufferHost::acquire_write_slot_() {
}
}
void TaskLogBufferHost::commit_write_slot_(int slot_index) {
void TaskLogBuffer::commit_write_slot_(int slot_index) {
// Mark the slot as ready for reading
this->slots_[slot_index].ready.store(true, std::memory_order_release);
@@ -70,8 +70,8 @@ void TaskLogBufferHost::commit_write_slot_(int slot_index) {
}
}
bool TaskLogBufferHost::send_message_thread_safe(uint8_t level, const char *tag, uint16_t line, const char *thread_name,
const char *format, va_list args) {
bool TaskLogBuffer::send_message_thread_safe(uint8_t level, const char *tag, uint16_t line, const char *thread_name,
const char *format, va_list args) {
// Acquire a slot
int slot_index = this->acquire_write_slot_();
if (slot_index < 0) {
@@ -115,7 +115,7 @@ bool TaskLogBufferHost::send_message_thread_safe(uint8_t level, const char *tag,
return true;
}
bool TaskLogBufferHost::get_message_main_loop(LogMessage **message) {
bool TaskLogBuffer::get_message_main_loop(LogMessage **message) {
if (message == nullptr) {
return false;
}
@@ -138,7 +138,7 @@ bool TaskLogBufferHost::get_message_main_loop(LogMessage **message) {
return true;
}
void TaskLogBufferHost::release_message_main_loop() {
void TaskLogBuffer::release_message_main_loop() {
size_t current_read = this->read_index_.load(std::memory_order_relaxed);
// Clear the ready flag
@@ -48,7 +48,7 @@ namespace esphome::logger {
* - Atomic CAS for slot reservation allows multiple producers without locks
* - Single consumer (main loop) processes messages in order
*/
class TaskLogBufferHost {
class TaskLogBuffer {
public:
// Default number of message slots - host has plenty of memory
static constexpr size_t DEFAULT_SLOT_COUNT = 64;
@@ -74,8 +74,8 @@ class TaskLogBufferHost {
};
/// Constructor that takes the number of message slots
explicit TaskLogBufferHost(size_t slot_count);
~TaskLogBufferHost();
explicit TaskLogBuffer(size_t slot_count);
~TaskLogBuffer();
// NOT thread-safe - get next message from buffer, only call from main loop
// Returns true if a message was retrieved, false if buffer is empty
@@ -8,7 +8,7 @@
namespace esphome::logger {
TaskLogBufferLibreTiny::TaskLogBufferLibreTiny(size_t total_buffer_size) {
TaskLogBuffer::TaskLogBuffer(size_t total_buffer_size) {
this->size_ = total_buffer_size;
// Allocate memory for the circular buffer using ESPHome's RAM allocator
RAMAllocator<uint8_t> allocator;
@@ -17,7 +17,7 @@ TaskLogBufferLibreTiny::TaskLogBufferLibreTiny(size_t total_buffer_size) {
this->mutex_ = xSemaphoreCreateMutex();
}
TaskLogBufferLibreTiny::~TaskLogBufferLibreTiny() {
TaskLogBuffer::~TaskLogBuffer() {
if (this->mutex_ != nullptr) {
vSemaphoreDelete(this->mutex_);
this->mutex_ = nullptr;
@@ -29,7 +29,7 @@ TaskLogBufferLibreTiny::~TaskLogBufferLibreTiny() {
}
}
size_t TaskLogBufferLibreTiny::available_contiguous_space() const {
size_t TaskLogBuffer::available_contiguous_space() const {
if (this->head_ >= this->tail_) {
// head is ahead of or equal to tail
// Available space is from head to end, plus from start to tail
@@ -47,7 +47,7 @@ size_t TaskLogBufferLibreTiny::available_contiguous_space() const {
}
}
bool TaskLogBufferLibreTiny::borrow_message_main_loop(LogMessage **message, const char **text) {
bool TaskLogBuffer::borrow_message_main_loop(LogMessage **message, const char **text) {
if (message == nullptr || text == nullptr) {
return false;
}
@@ -85,7 +85,7 @@ bool TaskLogBufferLibreTiny::borrow_message_main_loop(LogMessage **message, cons
return true;
}
void TaskLogBufferLibreTiny::release_message_main_loop() {
void TaskLogBuffer::release_message_main_loop() {
// Advance tail past the current message
this->tail_ += this->current_message_size_;
@@ -100,8 +100,8 @@ void TaskLogBufferLibreTiny::release_message_main_loop() {
xSemaphoreGive(this->mutex_);
}
bool TaskLogBufferLibreTiny::send_message_thread_safe(uint8_t level, const char *tag, uint16_t line,
const char *thread_name, const char *format, va_list args) {
bool TaskLogBuffer::send_message_thread_safe(uint8_t level, const char *tag, uint16_t line, const char *thread_name,
const char *format, va_list args) {
// First, calculate the exact length needed using a null buffer (no actual writing)
va_list args_copy;
va_copy(args_copy, args);
@@ -40,7 +40,7 @@ namespace esphome::logger {
* - Volatile counter enables fast has_messages() without lock overhead
* - If message doesn't fit at end, padding is added and message wraps to start
*/
class TaskLogBufferLibreTiny {
class TaskLogBuffer {
public:
// Structure for a log message header (text data follows immediately after)
struct LogMessage {
@@ -60,8 +60,8 @@ class TaskLogBufferLibreTiny {
static constexpr uint8_t PADDING_MARKER_LEVEL = 0xFF;
// Constructor that takes a total buffer size
explicit TaskLogBufferLibreTiny(size_t total_buffer_size);
~TaskLogBufferLibreTiny();
explicit TaskLogBuffer(size_t total_buffer_size);
~TaskLogBuffer();
// NOT thread-safe - borrow a message from the buffer, only call from main loop
bool borrow_message_main_loop(LogMessage **message, const char **text);
@@ -9,12 +9,12 @@ namespace esphome::logger {
__thread bool non_main_task_recursion_guard_; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static inline uint32_t get_wlen(const mpsc_pbuf_generic *item) {
auto *msg = reinterpret_cast<const TaskLogBufferZephyr::LogMessage *>(item);
auto *msg = reinterpret_cast<const TaskLogBuffer::LogMessage *>(item);
// Calculate total size in 32-bit words needed (header + text length + null terminator + 3(4 bytes alignment)
return (sizeof(TaskLogBufferZephyr::LogMessage) + msg->text_length + 1 + 3) / sizeof(uint32_t);
return (sizeof(TaskLogBuffer::LogMessage) + msg->text_length + 1 + 3) / sizeof(uint32_t);
}
TaskLogBufferZephyr::TaskLogBufferZephyr(size_t total_buffer_size) {
TaskLogBuffer::TaskLogBuffer(size_t total_buffer_size) {
// alignment to 4 bytes
total_buffer_size = (total_buffer_size + 3) / sizeof(uint32_t);
this->mpsc_config_.buf = new uint32_t[total_buffer_size];
@@ -25,10 +25,10 @@ TaskLogBufferZephyr::TaskLogBufferZephyr(size_t total_buffer_size) {
mpsc_pbuf_init(&this->log_buffer_, &this->mpsc_config_);
}
TaskLogBufferZephyr::~TaskLogBufferZephyr() { delete[] this->mpsc_config_.buf; }
TaskLogBuffer::~TaskLogBuffer() { delete[] this->mpsc_config_.buf; }
bool TaskLogBufferZephyr::send_message_thread_safe(uint8_t level, const char *tag, uint16_t line,
const char *thread_name, const char *format, va_list args) {
bool TaskLogBuffer::send_message_thread_safe(uint8_t level, const char *tag, uint16_t line, const char *thread_name,
const char *format, va_list args) {
// First, calculate the exact length needed using a null buffer (no actual writing)
va_list args_copy;
va_copy(args_copy, args);
@@ -76,7 +76,7 @@ bool TaskLogBufferZephyr::send_message_thread_safe(uint8_t level, const char *ta
return true;
}
bool TaskLogBufferZephyr::borrow_message_main_loop(LogMessage **message, const char **text) {
bool TaskLogBuffer::borrow_message_main_loop(LogMessage **message, const char **text) {
if (this->current_token_) {
return false;
}
@@ -100,7 +100,7 @@ bool TaskLogBufferZephyr::borrow_message_main_loop(LogMessage **message, const c
return true;
}
void TaskLogBufferZephyr::release_message_main_loop() {
void TaskLogBuffer::release_message_main_loop() {
if (this->current_token_ == nullptr) {
return;
}
@@ -15,7 +15,7 @@ static constexpr size_t MAX_POINTER_REPRESENTATION = 2 + sizeof(void *) * 2 + 1;
extern __thread bool non_main_task_recursion_guard_; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
class TaskLogBufferZephyr {
class TaskLogBuffer {
public:
// Structure for a log message header (text data follows immediately after)
struct LogMessage {
@@ -36,8 +36,8 @@ class TaskLogBufferZephyr {
inline const char *text_data() const { return reinterpret_cast<const char *>(this) + sizeof(LogMessage); }
};
// Constructor that takes a total buffer size
explicit TaskLogBufferZephyr(size_t total_buffer_size);
~TaskLogBufferZephyr();
explicit TaskLogBuffer(size_t total_buffer_size);
~TaskLogBuffer();
// Check if there are messages ready to be processed using an atomic counter for performance
inline bool HOT has_messages() { return mpsc_pbuf_is_pending(&this->log_buffer_); }