1
0
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:
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_);
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);
}

View File

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

View File

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

View File

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

View File

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