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