mirror of
https://github.com/esphome/esphome.git
synced 2025-03-13 22:28:14 +00:00
Avoid unnecessary copies
This commit is contained in:
parent
86b8ddd7e2
commit
44f9874645
@ -93,6 +93,9 @@ void Application::loop() {
|
||||
delay_time = this->loop_interval_ - (now - this->last_loop_);
|
||||
|
||||
uint32_t next_schedule = this->scheduler.next_schedule_in().value_or(delay_time);
|
||||
// next_schedule is max 0.5*delay_time
|
||||
// otherwise interval=0 schedules result in constant looping with almost no sleep
|
||||
next_schedule = std::max(next_schedule, delay_time / 2);
|
||||
delay_time = std::min(next_schedule, delay_time);
|
||||
delay(delay_time);
|
||||
}
|
||||
|
@ -42,16 +42,16 @@ void Component::setup() {}
|
||||
|
||||
void Component::loop() {}
|
||||
|
||||
void Component::set_interval(const std::string &name, uint32_t interval, std::function<void()> f) { // NOLINT
|
||||
App.scheduler.set_interval(this, name, interval, f);
|
||||
void Component::set_interval(const std::string &name, uint32_t interval, std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_interval(this, name, interval, std::move(f));
|
||||
}
|
||||
|
||||
bool Component::cancel_interval(const std::string &name) { // NOLINT
|
||||
return App.scheduler.cancel_interval(this, name);
|
||||
}
|
||||
|
||||
void Component::set_timeout(const std::string &name, uint32_t timeout, std::function<void()> f) { // NOLINT
|
||||
return App.scheduler.set_timeout(this, name, timeout, f);
|
||||
void Component::set_timeout(const std::string &name, uint32_t timeout, std::function<void()> &&f) { // NOLINT
|
||||
return App.scheduler.set_timeout(this, name, timeout, std::move(f));
|
||||
}
|
||||
|
||||
bool Component::cancel_timeout(const std::string &name) { // NOLINT
|
||||
@ -82,18 +82,20 @@ void Component::mark_failed() {
|
||||
this->component_state_ |= COMPONENT_STATE_FAILED;
|
||||
this->status_set_error();
|
||||
}
|
||||
void Component::defer(std::function<void()> f) { App.scheduler.set_timeout(this, "", 0, f); } // NOLINT
|
||||
bool Component::cancel_defer(const std::string &name) { // NOLINT
|
||||
void Component::defer(std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, "", 0, std::move(f));
|
||||
}
|
||||
bool Component::cancel_defer(const std::string &name) { // NOLINT
|
||||
return App.scheduler.cancel_timeout(this, name);
|
||||
}
|
||||
void Component::defer(const std::string &name, std::function<void()> f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, name, 0, f);
|
||||
void Component::defer(const std::string &name, std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, name, 0, std::move(f));
|
||||
}
|
||||
void Component::set_timeout(uint32_t timeout, std::function<void()> f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, "", timeout, f);
|
||||
void Component::set_timeout(uint32_t timeout, std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, "", timeout, std::move(f));
|
||||
}
|
||||
void Component::set_interval(uint32_t interval, std::function<void()> f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, "", interval, f);
|
||||
void Component::set_interval(uint32_t interval, std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, "", interval, std::move(f));
|
||||
}
|
||||
bool Component::is_failed() { return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED; }
|
||||
bool Component::can_proceed() { return true; }
|
||||
|
@ -153,9 +153,9 @@ class Component {
|
||||
*
|
||||
* @see cancel_interval()
|
||||
*/
|
||||
void set_interval(const std::string &name, uint32_t interval, std::function<void()> f); // NOLINT
|
||||
void set_interval(const std::string &name, uint32_t interval, std::function<void()> &&f); // NOLINT
|
||||
|
||||
void set_interval(uint32_t interval, std::function<void()> f); // NOLINT
|
||||
void set_interval(uint32_t interval, std::function<void()> &&f); // NOLINT
|
||||
|
||||
/** Cancel an interval function.
|
||||
*
|
||||
@ -164,7 +164,7 @@ class Component {
|
||||
*/
|
||||
bool cancel_interval(const std::string &name); // NOLINT
|
||||
|
||||
void set_timeout(uint32_t timeout, std::function<void()> f); // NOLINT
|
||||
void set_timeout(uint32_t timeout, std::function<void()> &&f); // NOLINT
|
||||
|
||||
/** Set a timeout function with a unique name.
|
||||
*
|
||||
@ -180,7 +180,7 @@ class Component {
|
||||
*
|
||||
* @see cancel_timeout()
|
||||
*/
|
||||
void set_timeout(const std::string &name, uint32_t timeout, std::function<void()> f); // NOLINT
|
||||
void set_timeout(const std::string &name, uint32_t timeout, std::function<void()> &&f); // NOLINT
|
||||
|
||||
/** Cancel a timeout function.
|
||||
*
|
||||
@ -196,10 +196,10 @@ class Component {
|
||||
* @param name The name of the defer function.
|
||||
* @param f The callback.
|
||||
*/
|
||||
void defer(const std::string &name, std::function<void()> f); // NOLINT
|
||||
void defer(const std::string &name, std::function<void()> &&f); // NOLINT
|
||||
|
||||
/// Defer a callback to the next loop() call.
|
||||
void defer(std::function<void()> f); // NOLINT
|
||||
void defer(std::function<void()> &&f); // NOLINT
|
||||
|
||||
/// Cancel a defer callback using the specified name, name must not be empty.
|
||||
bool cancel_defer(const std::string &name); // NOLINT
|
||||
|
@ -7,7 +7,7 @@ namespace esphome {
|
||||
|
||||
static const char *TAG = "scheduler";
|
||||
|
||||
void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function<void()> func) {
|
||||
void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function<void()> &&func) {
|
||||
const uint32_t now = millis();
|
||||
|
||||
if (!name.empty())
|
||||
@ -21,7 +21,7 @@ void HOT Scheduler::set_timeout(Component *component, const std::string &name, u
|
||||
item.type = SchedulerItem::TIMEOUT;
|
||||
item.timeout = timeout;
|
||||
item.last_execution = now;
|
||||
item.f = func;
|
||||
item.f = std::move(func);
|
||||
item.remove = false;
|
||||
this->push_(item);
|
||||
}
|
||||
@ -31,7 +31,7 @@ bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name
|
||||
void HOT Scheduler::set_interval(Component *component,
|
||||
const std::string &name,
|
||||
uint32_t interval,
|
||||
std::function<void()> func) {
|
||||
std::function<void()> &&func) {
|
||||
const uint32_t now = millis();
|
||||
|
||||
// only put offset in lower half
|
||||
@ -50,7 +50,7 @@ void HOT Scheduler::set_interval(Component *component,
|
||||
item.type = SchedulerItem::INTERVAL;
|
||||
item.interval = interval;
|
||||
item.last_execution = now - offset;
|
||||
item.f = func;
|
||||
item.f = std::move(func);
|
||||
item.remove = false;
|
||||
this->push_(item);
|
||||
}
|
||||
@ -58,11 +58,11 @@ bool HOT Scheduler::cancel_interval(Component *component, const std::string &nam
|
||||
return this->cancel_item_(component, name, SchedulerItem::INTERVAL);
|
||||
}
|
||||
optional<uint32_t> HOT Scheduler::next_schedule_in() {
|
||||
auto item = this->peek_();
|
||||
if (!item.has_value())
|
||||
if (!this->peek_())
|
||||
return {};
|
||||
auto &item = this->items_[0];
|
||||
const uint32_t now = millis();
|
||||
uint32_t next_time = item->last_execution + item->interval;
|
||||
uint32_t next_time = item.last_execution + item.interval;
|
||||
if (next_time < now)
|
||||
return 0;
|
||||
return next_time - now;
|
||||
@ -72,25 +72,36 @@ void ICACHE_RAM_ATTR HOT Scheduler::call() {
|
||||
this->process_to_add_();
|
||||
|
||||
while (true) {
|
||||
auto item = this->peek_();
|
||||
if (!item.has_value() || (now - item->last_execution) < item->interval)
|
||||
bool has_item = this->peek_();
|
||||
if (!has_item)
|
||||
break;
|
||||
|
||||
// Don't copy-by value yet
|
||||
auto &item_ref = this->items_[0];
|
||||
if ((now - item_ref.last_execution) < item_ref.interval)
|
||||
break;
|
||||
|
||||
auto item = this->items_[0];
|
||||
this->pop_();
|
||||
|
||||
// Don't run failed components
|
||||
if (item.component->is_failed())
|
||||
continue;
|
||||
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
const char *type =
|
||||
item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
|
||||
ESP_LOGVV(TAG, "Running %s '%s' with interval=%u last_execution=%u (now=%u)", type, item->name.c_str(),
|
||||
item->interval, item->last_execution, now);
|
||||
item.type == SchedulerItem::INTERVAL ? "interval" : "timeout";
|
||||
ESP_LOGVV(TAG, "Running %s '%s' with interval=%u last_execution=%u (now=%u)", type, item.name.c_str(),
|
||||
item.interval, item.last_execution, now);
|
||||
#endif
|
||||
|
||||
item->f();
|
||||
if (item->type == SchedulerItem::INTERVAL) {
|
||||
if (item->interval != 0) {
|
||||
const uint32_t amount = (now - item->last_execution) / item->interval;
|
||||
item->last_execution += amount * item->interval;
|
||||
item.f();
|
||||
if (item.type == SchedulerItem::INTERVAL) {
|
||||
if (item.interval != 0) {
|
||||
const uint32_t amount = (now - item.last_execution) / item.interval;
|
||||
item.last_execution += amount * item.interval;
|
||||
}
|
||||
this->push_(*item);
|
||||
this->push_(item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,23 +125,22 @@ void HOT Scheduler::cleanup_() {
|
||||
this->pop_raw_();
|
||||
}
|
||||
}
|
||||
optional<Scheduler::SchedulerItem> HOT Scheduler::peek_() {
|
||||
bool HOT Scheduler::peek_() {
|
||||
this->cleanup_();
|
||||
if (this->items_.empty())
|
||||
return {};
|
||||
return this->items_[0];
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
optional<Scheduler::SchedulerItem> HOT Scheduler::pop_() {
|
||||
bool HOT Scheduler::pop_() {
|
||||
this->cleanup_();
|
||||
if (this->items_.empty())
|
||||
return {};
|
||||
return this->pop_raw_();
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
Scheduler::SchedulerItem HOT Scheduler::pop_raw_() {
|
||||
void HOT Scheduler::pop_raw_() {
|
||||
std::pop_heap(this->items_.begin(), this->items_.end());
|
||||
auto item = this->items_.back();
|
||||
this->items_.pop_back();
|
||||
return item;
|
||||
}
|
||||
void HOT Scheduler::push_(const Scheduler::SchedulerItem &item) {
|
||||
this->to_add_.push_back(item);
|
||||
@ -141,15 +151,11 @@ bool HOT Scheduler::cancel_item_(Component *component, const std::string &name,
|
||||
if (it.component == component && it.name == name && it.type == type) {
|
||||
it.remove = true;
|
||||
ret = true;
|
||||
if (!name.empty())
|
||||
return true;
|
||||
}
|
||||
for (auto &it : this->to_add_)
|
||||
if (it.component == component && it.name == name && it.type == type) {
|
||||
it.remove = true;
|
||||
ret = true;
|
||||
if (!name.empty())
|
||||
return true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -9,9 +9,9 @@ class Component;
|
||||
|
||||
class Scheduler {
|
||||
public:
|
||||
void set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function<void()> func);
|
||||
void set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function<void()> &&func);
|
||||
bool cancel_timeout(Component *component, const std::string &name);
|
||||
void set_interval(Component *component, const std::string &name, uint32_t interval, std::function<void()> func);
|
||||
void set_interval(Component *component, const std::string &name, uint32_t interval, std::function<void()> &&func);
|
||||
bool cancel_interval(Component *component, const std::string &name);
|
||||
|
||||
optional<uint32_t> next_schedule_in();
|
||||
@ -36,9 +36,9 @@ class Scheduler {
|
||||
|
||||
void process_to_add_();
|
||||
void cleanup_();
|
||||
optional<SchedulerItem> peek_();
|
||||
optional<SchedulerItem> pop_();
|
||||
SchedulerItem pop_raw_();
|
||||
bool peek_();
|
||||
bool pop_();
|
||||
void pop_raw_();
|
||||
void push_(const SchedulerItem& item);
|
||||
bool cancel_item_(Component *component, const std::string &name, SchedulerItem::Type type);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user