Each of these methods called encode_field_raw() then a value encoder,
causing a store-load pair on pos_ between the tag and value writes.
Inline the tag write into the same __restrict__ local scope as the
value write so the compiler can emit tag + value with a single pos_
load at start and store at end. Verified on Xtensa: encode_uint32
now does one load + two writes + one store (was load-store-load-store).
Add sync_debug_check_bounds_() that syncs pos_ from a local pointer
before checking bounds. Use it in encode_varint_raw_64 and
encode_varint_raw_slow_ to restore per-byte bounds checking in
debug mode without breaking the __restrict__ optimization in
production (where it's a no-op).
Previously encode_string called encode_varint_raw(len) then
encode_raw(data, len) as separate methods, each with their own
__restrict__ pos scope. This caused a redundant store-load pair
of pos_ between the two operations.
Inline the length varint write and memcpy under a single local
pos variable so the compiler can keep pos_ in a register across
both operations. Eliminates one load-store pair per string encode.
Apply the same __restrict__ local pointer pattern proven in
encode_varint_raw_64 to all remaining methods that write through
pos_: encode_varint_raw, encode_varint_raw_short, write_raw_byte,
encode_raw, write_tag_and_fixed32, encode_string, encode_bool,
and encode_fixed32.
Each method now hoists pos_ into a __restrict__ local before
writing and stores back once at the end. When the compiler inlines
these into a generated encode() method, it can keep pos_ in a
register across consecutive calls instead of reloading from memory
after every write.
Same optimization as encode_varint_raw_64: hoist pos_ into a
__restrict__ local so the compiler keeps it in a register across
the loop instead of reloading from memory each iteration.
Use a __restrict__ local pointer for the varint write loop so the
compiler can keep it in a register instead of reloading pos_ from
memory on each iteration. Eliminates the store→load dependency
chain that was causing 7 load/store pairs for a typical 48-bit
BLE address varint.
Use a __restrict__ local pointer for the varint write loop so the
compiler can keep it in a register instead of reloading pos_ from
memory on each iteration. Eliminates the store→load dependency
chain that was causing 7 load/store pairs for a typical 48-bit
BLE address varint.
Add encode_varint_raw_short() and ProtoSize::varint_short() that
inline both the 1-byte and 2-byte varint paths, falling back to
the noinline slow path for 3+ bytes.
Use these for sint32 fields (zigzag encoding), where values like
RSSI (-100 to 0) produce zigzag values that are 1-2 bytes. This
avoids a function call for the common case without bloating the
generic encode_varint_raw fast path.
Add CodSpeed benchmarks for BluetoothLERawAdvertisementsResponse
(12 advertisements) covering calculate_size, encode, calc+encode,
and fresh-buffer paths.
Includes a lightweight bluetooth_proxy stub header in
tests/benchmarks/stubs/ so the api component can compile with
USE_BLUETOOTH_PROXY on the host platform without pulling in
ESP32 BLE dependencies.