8000
Skip to content

[api] Optimize protobuf memory usage with fixed-size arrays for Bluetooth UUIDs - #9782

Merged
jesserockz merged 14 commits into
devfrom
fixed_arrays
Jul 22, 2025
Merged

[api] Optimize protobuf memory usage with fixed-size arrays for Bluetooth UUIDs#9782
jesserockz merged 14 commits into
devfrom
fixed_arrays

Conversation

@bdraco
@bdraco bdraco commented Jul 21, 2025
Copy link
Copy Markdown
Member

What does this implement/fix?

This PR implements a critical performance optimization for Bluetooth proxy functionality by introducing support for fixed-size arrays in protobuf messages. Service discovery is the performance bottleneck for all BLE connections, and this optimization directly addresses that by replacing dynamic memory allocations with fixed-size arrays for Bluetooth UUIDs and service responses.

Key Changes:

  1. Extended protobuf code generator to support fixed_array_size option on repeated fields
  2. Converted Bluetooth UUID fields from std::vector<uint64_t> to std::array<uint64_t, 2>
  3. Converted service response from std::vector<BluetoothGATTService> to std::array<BluetoothGATTService, 1>
  4. Added validation to ensure fixed arrays are only used for encode-only (SOURCE_SERVER) messages
  5. Optimized code generation for small arrays (size 1-2) by unrolling loops
  6. Refactored UUID conversion to use direct array filling instead of return-by-value for better performance

Memory Savings (ESP32 - 32-bit architecture):

For a typical Bluetooth service discovery with 31 UUIDs (1 service + 10 characteristics + 20 descriptors):

Before: Each UUID required its own heap allocation

  • 31 separate heap allocations for UUID vectors
  • 620 bytes overhead (vector headers + allocation metadata)
  • 496 bytes for UUID data
  • Total: 1,116 bytes

After: UUIDs embedded directly in their parent structures

  • 0 separate heap allocations for UUIDs
  • 0 bytes overhead (no vectors, no allocation metadata)
  • 496 bytes for UUID data (embedded)
  • Total: 496 bytes

Savings: 620 bytes (56% reduction) + 12 bytes from service array = 632 bytes per discovery

Flash savings: 728 bytes (measured reduction in compiled binary size)

This optimization significantly improves BLE connection performance by:

  • Eliminating heap allocations during the critical service discovery phase
  • Reducing memory fragmentation that can cause connection failures
  • Improving response times for BLE operations
  • Making it more feasible to increase the simultaneous connection limit beyond the current default 3-device limit in future releases

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Code quality improvements to existing code or addition of tests
  • Other

Related issue or feature (if applicable): N/A

Pull request in esphome-docs with documentation (if applicable): N/A (internal implementation detail)

Test Environment

  • ESP32
  • ESP32 IDF
  • ESP8266
  • RP2040
  • BK72xx
  • RTL87xx
  • nRF52840

Example entry for config.yaml:

# No configuration changes required - this is an internal optimization
bluetooth_proxy:
  active: true

Checklist:

  • The code change is tested and works locally.
  • Tests have been added to verify that the new code works (under tests/ folder).

If user exposed functionality or configuration variables are added/changed:

Additional Notes:

  • This change maintains full backward compatibility - the protobuf wire format is unchanged
  • Fixed arrays are only used for SOURCE_SERVER messages where we control the data
  • The optimization includes loop unrolling for arrays of size 1-2 for better performance
  • No user-facing changes; this is purely an internal memory optimization

@github-actions
Copy link
Copy Markdown
Contributor

To use the changes from this PR as an external component, add the following to your ESPHome configuration YAML file:

external_components:
  - source: github://pr#9782
    components: [api, bluetooth_proxy]
    refresh: 1h

(Added by the PR bot)

@codecov-commenter
codecov-commenter commented Jul 21, 2025
Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 59.96%. Comparing base (5343a6d) to head (37d24dd).
Report is 2 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #9782      +/-   ##
==========================================
- Coverage   59.97%   59.96%   -0.01%     
==========================================
  Files          51       51              
  Lines       10310    10333      +23     
  Branches     1382     1387       +5     
==========================================
+ Hits         6183     6196      +13     
- Misses       3768     3774       +6     
- Partials      359      363       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@bdraco
bdraco commented Jul 21, 2025
Copy link
8000 Copy Markdown
Member Author

All works good on all my proxies. Now I need to port it to aioesphomeapi so its in sync

bdraco added a commit to esphome/aioesphomeapi that referenced this pull request Jul 21, 2025
bdraco added a commit to esphome/aioesphomeapi that referenced this pull request Jul 21, 2025
@bdraco
bdraco marked this pull request as ready for review July 21, 2025 23:58
Copilot AI review requested due to automatic review settings July 21, 2025 23:58
@github-actions
Copy link
Copy Markdown
Contributor

👋 Hi there! I've automatically requested reviews from codeowners based on the files changed in this PR.

@OttoWinter, @jesserockz - You've been requested to review this PR as codeowner(s) of 4 file(s) that were modified. Thanks for your time! 🙏

Copilot AI left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements a performance optimization for Bluetooth proxy functionality by introducing fixed-size arrays for protobuf messages, specifically targeting Bluetooth UUIDs and service responses to reduce memory allocations during service discovery.

  • Extended the protobuf code generator to support fixed_array_size option for repeated fields, creating std::array instead of std::vector
  • Converted Bluetooth UUID fields from dynamic vectors to fixed 2-element arrays and service responses to 1-element arrays
  • Added validation to restrict fixed arrays to encode-only (SOURCE_SERVER) messages with optimized code generation for small arrays

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
script/api_protobuf/api_protobuf.py Adds FixedArrayRepeatedType class and validation logic for fixed-size array support
esphome/components/bluetooth_proxy/bluetooth_connection.cpp Refactors UUID handling to use direct array filling instead of vector operations
esphome/components/api/api_pb2.h Updates protobuf message declarations to use std::array for UUIDs and services
esphome/components/api/api_pb2.cpp Updates generated encode/calculate_size methods to use unrolled array access
esphome/components/api/api.proto Adds fixed_array_size annotations to UUID and service fields

Comment thread script/api_protobuf/api_protobuf.py
Comment thread script/api_protobuf/api_protobuf.py
Comment thread esphome/components/api/api_pb2.cpp
Comment thread esphome/components/api/api_pb2.cpp
Comment thread esphome/components/api/api_pb2.cpp
Comment thread esphome/components/api/api_pb2.cpp
Comment thread esphome/components/api/api_pb2.cpp
Comment thread esphome/components/api/api_pb2.cpp
Comment thread esphome/components/api/api_pb2.cpp
@jesserockz
jesserockz merged commit ac08fb3 into dev Jul 22, 2025
32 checks passed
@jesserockz
jesserockz deleted the fixed_arrays branch July 22, 2025 09:50
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 24, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

0