Commit Graph
23681 Commits
Author SHA1 Message Date
J. Nick Koston 696c93ee43 Merge remote-tracking branch 'upstream/esp32-millis-euclidean-decomposition' into integration 2026-03-02 00:16:16 -10:00
J. Nick Koston 1e3f7b3c90 [core] Fix clang-tidy: lowercase function-local constexpr variables
clang-tidy readability-identifier-naming requires lowercase for
function-local variables, even constexpr ones. Rename D/Q/R to d/q/r.
2026-03-02 00:16:02 -10:00
J. Nick Koston 7bed94aa38 Merge remote-tracking branch 'upstream/esp32-millis-euclidean-decomposition' into integration 2026-03-02 00:11:13 -10:00
J. Nick Koston df57c21368 [core] Template micros_to_millis for both 32/64-bit results
Make micros_to_millis a template on return type (default uint32_t).
millis_64() now calls micros_to_millis<uint64_t>() to eliminate
__udivdi3 there too — same Euclidean decomposition, just with a
32x32->64 multiply for hi*Q instead of truncating.

Add 64-bit variant tests (140 total, all passing).
2026-03-02 00:11:02 -10:00
J. Nick Koston a8f8c3753f Merge remote-tracking branch 'upstream/esp32-millis-euclidean-decomposition' into integration 2026-03-02 00:10:32 -10:00
J. Nick Koston 99aa5043a3 [core] Add unit tests for micros_to_millis, make constexpr
Add Python unit tests (70 cases) verifying the Euclidean decomposition
matches us // 1000 across edge cases: small values, hi/lo boundaries,
carry-path overflow, realistic uptimes, and shift-boundary mod-8
variations.

Make micros_to_millis constexpr to enable compile-time validation
via static_assert.
2026-03-02 00:05:06 -10:00
J. Nick Koston bb4e34509d Merge remote-tracking branch 'upstream/esp32-millis-euclidean-decomposition' into integration 2026-03-01 23:49:32 -10:00
J. Nick Koston 0dc56d7a4d [core] Eliminate __udivdi3 in millis() on ESP32 and RP2040
On 32-bit targets GCC does not optimize 64-bit constant division
into a multiply-by-reciprocal, emitting a call to __udivdi3 instead
(~650-710 ns on Xtensa @ 240 MHz).

Add micros_to_millis() which exploits 1000 = 8 * 125: a free
right-shift by 3 followed by Euclidean decomposition with D=125,
reducing the 64-bit division to a single 32-bit / 125U that GCC
compiles to a multiply-by-reciprocal.

Benchmarked at 258 ns per call on ESP32 classic — a 2.5-2.8x
speedup. With ~21 millis() calls per loop iteration this saves
~9 us per loop.
2026-03-01 23:49:18 -10:00
J. Nick Koston 836a050123 Merge remote-tracking branch 'upstream/esp32-millis-euclidean-decomposition' into integration 2026-03-01 23:48:45 -10:00
J. Nick KostonandClaude Opus 4.6 5f91c96306 [core] Use shift3+div125 for micros_to_millis (1000 = 8 * 125)
Factor 1000 as 8 * 125. The divide-by-8 is a free right-shift,
then Euclidean decomposition with D=125 has a smaller remainder
(R=46 vs R=296), making hi*R cheaper and the safe input range
51x wider (~3.2e18 vs ~6.2e16 microseconds).

Benchmarked ~7% faster than the divide-by-1000 variant on ESP32
classic (257 ns vs 277 ns per call at 240 MHz).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:46:34 -10:00
J. Nick Koston bd0ba9ea4b Merge remote-tracking branch 'origin/esp32-millis-euclidean-decomposition' into integration 2026-03-01 23:32:46 -10:00
J. Nick Koston b3e1cbaa31 Merge branch 'dev' into esp32-millis-euclidean-decomposition 2026-03-01 23:31:55 -10:00
J. Nick Koston 7c175dda17 [core] Rename fast_div1000_32 to micros_to_millis 2026-03-01 23:30:06 -10:00
J. Nick Koston bf8990dcb0 [core] Document exact safe input range for fast_div1000_32 2026-03-01 23:27:38 -10:00
J. Nick Koston 263d6c1085 [core] Fix comment to describe input range, not uptime 2026-03-01 23:24:08 -10:00
J. Nick Koston cc3a51562d [core] Document safe range for fast_div1000_32 intermediate 2026-03-01 23:23:34 -10:00
J. Nick Koston 17a10bf303 [core] Derive fast_div1000_32 constants from expressions 2026-03-01 23:21:08 -10:00
J. Nick Koston 90b8f25a9b Merge remote-tracking branch 'origin/esp32-millis-euclidean-decomposition' into integration 2026-03-01 23:10:38 -10:00
J. Nick Koston 309cda0799 Merge remote-tracking branch 'upstream/dev' into integration 2026-03-01 23:02:57 -10:00
J. Nick Koston 4dbc139ede [core] Use ternary in fast_div1000_32 for clarity 2026-03-01 22:57:23 -10:00
J. Nick Koston 92106d2a4d [core] Eliminate __udivdi3 in millis() on ESP32 and RP2040
On 32-bit targets, GCC does not optimize 64-bit constant division
into a multiply-by-reciprocal and instead calls __udivdi3 (software
64-bit divide). This replaces the division with Euclidean
decomposition using a single 32-bit divide that GCC optimizes into
a multiply-by-reciprocal.

Benchmarked on ESP32 classic (Xtensa LX6, 240 MHz):
  __udivdi3: 628-705 ns
  fast_div1000_32: 269-279 ns (2.3-2.6x faster)

millis() is called ~21 times per main loop iteration. At ~350 ns
savings per call, this saves ~7 us per loop iteration.
2026-03-01 22:53:27 -10:00
Bonne EgglestonandJ. Nick Koston 3160457ca6 Create integration tests for modbus (#14395)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-03-01 22:51:27 -10:00
J. Nick Koston b387934880 Merge remote-tracking branch 'upstream/dev' into integration 2026-03-01 21:09:33 -10:00
J. Nick Koston 8f83f5c9fc Merge branch 'esp8266-wake-loop-any-context' into integration 2026-03-01 21:09:29 -10:00
590ee81f7a [openthread] Disable default enabled OT console build (#14390)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-03-02 06:16:36 +00:00
J. Nick Koston 0b0992fdf1 Merge remote-tracking branch 'upstream/dev' into esp8266-wake-loop-any-context 2026-03-01 19:57:00 -10:00
J. Nick Koston 9d4357c619 [core] Wake main loop from ISR in enable_loop_soon_any_context() (#14383) 2026-03-01 18:20:14 -10:00
J. Nick Koston 80a2acca4f [ld2410] Add UART mock integration test for LD2410 component (#14377) 2026-03-01 18:19:32 -10:00
J. Nick Koston f68a3ed15d [api] Remove virtual destructor from ProtoMessage (#14393) 2026-03-01 18:09:00 -10:00
schrob 6d3d8970a6 [openthread] Disable default enabled OT diag code (#14399) 2026-03-01 22:47:02 -05:00
073ca63f60 [rtttl] improve comments Part 2 (#13971)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-03-01 22:44:02 -05:00
J. Nick Koston fd78e19bc2 Merge remote-tracking branch 'origin/web_server' into integration 2026-03-01 17:04:50 -10:00
J. Nick Koston 3601aff8e0 Merge remote-tracking branch 'origin/api-flash-string-progmem' into integration 2026-03-01 17:04:44 -10:00
J. Nick Koston e93df630fa Merge remote-tracking branch 'origin/remove_posix_tz_parser' into integration 2026-03-01 17:04:42 -10:00
J. Nick Koston 33b4fc516b Merge branch 'dev' into web_server 2026-03-01 17:04:01 -10:00
J. Nick Koston 367de9b737 Merge branch 'dev' into api-flash-string-progmem 2026-03-01 17:03:18 -10:00
J. Nick Koston 251e0129a2 Merge remote-tracking branch 'upstream/dev' into remove_posix_tz_parser 2026-03-01 17:02:06 -10:00
J. Nick KostonandClaude Opus 4.6 0e18e4461e [time,api] Send pre-parsed timezone struct over protobuf (#14233)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:52:53 +13:00
J. Nick Koston 338a1ce244 Merge branch 'cache-lwip-sock-pointers' into integration
# Conflicts:
#	esphome/core/application.h
2026-03-01 16:47:08 -10:00
J. Nick Koston 5bd7f0ea96 [core] Cache lwip_sock pointers to simplify fast select hot path
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.

- register_socket(lwip_sock*) returns bool and hooks the callback
  internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
  fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
  for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
2026-03-01 16:46:58 -10:00
J. Nick Koston bad8525235 eliminate duplicate socket_listen* symbols on BSD/LWIP_SOCKETS 2026-03-01 16:44:53 -10:00
J. Nick Koston affad9439d Merge remote-tracking branch 'upstream/dev' into integration 2026-03-01 16:37:09 -10:00
J. Nick Koston 023faab206 Merge branch 'cache-lwip-sock-pointers' into integration
# Conflicts:
#	esphome/core/application.h
2026-03-01 15:38:10 -10:00
J. Nick Koston 680417941e [core] Cache lwip_sock pointers to simplify fast select hot path
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.

- register_socket(lwip_sock*) returns bool and hooks the callback
  internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
  fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
  for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
2026-03-01 15:38:01 -10:00
J. Nick Koston d8fa5ace1b document stale read tolerance in hint read comment 2026-03-01 15:37:42 -10:00
J. Nick Koston 1a8b7bd38e Merge branch 'cache-lwip-sock-pointers' into integration
# Conflicts:
#	esphome/core/application.h
2026-03-01 15:36:20 -10:00
J. Nick Koston 0a45c5a351 [core] Cache lwip_sock pointers to simplify fast select hot path
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.

- register_socket(lwip_sock*) returns bool and hooks the callback
  internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
  fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
  for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
2026-03-01 15:36:09 -10:00
J. Nick Koston 52f76a4f43 restore SYS_ARCH_UNPROTECT visibility comment 2026-03-01 15:35:52 -10:00
J. Nick Koston 1b5df15aaf Merge branch 'cache-lwip-sock-pointers' into integration
# Conflicts:
#	esphome/core/application.h
2026-03-01 15:35:32 -10:00
J. Nick Koston 2f43416005 [core] Cache lwip_sock pointers to simplify fast select hot path
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.

- register_socket(lwip_sock*) returns bool and hooks the callback
  internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
  fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
  for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
2026-03-01 15:35:20 -10:00