ベンチマーク結果
すべてのベンチマークは、E2E暗号化(AES-128-GCM)を有効にしたbleRPCファームウェアを実行するnRF54L15 DKペリフェラルに対して実施されました。MTUは247バイトで合意形成されています。いずれのCentralもコネクションインターバルは15msで合意形成されました。
スループット比較
Python (macOS)
CI: 15ms
iOS (iPhone 16)
CI: 15ms
Android (Pixel 5)
CI: 15ms
Web (Chrome, macOS)
CI: 15ms
プラットフォーム別詳細結果
Python Central (macOS, bleak)
コネクションインターバル: 15ms(macOSによる合意形成) — テストコード
| ベンチマーク | 結果 | 詳細 |
|---|---|---|
| flash_read_throughput | 56.6 KB/s | 10x 8192バイト、141.3 ms/call |
| flash_read_overhead | 30.1 ms/call | 1バイト x 20回 |
| echo_roundtrip | 30.0 ms/call | 50回 |
| data_write_throughput | 6.5 KB/s | 200バイト x 20回、30.1 ms/call |
| counter_stream (P→C) | 3.3 ms/item | 20アイテム、66 ms |
| counter_upload (C→P) | 2.9 ms/item | 20アイテム、59 ms |
| 機能テスト | 結果 | 詳細 |
|---|---|---|
| echo_basic | PASS | |
| echo_empty | PASS | |
| echo_max_length | PASS | 256文字 |
| flash_read_basic | PASS | 16バイト |
| flash_read_8kb | PASS | 8192バイト |
| data_write_basic | PASS | 1024バイト |
| data_write_8kb | PASS | 8192バイト |
| multi_container_echo | PASS | 250文字 |
| counter_stream | PASS | 5アイテム |
| counter_stream_large | PASS | 20アイテム |
| counter_upload | PASS | 5アイテム |
| counter_upload_large | PASS | 20アイテム |
iOS Central (iPhone 16, CoreBluetooth)
コネクションインターバル: 15ms(iOSによる合意形成) — テストコード
| ベンチマーク | 結果 | 詳細 |
|---|---|---|
| flash_read_throughput | 55.5 KB/s | 10x 8192バイト、144.1 ms/call |
| flash_read_overhead | 30.0 ms/call | 1バイト x 20回 |
| echo_roundtrip | 30.6 ms/call | 50回 |
| data_write_throughput | 6.4 KB/s | 200バイト x 20回、30.6 ms/call |
| counter_stream (P→C) | 3.1 ms/item | 20アイテム、62 ms |
| counter_upload (C→P) | 3.8 ms/item | 20アイテム、75 ms |
| 機能テスト | 結果 | 詳細 |
|---|---|---|
| echo_basic | PASS | |
| echo_empty | PASS | |
| flash_read_basic | PASS | 64バイト |
| flash_read_8kb | PASS | 8192バイト |
| data_write | PASS | 64バイト |
| counter_stream | PASS | 5アイテム |
| counter_upload | PASS | 5アイテム |
Android Central (Pixel 5)
コネクションインターバル: 15ms(Androidによる合意形成) — テストコード
| ベンチマーク | 結果 | 詳細 |
|---|---|---|
| flash_read_throughput | 83.5 KB/s | 10x 8192バイト、95.8 ms/call |
| flash_read_overhead | 38.4 ms/call | 1バイト x 20回 |
| echo_roundtrip | 38.2 ms/call | 50回 |
| data_write_throughput | 4.8 KB/s | 200バイト x 20回、40.7 ms/call |
| counter_stream (P→C) | 2.8 ms/item | 20アイテム、55 ms |
| counter_upload (C→P) | 5.9 ms/item | 20アイテム、118 ms |
| 機能テスト | 結果 | 詳細 |
|---|---|---|
| echo_basic | PASS | |
| echo_empty | PASS | |
| flash_read_basic | PASS | 64バイト |
| flash_read_8kb | PASS | 8192バイト |
| data_write | PASS | 64バイト |
| counter_stream | PASS | 5アイテム |
| counter_upload | PASS | 5アイテム |
Web Central (Chrome, macOS, Web Bluetooth)
コネクションインターバル: 15ms(macOSによる合意形成) — テストコード
| ベンチマーク | 結果 | 詳細 |
|---|---|---|
| flash_read_throughput | 57.4 KB/s | 10x 8192バイト、139.3 ms/call |
| flash_read_overhead | 30.0 ms/call | 1バイト x 20回 |
| echo_roundtrip | 30.0 ms/call | 50回 |
| data_write_throughput | 6.5 KB/s | 200バイト x 20回、30.0 ms/call |
| counter_stream (P→C) | 3.1 ms/item | 20アイテム、61 ms |
| counter_upload (C→P) | 2.8 ms/item | 20アイテム、56 ms |
central_web デモ(Chrome、暗号化、MTU 247)で計測。トランスポート非依存のプロトコル層(@blerpc/protocol-ts)がブラウザでもそのまま動作するため、Python(macOS)セントラルとほぼ同等の結果になります。
パフォーマンスに関する注記
コネクションインターバルの影響
コネクションインターバル(CI)は、ラウンドトリップレイテンシの主要な要因です。1回のリクエスト・レスポンスサイクルには2コネクションイベント(Centralによるリクエスト書き込みと、ペリフェラルからの通知)を要します。ファームウェアは推奨インターバルを15msに固定しており(PREF_MIN_INT = PREF_MAX_INT = 12)、検証したすべてのCentralがこれを受け入れます:
- macOS (bleak): CI = 15ms → 30.0msのラウンドトリップ
- iOS (iPhone 16): CI = 15ms → 30.6msのラウンドトリップ
- Android (Pixel 5): CI = 15ms → 38.2msのラウンドトリップ。ただし、コネクションイベントあたりのパケット数が多いため、最高のスループットを実現
- Web (Chrome, macOS): CI = 15ms → 30.0msのラウンドトリップ(Pythonと同一のトランスポート・プロトコル層)
コストがかかるのは範囲で要求した場合です。以前の15〜30msの範囲(PREF_MAX_INT=24)では、どのCentralも省電力側の端である30msを選び、ラウンドトリップは約60msと倍になっていました。この30msはOS側の下限ではなく、ペリフェラル自身の要求が原因でした。問題にならなかった点が2つあります。AndroidでrequestConnectionPriority(CONNECTION_PRIORITY_HIGH)を呼ぶ必要はありません(アプリの接続優先度設定に関わらず、ペリフェラル側のパラメータ更新要求が受け入れられます)。またiPhoneでは、AppleのQA1931が警告する「15msの要求を30msにスケールし直す」挙動は発生しませんでした。トレードオフは消費電力です。
再現する場合の注意: ペリフェラルがパラメータ更新を要求するのは接続からCONFIG_BT_CONN_PARAM_UPDATE_TIMEOUT(5秒)後で、それまでのCIはCentral側の初期値(macOS・iOSは30ms、Pixel 5は45ms)です。上記のベンチマークはいずれも接続後5.5秒待ってから計測しており、Centralの初期値ではなく合意形成後のCIを測っています。
暗号化のオーバーヘッド
E2E暗号化はトランザクションあたり20バイトのオーバーヘッドを追加します(4バイトのカウンター + 16バイトのAES-GCMタグ)。大きなペイロード(8 KB)の場合、このオーバーヘッドは無視できる程度です(0.3%未満)。AES-128-GCMの暗号化/復号自体は、最新のモバイルデバイスではハードウェアアクセラレーションされ、8 KBのペイロードでも1ms未満で完了
スループット最適化
- nanopb FT_CALLBACK: フラッシュデータをprotobufエンコーディングに直接ストリーミングし、4 KBの静的RAMを節約
- ゼロコピーレスポンス: Protobufレスポンスをコンテナヘッダーオフセットに直接エンコード
- パケット間遅延なし: コンテナは連続して送信
- flash readは最大8KB: レイテンシとスループットの最適なバランス