This commit is contained in:
J. Nick Koston 2025-07-08 09:16:42 -06:00
parent d06bab01ac
commit a3c8f667a7
No known key found for this signature in database
7 changed files with 38 additions and 20 deletions

View File

@ -7,12 +7,10 @@ import esphome.config_validation as cv
DEPENDENCIES = []
CONF_ENABLED = "enabled"
CONF_LOG_INTERVAL = "log_interval"
CONFIG_SCHEMA = cv.Schema(
{
cv.Optional(CONF_ENABLED, default=True): cv.boolean,
cv.Optional(
CONF_LOG_INTERVAL, default=60000
): cv.positive_time_period_milliseconds,
@ -20,7 +18,18 @@ CONFIG_SCHEMA = cv.Schema(
)
def FILTER_SOURCE_FILES() -> list[str]:
"""Filter out runtime_stats.cpp when not enabled."""
# When runtime_stats component is not included in the configuration,
# we don't want to compile runtime_stats.cpp
# This function is called when the component IS included, so we return
# an empty list to include all source files
return []
async def to_code(config):
"""Generate code for the runtime statistics component."""
cg.add(cg.App.set_runtime_stats_enabled(config[CONF_ENABLED]))
# Define USE_RUNTIME_STATS when this component is used
cg.add_define("USE_RUNTIME_STATS")
cg.add(cg.App.set_runtime_stats_log_interval(config[CONF_LOG_INTERVAL]))

View File

@ -1,4 +1,7 @@
#include "esphome/core/runtime_stats.h"
#include "runtime_stats.h"
#ifdef USE_RUNTIME_STATS
#include "esphome/core/component.h"
#include <algorithm>
@ -7,7 +10,7 @@ namespace esphome {
RuntimeStatsCollector runtime_stats;
void RuntimeStatsCollector::record_component_time(Component *component, uint32_t duration_ms, uint32_t current_time) {
if (!this->enabled_ || component == nullptr)
if (component == nullptr)
return;
// Check if we have cached the name for this component
@ -79,7 +82,7 @@ void RuntimeStatsCollector::log_stats_() {
}
void RuntimeStatsCollector::process_pending_stats(uint32_t current_time) {
if (!this->enabled_ || this->next_log_time_ == 0)
if (this->next_log_time_ == 0)
return;
if (current_time >= this->next_log_time_) {
@ -90,3 +93,5 @@ void RuntimeStatsCollector::process_pending_stats(uint32_t current_time) {
}
} // namespace esphome
#endif // USE_RUNTIME_STATS

View File

@ -1,5 +1,7 @@
#pragma once
#ifdef USE_RUNTIME_STATS
#include <map>
#include <string>
#include <vector>
@ -85,14 +87,11 @@ struct ComponentStatPair {
class RuntimeStatsCollector {
public:
RuntimeStatsCollector() : log_interval_(60000), next_log_time_(0), enabled_(true) {}
RuntimeStatsCollector() : log_interval_(60000), next_log_time_(0) {}
void set_log_interval(uint32_t log_interval) { this->log_interval_ = log_interval; }
uint32_t get_log_interval() const { return this->log_interval_; }
void set_enabled(bool enabled) { this->enabled_ = enabled; }
bool is_enabled() const { return this->enabled_; }
void record_component_time(Component *component, uint32_t duration_ms, uint32_t current_time);
// Process any pending stats printing (should be called after component loop)
@ -112,10 +111,11 @@ class RuntimeStatsCollector {
std::map<Component *, std::string> component_names_cache_;
uint32_t log_interval_;
uint32_t next_log_time_;
bool enabled_;
};
// Global instance for runtime stats collection
extern RuntimeStatsCollector runtime_stats;
} // namespace esphome
} // namespace esphome
#endif // USE_RUNTIME_STATS

View File

@ -141,9 +141,11 @@ void Application::loop() {
this->in_loop_ = false;
this->app_state_ = new_app_state;
#ifdef USE_RUNTIME_STATS
// Process any pending runtime stats printing after all components have run
// This ensures stats printing doesn't affect component timing measurements
runtime_stats.process_pending_stats(last_op_end_time);
#endif
// Use the last component's end time instead of calling millis() again
auto elapsed = last_op_end_time - this->last_loop_;

View File

@ -9,7 +9,9 @@
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/preferences.h"
#include "esphome/core/runtime_stats.h"
#ifdef USE_RUNTIME_STATS
#include "esphome/components/runtime_stats/runtime_stats.h"
#endif
#include "esphome/core/scheduler.h"
#ifdef USE_DEVICES
@ -349,17 +351,13 @@ class Application {
uint32_t get_loop_interval() const { return static_cast<uint32_t>(this->loop_interval_); }
/** Enable or disable runtime statistics collection.
*
* @param enable Whether to enable runtime statistics collection.
*/
void set_runtime_stats_enabled(bool enable) { runtime_stats.set_enabled(enable); }
#ifdef USE_RUNTIME_STATS
/** Set the interval at which runtime statistics are logged.
*
* @param interval The interval in milliseconds between logging of runtime statistics.
*/
void set_runtime_stats_log_interval(uint32_t interval) { runtime_stats.set_log_interval(interval); }
#endif
void schedule_dump_config() { this->dump_config_at_ = 0; }

View File

@ -396,8 +396,10 @@ uint32_t WarnIfComponentBlockingGuard::finish() {
uint32_t blocking_time = curr_time - this->started_;
#ifdef USE_RUNTIME_STATS
// Record component runtime stats
runtime_stats.record_component_time(this->component_, blocking_time, curr_time);
#endif
bool should_warn;
if (this->component_ != nullptr) {
should_warn = this->component_->should_warn_of_blocking(blocking_time);

View File

@ -6,7 +6,9 @@
#include <string>
#include "esphome/core/optional.h"
#include "esphome/core/runtime_stats.h"
#ifdef USE_RUNTIME_STATS
#include "esphome/components/runtime_stats/runtime_stats.h"
#endif
namespace esphome {