Skip to content

Unexpected NimBLE GATT performance compared to Bluedroid (IDFGH-11677) #12789

@Scottapotamas

Description

@Scottapotamas

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

General issue report

I've been working on a series of latency benchmarks for different wireless radios/stacks, and measured some odd behaviours from NimBLE when compared to Bluedroid for GATT/SPP style transfers.


These measurements are for one-way transfer latency - no ack/response behaviour is implemented or measured.

esp32-spp-results

esp32-ble-results

esp32-nimble-results

Is this behaviour reasonable/expected for the NimBLE + ESP32 stack? Any suggestions?


Comparing server notify and client WriteNoResp is also inconsistent between Bluedroid and NimBLE:

esp32-ble-server-client-directionality

esp32-nimble-server-client-directionality


Reproduction Notes

Software

Code for esp32-spp (classic), esp32-ble, esp32-nimble is on GitHub. These vary between minor changes from Espressif examples to heavier modifications to achieve feature parity.

The biggest difference from IDF examples: I've removed UART bridge behaviour, test payloads are handled directly on device.

Where test payloads exceed MTU, I manually send them as smaller MTU sized packets where the benchmark task requires some kind of library level event to signal the next packet i.e. BLE_GAP_EVENT_NOTIFY_TX, similar to the approach used in Espressif throughput example.

I originally ran these tests with IDF 5.1.1 but can reproduce them with latest v5.3-dev-892-g692c1fcc52 which is ~3 days old.

docker run -i --privileged --rm -v $PWD:/project -w /project -it espressif/idf:latest

Other relevant changes with menuconfig:

  • Change NimBLE internal logging to "Warning" to suppress extra terminal output (which affects results).
  • Change compiler options to build for performance -O2

Test Setup

IMG_4191

  • Two ESP32-WROOM-32 devkit boards, positioned on table 1m apart.
  • Signal generator provides a 3.3V 50 μs square pulse at configurable interval (250 ms for all tests) as stimulus signal. Connected to IO19, handled via GPIO ISR.
  • When trigger is flagged, and BT connection is already established, send test payload
  • Receiving board rx event occurs, payload data is sent to user's benchmark task via FreeRTOS queue.
  • Benchmark task checks payload for length and CRC, if valid, drives IO18 high to signal valid transmission.
  • Saleae Logic 8 captures trigger and complete signals at 100 MS/s (10 ns resolution).

I've measured trigger-to-output overhead at ~4.11 μs when tested in a loopback configuration.

All firmware variants support both server notify and client writes, so swapping the trigger/valid signal connections allows testing client-server direction as needed.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions