Mark SubscribeLogsResponse with (speed_optimized) = true so its
encode() and calculate_size() are compiled with -O2. Log messages
are among the most frequent messages sent over the API, especially
during debug sessions.
Add __attribute__((optimize("O2"))) to the main loop functions
(loop_task on ESP32, codegen loop() on other platforms) so GCC
inlines scheduler helpers and loop bookkeeping more aggressively.
Under -Os, GCC outlines small functions (Scheduler::call helpers,
millis conversions, etc.) that are called every loop iteration.
With -O2, these get inlined into the loop body, reducing call
overhead on the hottest code path in the firmware.
ESP32: loop_task grows from 303 to 416 bytes (+113 bytes).
ESP8266: no change (already fully inlined via ESPHOME_ALWAYS_INLINE).
Add __attribute__((optimize("O2"))) to the main loop functions
(loop_task on ESP32, codegen loop() on other platforms) so GCC
inlines scheduler helpers and loop bookkeeping more aggressively.
Under -Os, GCC outlines small functions (Scheduler::call helpers,
millis conversions, etc.) that are called every loop iteration.
With -O2, these get inlined into the loop body, reducing call
overhead on the hottest code path in the firmware.
ESP32: loop_task grows from 303 to 416 bytes (+113 bytes).
ESP8266: no change (already fully inlined via ESPHOME_ALWAYS_INLINE).
Add a new (speed_optimized) message option that emits
__attribute__((optimize("O2"))) on the generated encode() and
calculate_size() methods. Under -Os, GCC does not inline the small
ProtoEncode helpers (write_raw_byte, encode_varint, etc.) into the
generated methods, causing significant overhead on hot paths.
Apply to SensorStateResponse and BluetoothLERawAdvertisementsResponse
which are the highest-frequency encode paths.
Add a new (speed_optimized) message option that emits
__attribute__((optimize("O2"))) on the generated encode() and
calculate_size() methods. Under -Os, GCC does not inline the small
ProtoEncode helpers (write_raw_byte, encode_varint, etc.) into the
generated methods, causing significant overhead on hot paths.
Apply to SensorStateResponse and BluetoothLERawAdvertisementsResponse
which are the highest-frequency encode paths.
CodSpeed results show only Noise benchmarks improved with -O2 —
the speedup comes from libsodium's crypto primitives (Curve25519,
ChaCha20, Poly1305), not noise-c's protocol layer. Narrow the
optimization to libsodium only.
Crypto libraries are CPU-bound and benefit significantly from speed
optimization over the default -Os. Add a post: extra_script that
appends -O2 to noise-c and libsodium build flags when API noise
encryption is enabled. GCC uses the last -O flag, so this overrides
the global -Os for these libraries only.
CodSpeed benchmarks were building with -O2, while all firmware
targets (ESP8266, ESP32, LibreTiny) use -Os. This mismatch means
the benchmarks cannot detect inlining regressions that affect real
devices — GCC under -O2 inlines functions that -Os outlines due to
its size-conscious cost model.
Switch to -Os with -ffunction-sections/-fdata-sections for proper
dead-code stripping (needed because -Os preserves references that
-O2 optimizes away at compile time).
CodSpeed benchmarks were building with -O2, while all firmware
targets (ESP8266, ESP32, LibreTiny) use -Os. This mismatch means
the benchmarks cannot detect inlining regressions that affect real
devices — GCC under -O2 inlines functions that -Os outlines due to
its size-conscious cost model.
Remove the -Os unflag and -O2 override so benchmarks use the
platform default -Os, matching what actually runs on devices.
process_defer_queue_() follows the same fast-path/slow-path pattern
as cleanup_() and process_to_add(): an atomic load + branch that
skips to the slow path only when work is pending. GCC currently
inlines it, but past experience shows the compiler can change its
mind when surrounding code changes. Use ESPHOME_ALWAYS_INLINE to
lock in the intended behavior.
process_to_add() has the same pattern as cleanup_(): a one-line
inline fast path (check if to_add_ is empty) with the slow path
already out-of-line in process_to_add_slow_path_(). GCC inlines it
on ESP8266 but not on ESP32, emitting a 20-byte out-of-line body.
Use ESPHOME_ALWAYS_INLINE to guarantee inlining on all platforms.
Verified on ESP32 (xtensa-esp32):
- process_to_add() symbol eliminated from binary
- Scheduler::call() idle path: 1 out-of-line call (millis_64 only)