mirror of
https://github.com/esphome/esphome.git
synced 2025-03-15 07:08:20 +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_);
|
delay_time = this->loop_interval_ - (now - this->last_loop_);
|
||||||
|
|
||||||
uint32_t next_schedule = this->scheduler.next_schedule_in().value_or(delay_time);
|
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_time = std::min(next_schedule, delay_time);
|
||||||
delay(delay_time);
|
delay(delay_time);
|
||||||
}
|
}
|
||||||
|
@ -42,16 +42,16 @@ void Component::setup() {}
|
|||||||
|
|
||||||
void Component::loop() {}
|
void Component::loop() {}
|
||||||
|
|
||||||
void Component::set_interval(const std::string &name, uint32_t interval, std::function<void()> f) { // NOLINT
|
void Component::set_interval(const std::string &name, uint32_t interval, std::function<void()> &&f) { // NOLINT
|
||||||
App.scheduler.set_interval(this, name, interval, f);
|
App.scheduler.set_interval(this, name, interval, std::move(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Component::cancel_interval(const std::string &name) { // NOLINT
|
bool Component::cancel_interval(const std::string &name) { // NOLINT
|
||||||
return App.scheduler.cancel_interval(this, name);
|
return App.scheduler.cancel_interval(this, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Component::set_timeout(const std::string &name, uint32_t timeout, std::function<void()> f) { // NOLINT
|
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);
|
return App.scheduler.set_timeout(this, name, timeout, std::move(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Component::cancel_timeout(const std::string &name) { // NOLINT
|
bool Component::cancel_timeout(const std::string &name) { // NOLINT
|
||||||
@ -82,18 +82,20 @@ void Component::mark_failed() {
|
|||||||
this->component_state_ |= COMPONENT_STATE_FAILED;
|
this->component_state_ |= COMPONENT_STATE_FAILED;
|
||||||
this->status_set_error();
|
this->status_set_error();
|
||||||
}
|
}
|
||||||
void Component::defer(std::function<void()> f) { App.scheduler.set_timeout(this, "", 0, f); } // NOLINT
|
void Component::defer(std::function<void()> &&f) { // NOLINT
|
||||||
bool Component::cancel_defer(const std::string &name) { // 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);
|
return App.scheduler.cancel_timeout(this, name);
|
||||||
}
|
}
|
||||||
void Component::defer(const std::string &name, std::function<void()> f) { // NOLINT
|
void Component::defer(const std::string &name, std::function<void()> &&f) { // NOLINT
|
||||||
App.scheduler.set_timeout(this, name, 0, f);
|
App.scheduler.set_timeout(this, name, 0, std::move(f));
|
||||||
}
|
}
|
||||||
void Component::set_timeout(uint32_t timeout, std::function<void()> f) { // NOLINT
|
void Component::set_timeout(uint32_t timeout, std::function<void()> &&f) { // NOLINT
|
||||||
App.scheduler.set_timeout(this, "", timeout, f);
|
App.scheduler.set_timeout(this, "", timeout, std::move(f));
|
||||||
}
|
}
|
||||||
void Component::set_interval(uint32_t interval, std::function<void()> f) { // NOLINT
|
void Component::set_interval(uint32_t interval, std::function<void()> &&f) { // NOLINT
|
||||||
App.scheduler.set_timeout(this, "", interval, f);
|
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::is_failed() { return (this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED; }
|
||||||
bool Component::can_proceed() { return true; }
|
bool Component::can_proceed() { return true; }
|
||||||
|
@ -153,9 +153,9 @@ class Component {
|
|||||||
*
|
*
|
||||||
* @see cancel_interval()
|
* @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.
|
/** Cancel an interval function.
|
||||||
*
|
*
|
||||||
@ -164,7 +164,7 @@ class Component {
|
|||||||
*/
|
*/
|
||||||
bool cancel_interval(const std::string &name); // NOLINT
|
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.
|
/** Set a timeout function with a unique name.
|
||||||
*
|
*
|
||||||
@ -180,7 +180,7 @@ class Component {
|
|||||||
*
|
*
|
||||||
* @see cancel_timeout()
|
* @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.
|
/** Cancel a timeout function.
|
||||||
*
|
*
|
||||||
@ -196,10 +196,10 @@ class Component {
|
|||||||
* @param name The name of the defer function.
|
* @param name The name of the defer function.
|
||||||
* @param f The callback.
|
* @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.
|
/// 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.
|
/// Cancel a defer callback using the specified name, name must not be empty.
|
||||||
bool cancel_defer(const std::string &name); // NOLINT
|
bool cancel_defer(const std::string &name); // NOLINT
|
||||||
|
@ -7,7 +7,7 @@ namespace esphome {
|
|||||||
|
|
||||||
static const char *TAG = "scheduler";
|
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();
|
const uint32_t now = millis();
|
||||||
|
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
@ -21,7 +21,7 @@ void HOT Scheduler::set_timeout(Component *component, const std::string &name, u
|
|||||||
item.type = SchedulerItem::TIMEOUT;
|
item.type = SchedulerItem::TIMEOUT;
|
||||||
item.timeout = timeout;
|
item.timeout = timeout;
|
||||||
item.last_execution = now;
|
item.last_execution = now;
|
||||||
item.f = func;
|
item.f = std::move(func);
|
||||||
item.remove = false;
|
item.remove = false;
|
||||||
this->push_(item);
|
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,
|
void HOT Scheduler::set_interval(Component *component,
|
||||||
const std::string &name,
|
const std::string &name,
|
||||||
uint32_t interval,
|
uint32_t interval,
|
||||||
std::function<void()> func) {
|
std::function<void()> &&func) {
|
||||||
const uint32_t now = millis();
|
const uint32_t now = millis();
|
||||||
|
|
||||||
// only put offset in lower half
|
// only put offset in lower half
|
||||||
@ -50,7 +50,7 @@ void HOT Scheduler::set_interval(Component *component,
|
|||||||
item.type = SchedulerItem::INTERVAL;
|
item.type = SchedulerItem::INTERVAL;
|
||||||
item.interval = interval;
|
item.interval = interval;
|
||||||
item.last_execution = now - offset;
|
item.last_execution = now - offset;
|
||||||
item.f = func;
|
item.f = std::move(func);
|
||||||
item.remove = false;
|
item.remove = false;
|
||||||
this->push_(item);
|
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);
|
return this->cancel_item_(component, name, SchedulerItem::INTERVAL);
|
||||||
}
|
}
|
||||||
optional<uint32_t> HOT Scheduler::next_schedule_in() {
|
optional<uint32_t> HOT Scheduler::next_schedule_in() {
|
||||||
auto item = this->peek_();
|
if (!this->peek_())
|
||||||
if (!item.has_value())
|
|
||||||
return {};
|
return {};
|
||||||
|
auto &item = this->items_[0];
|
||||||
const uint32_t now = millis();
|
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)
|
if (next_time < now)
|
||||||
return 0;
|
return 0;
|
||||||
return next_time - now;
|
return next_time - now;
|
||||||
@ -72,25 +72,36 @@ void ICACHE_RAM_ATTR HOT Scheduler::call() {
|
|||||||
this->process_to_add_();
|
this->process_to_add_();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto item = this->peek_();
|
bool has_item = this->peek_();
|
||||||
if (!item.has_value() || (now - item->last_execution) < item->interval)
|
if (!has_item)
|
||||||
break;
|
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_();
|
this->pop_();
|
||||||
|
|
||||||
|
// Don't run failed components
|
||||||
|
if (item.component->is_failed())
|
||||||
|
continue;
|
||||||
|
|
||||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||||
const char *type =
|
const char *type =
|
||||||
item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
|
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(),
|
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.interval, item.last_execution, now);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
item->f();
|
item.f();
|
||||||
if (item->type == SchedulerItem::INTERVAL) {
|
if (item.type == SchedulerItem::INTERVAL) {
|
||||||
if (item->interval != 0) {
|
if (item.interval != 0) {
|
||||||
const uint32_t amount = (now - item->last_execution) / item->interval;
|
const uint32_t amount = (now - item.last_execution) / item.interval;
|
||||||
item->last_execution += amount * 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_();
|
this->pop_raw_();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
optional<Scheduler::SchedulerItem> HOT Scheduler::peek_() {
|
bool HOT Scheduler::peek_() {
|
||||||
this->cleanup_();
|
this->cleanup_();
|
||||||
if (this->items_.empty())
|
if (this->items_.empty())
|
||||||
return {};
|
return false;
|
||||||
return this->items_[0];
|
return true;
|
||||||
}
|
}
|
||||||
optional<Scheduler::SchedulerItem> HOT Scheduler::pop_() {
|
bool HOT Scheduler::pop_() {
|
||||||
this->cleanup_();
|
this->cleanup_();
|
||||||
if (this->items_.empty())
|
if (this->items_.empty())
|
||||||
return {};
|
return false;
|
||||||
return this->pop_raw_();
|
return true;
|
||||||
}
|
}
|
||||||
Scheduler::SchedulerItem HOT Scheduler::pop_raw_() {
|
void HOT Scheduler::pop_raw_() {
|
||||||
std::pop_heap(this->items_.begin(), this->items_.end());
|
std::pop_heap(this->items_.begin(), this->items_.end());
|
||||||
auto item = this->items_.back();
|
auto item = this->items_.back();
|
||||||
this->items_.pop_back();
|
this->items_.pop_back();
|
||||||
return item;
|
|
||||||
}
|
}
|
||||||
void HOT Scheduler::push_(const Scheduler::SchedulerItem &item) {
|
void HOT Scheduler::push_(const Scheduler::SchedulerItem &item) {
|
||||||
this->to_add_.push_back(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) {
|
if (it.component == component && it.name == name && it.type == type) {
|
||||||
it.remove = true;
|
it.remove = true;
|
||||||
ret = true;
|
ret = true;
|
||||||
if (!name.empty())
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
for (auto &it : this->to_add_)
|
for (auto &it : this->to_add_)
|
||||||
if (it.component == component && it.name == name && it.type == type) {
|
if (it.component == component && it.name == name && it.type == type) {
|
||||||
it.remove = true;
|
it.remove = true;
|
||||||
ret = true;
|
ret = true;
|
||||||
if (!name.empty())
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -9,9 +9,9 @@ class Component;
|
|||||||
|
|
||||||
class Scheduler {
|
class Scheduler {
|
||||||
public:
|
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);
|
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);
|
bool cancel_interval(Component *component, const std::string &name);
|
||||||
|
|
||||||
optional<uint32_t> next_schedule_in();
|
optional<uint32_t> next_schedule_in();
|
||||||
@ -36,9 +36,9 @@ class Scheduler {
|
|||||||
|
|
||||||
void process_to_add_();
|
void process_to_add_();
|
||||||
void cleanup_();
|
void cleanup_();
|
||||||
optional<SchedulerItem> peek_();
|
bool peek_();
|
||||||
optional<SchedulerItem> pop_();
|
bool pop_();
|
||||||
SchedulerItem pop_raw_();
|
void pop_raw_();
|
||||||
void push_(const SchedulerItem& item);
|
void push_(const SchedulerItem& item);
|
||||||
bool cancel_item_(Component *component, const std::string &name, SchedulerItem::Type type);
|
bool cancel_item_(Component *component, const std::string &name, SchedulerItem::Type type);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user