mirror of
https://github.com/esphome/esphome.git
synced 2026-02-20 00:15:36 -07:00
tweak
This commit is contained in:
@@ -100,6 +100,7 @@ CONF_INITIAL_LEVEL = "initial_level"
|
||||
CONF_LOGGER_ID = "logger_id"
|
||||
CONF_RUNTIME_TAG_LEVELS = "runtime_tag_levels"
|
||||
CONF_TASK_LOG_BUFFER_SIZE = "task_log_buffer_size"
|
||||
CONF_TASK_LOG_BUFFER_SLOTS = "task_log_buffer_slots"
|
||||
|
||||
UART_SELECTION_ESP32 = {
|
||||
VARIANT_ESP32: [UART0, UART1, UART2],
|
||||
@@ -227,12 +228,25 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.SplitDefault(
|
||||
CONF_TASK_LOG_BUFFER_SIZE,
|
||||
esp32=768, # Default: 768 bytes (~5-6 messages with 70-byte text plus thread names)
|
||||
host=64, # Default: 64 slots (host uses slot count, not byte size)
|
||||
): cv.All(
|
||||
cv.only_on([PLATFORM_ESP32, PLATFORM_HOST]),
|
||||
cv.only_on_esp32,
|
||||
cv.validate_bytes,
|
||||
cv.Any(
|
||||
cv.int_(0), # Disabled
|
||||
cv.int_range(min=4, max=32768),
|
||||
cv.int_range(
|
||||
min=640, # Min: ~4-5 messages with 70-byte text plus thread names
|
||||
max=32768, # Max: Depends on message sizes, typically ~300 messages with default size
|
||||
),
|
||||
),
|
||||
),
|
||||
cv.SplitDefault(
|
||||
CONF_TASK_LOG_BUFFER_SLOTS,
|
||||
host=64, # Default: 64 message slots for host platform
|
||||
): cv.All(
|
||||
cv.only_on(PLATFORM_HOST),
|
||||
cv.Any(
|
||||
cv.int_(0), # Disabled
|
||||
cv.int_range(min=4, max=256), # 4-256 message slots
|
||||
),
|
||||
),
|
||||
cv.SplitDefault(
|
||||
@@ -302,12 +316,18 @@ async def to_code(config):
|
||||
baud_rate,
|
||||
config[CONF_TX_BUFFER_SIZE],
|
||||
)
|
||||
if CORE.is_esp32 or CORE.is_host:
|
||||
if CORE.is_esp32:
|
||||
cg.add(log.create_pthread_key())
|
||||
task_log_buffer_size = config.get(CONF_TASK_LOG_BUFFER_SIZE, 0)
|
||||
if task_log_buffer_size > 0:
|
||||
cg.add_define("USE_ESPHOME_TASK_LOG_BUFFER")
|
||||
cg.add(log.init_log_buffer(task_log_buffer_size))
|
||||
elif CORE.is_host:
|
||||
cg.add(log.create_pthread_key())
|
||||
task_log_buffer_slots = config.get(CONF_TASK_LOG_BUFFER_SLOTS, 0)
|
||||
if task_log_buffer_slots > 0:
|
||||
cg.add_define("USE_ESPHOME_TASK_LOG_BUFFER")
|
||||
cg.add(log.init_log_buffer(task_log_buffer_slots))
|
||||
|
||||
cg.add(log.set_log_level(initial_level))
|
||||
if CONF_HARDWARE_UART in config:
|
||||
|
||||
@@ -292,7 +292,7 @@ void Logger::dump_config() {
|
||||
#endif
|
||||
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
|
||||
if (this->log_buffer_) {
|
||||
ESP_LOGCONFIG(TAG, " Task Log Buffer Size: %u", this->log_buffer_->size());
|
||||
ESP_LOGCONFIG(TAG, " Task Log Buffer Size: %u", static_cast<unsigned int>(this->log_buffer_->size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
157
esphome/components/logger/task_log_buffer_host.cpp
Normal file
157
esphome/components/logger/task_log_buffer_host.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
#ifdef USE_HOST
|
||||
|
||||
#include "task_log_buffer_host.h"
|
||||
|
||||
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
|
||||
namespace esphome::logger {
|
||||
|
||||
TaskLogBufferHost::TaskLogBufferHost(size_t slot_count) : slot_count_(slot_count) {
|
||||
// Allocate message slots
|
||||
this->slots_ = std::make_unique<LogMessage[]>(slot_count);
|
||||
}
|
||||
|
||||
TaskLogBufferHost::~TaskLogBufferHost() {
|
||||
// unique_ptr handles cleanup automatically
|
||||
}
|
||||
|
||||
int TaskLogBufferHost::acquire_write_slot_() {
|
||||
// Try to reserve a slot using compare-and-swap
|
||||
size_t current_reserve = this->reserve_index_.load(std::memory_order_relaxed);
|
||||
|
||||
while (true) {
|
||||
// Calculate next index (with wrap-around)
|
||||
size_t next_reserve = (current_reserve + 1) % this->slot_count_;
|
||||
|
||||
// Check if buffer would be full
|
||||
// Buffer is full when next write position equals read position
|
||||
size_t current_read = this->read_index_.load(std::memory_order_acquire);
|
||||
if (next_reserve == current_read) {
|
||||
return -1; // Buffer full
|
||||
}
|
||||
|
||||
// Try to claim this slot
|
||||
if (this->reserve_index_.compare_exchange_weak(current_reserve, next_reserve, std::memory_order_acq_rel,
|
||||
std::memory_order_relaxed)) {
|
||||
return static_cast<int>(current_reserve);
|
||||
}
|
||||
// If CAS failed, current_reserve was updated, retry with new value
|
||||
}
|
||||
}
|
||||
|
||||
void TaskLogBufferHost::commit_write_slot_(int slot_index) {
|
||||
// Mark the slot as ready for reading
|
||||
this->slots_[slot_index].ready.store(true, std::memory_order_release);
|
||||
|
||||
// Try to advance the write_index if we're the next expected commit
|
||||
// This ensures messages are read in order
|
||||
size_t expected = slot_index;
|
||||
size_t next = (slot_index + 1) % this->slot_count_;
|
||||
|
||||
// We only advance write_index if this slot is the next one expected
|
||||
// This handles out-of-order commits correctly
|
||||
while (true) {
|
||||
if (!this->write_index_.compare_exchange_weak(expected, next, std::memory_order_release,
|
||||
std::memory_order_relaxed)) {
|
||||
// Someone else advanced it or we're not next in line, that's fine
|
||||
break;
|
||||
}
|
||||
|
||||
// Successfully advanced, check if next slot is also ready
|
||||
expected = next;
|
||||
next = (next + 1) % this->slot_count_;
|
||||
if (!this->slots_[expected].ready.load(std::memory_order_acquire)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskLogBufferHost::send_message_thread_safe(uint8_t level, const char *tag, uint16_t line, const char *format,
|
||||
va_list args) {
|
||||
// Acquire a slot
|
||||
int slot_index = this->acquire_write_slot_();
|
||||
if (slot_index < 0) {
|
||||
return false; // Buffer full
|
||||
}
|
||||
|
||||
LogMessage &msg = this->slots_[slot_index];
|
||||
|
||||
// Fill in the message header
|
||||
msg.level = level;
|
||||
msg.tag = tag;
|
||||
msg.line = line;
|
||||
|
||||
// Get thread name using pthread
|
||||
char thread_name_buf[LogMessage::MAX_THREAD_NAME_SIZE];
|
||||
// pthread_getname_np works the same on Linux and macOS
|
||||
if (pthread_getname_np(pthread_self(), thread_name_buf, sizeof(thread_name_buf)) == 0) {
|
||||
strncpy(msg.thread_name, thread_name_buf, sizeof(msg.thread_name) - 1);
|
||||
msg.thread_name[sizeof(msg.thread_name) - 1] = '\0';
|
||||
} else {
|
||||
msg.thread_name[0] = '\0';
|
||||
}
|
||||
|
||||
// Format the message text
|
||||
int ret = vsnprintf(msg.text, sizeof(msg.text), format, args);
|
||||
if (ret < 0) {
|
||||
// Formatting error - still commit the slot but with empty text
|
||||
msg.text[0] = '\0';
|
||||
msg.text_length = 0;
|
||||
} else {
|
||||
msg.text_length = static_cast<uint16_t>(std::min(static_cast<size_t>(ret), sizeof(msg.text) - 1));
|
||||
}
|
||||
|
||||
// Remove trailing newlines
|
||||
while (msg.text_length > 0 && msg.text[msg.text_length - 1] == '\n') {
|
||||
msg.text_length--;
|
||||
}
|
||||
msg.text[msg.text_length] = '\0';
|
||||
|
||||
// Commit the slot
|
||||
this->commit_write_slot_(slot_index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TaskLogBufferHost::get_message_main_loop(LogMessage **message) {
|
||||
if (message == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t current_read = this->read_index_.load(std::memory_order_relaxed);
|
||||
size_t current_write = this->write_index_.load(std::memory_order_acquire);
|
||||
|
||||
// Check if buffer is empty
|
||||
if (current_read == current_write) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the slot is ready (should always be true if write_index advanced)
|
||||
LogMessage &msg = this->slots_[current_read];
|
||||
if (!msg.ready.load(std::memory_order_acquire)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*message = &msg;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TaskLogBufferHost::release_message_main_loop() {
|
||||
size_t current_read = this->read_index_.load(std::memory_order_relaxed);
|
||||
|
||||
// Clear the ready flag
|
||||
this->slots_[current_read].ready.store(false, std::memory_order_release);
|
||||
|
||||
// Advance read index
|
||||
size_t next_read = (current_read + 1) % this->slot_count_;
|
||||
this->read_index_.store(next_read, std::memory_order_release);
|
||||
}
|
||||
|
||||
} // namespace esphome::logger
|
||||
|
||||
#endif // USE_ESPHOME_TASK_LOG_BUFFER
|
||||
#endif // USE_HOST
|
||||
Reference in New Issue
Block a user