1
0
mirror of https://github.com/esphome/esphome.git synced 2025-03-15 15:18:16 +00:00

Avoid unnecessary copies

This commit is contained in:
Otto Winter 2019-06-03 22:17:56 +02:00
parent 86b8ddd7e2
commit 44f9874645
No known key found for this signature in database
GPG Key ID: DB66C0BE6013F97E
5 changed files with 64 additions and 53 deletions

View File

@ -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);
} }

View File

@ -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
App.scheduler.set_timeout(this, "", 0, std::move(f));
}
bool Component::cancel_defer(const std::string &name) { // NOLINT 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; }

View File

@ -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

View File

@ -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;

View File

@ -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);