Files
esphome/esphome
J. Nick Koston 75f5b17937 [core] Thread Scheduler now_64 into next_schedule_in to skip duplicate clock read
Scheduler::call() and Scheduler::next_schedule_in() both computed now_64 via
millis_64_from_(now) at the top of every main-loop iteration. On ESP32 with
USE_NATIVE_64BIT_TIME this is an esp_timer_get_time() MMIO read (~1us);
doing it twice per iteration is wasted work since the two calls happen
microseconds apart.

Thread the value through:

- Scheduler::call() now returns a CallResult { now, now_64 } struct instead
  of just the advanced uint32_t now. When items fired, now_64 is set to 0
  (sentinel) because execute_item_() only advances the uint32 and the local
  now_64 is stale by the time we return.
- Scheduler::next_schedule_in() takes an optional now_64 parameter
  (default 0). Non-zero values are trusted and used directly; the 0
  sentinel triggers a fresh millis_64_from_(now) read.
- Application::scheduler_tick_() forwards the CallResult through.
- Application::loop() passes sched_result.now_64 to next_schedule_in().

Verified in the disassembly: on the fast path (no items fired),
next_schedule_in branches over its esp_timer_get_time call entirely via
`or a8, a4, a5; bnez a8, ...` on the two halves of now_64, jumping
straight to the next_exec comparison. When call() returned the 0 sentinel,
next_schedule_in falls through to the existing inlined
micros_to_millis(esp_timer_get_time()) sequence as before.

Bench callers (tests/benchmarks/core/bench_scheduler.cpp) and the external
test component (tests/integration/fixtures/.../scheduler_bulk_cleanup_component)
ignore the return value — no changes needed there.
2026-04-24 15:32:09 -05:00
..
2026-04-09 11:28:48 +12:00
…
…
…
…