# BitChat Performance Characteristics: Benchmarks, Throughput Metrics, and Architectural Optimizations

> Explore BitChat performance benchmarks achieving 11000 BLE packets/sec and 2000 Nostr events/sec. Discover architectural optimizations for high throughput and low latency.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: performance
- Published: 2026-08-01

---

**BitChat achieves sustained throughputs of 11,000 BLE packets/sec for local mesh communication and 2,000 Nostr events/sec for global relay processing, with sub-millisecond latency for deduplication and filter operations.**

The BitChat message routing system, maintained in `permissionlesstech/bitchat`, is engineered for high-throughput, low-latency communication across dual transport layers. Its performance characteristics emerge from a combination of zero-copy binary protocols, adaptive battery management, and carefully optimized data structures that minimize CPU and memory overhead on mobile devices.

---

## Core Performance Goals and Design Philosophy

BitChat operates simultaneously on two network layers with distinct performance requirements:

- **Bluetooth LE mesh** for local, offline-capable communication with tight latency budgets
- **Nostr protocol** for global, censorship-resistant message relay

The architecture prioritizes **fast local communication** through a binary protocol that avoids memory copies wherever possible. In [`localPackages/BitFoundation/Sources/BitFoundation/BinaryProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/BinaryProtocol.swift), the `BinaryProtocol` implementation uses Swift `Data` views to encode and decode packets without allocating new buffers.

Battery efficiency is equally critical. **Adaptive battery modes** dynamically throttle BLE scanning and transmission when devices are idle, extending operational time without sacrificing responsiveness when active.

---

## Performance Baseline Benchmarks

The `PerformanceBaselineTests` suite in [`bitchatTests/Performance/PerformanceBaselineTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/Performance/PerformanceBaselineTests.swift) establishes quantitative throughput floors for every critical code path. These benchmarks run in CI and enforce performance regressions via [`scripts/check-perf-floors.sh`](https://github.com/permissionlesstech/bitchat/blob/main/scripts/check-perf-floors.sh).

### Nostr Inbound Processing

| Benchmark | Path | Throughput |
|-----------|------|------------|
| **Nostr inbound (fresh events)** | Full processing: deduplication, geo-hash validation, scheduling | **~2,000 events/sec** |
| **Nostr inbound (duplicate events)** | Fast-path deduplication without cryptographic operations | **~30,000 events/sec** |

The 15x throughput differential between fresh and duplicate events highlights the cost of cryptographic validation and state management versus the O(1) deduplication check. The `MessageDeduplicator` stores compact 64-bit keys enabling constant-time duplicate detection.

### BLE Mesh Communication

| Benchmark | Operation | Throughput |
|-----------|-----------|------------|
| **BLE inbound packet pipeline** | Decode + deduplication of 100-300 byte packets | **~11,000 packets/sec** |

This measurement covers the complete path from raw `Data` through `BitchatPacket.from(_:)` to deduplication key generation. The zero-copy binary protocol eliminates buffer allocations that would otherwise dominate latency.

### Data Structure Operations

| Benchmark | What It Measures | Throughput |
|-----------|------------------|------------|
| **GCS filter build & decode** | Golomb-Coded Set construction and parsing for 1,000 packet IDs | **~140 filters/sec** |
| **Delivery status (coordinator)** | Incremental updates through `DeliveryStatusCoordinator` | **~9,000 updates/sec** |
| **Delivery status (store direct)** | Direct `ConversationStore` updates | **~13,000 updates/sec** |

The coordinator overhead reduces throughput by approximately 30%, reflecting the cost of cross-component synchronization versus direct store access.

### Message Processing Pipelines

| Benchmark | Scope | Throughput |
|-----------|-------|------------|
| **Message formatting** | 200 messages with mentions, hashtags, URL detection | **~1,000 messages/sec** |
| **Private ingest pipeline** | Full `ChatViewModel` path for private messages | **~1,000 messages/sec** |
| **Public ingest pipeline** | Full path with 50 distinct senders | **~900 messages/sec** |

Public message processing incurs slightly higher overhead due to sender validation and provenance tracking across multiple identities.

### ConversationStore Performance

| Benchmark | Scenario | Throughput |
|-----------|----------|------------|
| **ConversationStore append** | 1,000 out-of-order inserts with ordering maintenance | **~5,000 messages/sec** |
| **Steady-state append** | Append under 1,337-message retention cap with eviction | **~12,000 messages/sec** |
| **ConversationStore audit** | Invariant validation over 5,000-message corpus | **~80 audits/sec** |

The 2.4x throughput increase in steady-state operation reflects streamlined eviction paths versus the binary search and insertion overhead of out-of-order appends.

---

## Architectural Optimizations

### Zero-Copy Binary Protocol

The `BinaryProtocol` implementation at `BinaryProtocol.swift#L84-L86` uses `Data.subdata(in:)` and `withUnsafeBytes` to parse packet fields without copying underlying bytes. This eliminates heap allocation pressure during high-frequency BLE operations.

### LZ4 Compression

Outgoing BLE payloads undergo **LZ4 compression**, reducing transmission time and radio-on duration. The compression ratio typically achieves 2-3x reduction for text-heavy messages, directly improving battery life.

### Noise Protocol Encryption

Mesh encryption uses the **Noise protocol** via `NoiseEncryptionService.swift#L78`, providing forward secrecy with minimal overhead. The handshake completes in single round-trip with small message expansion, unlike TLS which would require multiple exchanges and certificate overhead.

### Golomb-Coded Set Filters

**GCS filters** enable bandwidth-efficient state synchronization between mesh nodes. Each filter represents 1,000 packet IDs in ~150 bytes, allowing nodes to identify missing messages with sub-millisecond set operations rather than transmitting full inventories.

### Single-Source-of-Truth Store

All message state converges on `ConversationStore`, eliminating redundant indices. Ordered insertion uses binary search on a sorted array rather than tree structures, optimizing for cache locality and Swift's copy-on-write semantics.

### Adaptive Battery Management

BLE scan intervals scale from continuous (active conversation) to 10-second windows (idle), reducing radio power consumption by up to 90% during quiescent periods without breaking mesh connectivity.

---

## Running and Interpreting Benchmarks

### Execute Performance Tests Locally

```bash

# Run complete suite including performance baselines

swift test

# Skip performance tests for faster iteration

BITCHAT_SKIP_PERF_BASELINES=1 swift test

# Capture structured performance output

BITCHAT_PERF_LOG=perf.log swift test --quiet --filter PerformanceBaselineTests

```

The `BITCHAT_PERF_LOG` environment variable triggers formatted output parsing by [`scripts/check-perf-floors.sh`](https://github.com/permissionlesstech/bitchat/blob/main/scripts/check-perf-floors.sh).

### Parse Benchmark Output

```bash
cat perf.log | grep "PERF\[store.append\]"

# Output: PERF[store.append]: 5400 messages/sec (avg 0.185 ms per pass of 1000, 5 passes)

```

Interpretation:
- **Operations per pass**: 1,000 `append` calls
- **Average latency**: 0.185 ms per operation
- **Sustainable throughput**: 5,400 operations/second

### Direct Store Usage Pattern

```swift
import BitFoundation

let store = ConversationStore()
let message = BitchatMessage(
    id: "msg-\(UUID().uuidString.prefix(8))",
    sender: "alice",
    content: "Zero-copy mesh message",
    timestamp: Date(),
    isRelay: false
)

// O(log n) ordered insert with binary search positioning
store.append(message, to: .mesh)

```

This pattern mirrors the benchmarked path in `testConversationStoreAppend` at `PerformanceBaselineTests.swift#L268-L304`.

### BLE Packet Processing Micro-Benchmark

```swift
import XCTest
@testable import bitchat

func measureBLEThroughput() {
    let deduplicator = MessageDeduplicator()
    let packets = (0..<1000).map { _ in generateRandomPacket() }
    
    let start = Date()
    for packet in packets {
        guard let data = packet.toBinaryData(),
              let decoded = BitchatPacket.from(data) else { continue }
        
        let key = dedupKey(packet: decoded)
        _ = deduplicator.isDuplicate(key: key)
    }
    let elapsed = Date().timeIntervalSince(start)
    
    print("Throughput: \(Double(packets.count) / elapsed) packets/sec")
}

```

This replicates the core measurement from `testBLEInboundPacketPipeline` at `PerformanceBaselineTests.swift#L38-L44`.

---

## Key Source Files

| File | Purpose |
|------|---------|
| [`bitchatTests/Performance/PerformanceBaselineTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/Performance/PerformanceBaselineTests.swift) | Complete benchmark suite with throughput floors |
| [`localPackages/BitFoundation/Sources/BitFoundation/BinaryProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/BinaryProtocol.swift) | Zero-copy binary encoding/decoding |
| [`bitchat/Services/NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/NoiseEncryptionService.swift) | Noise protocol mesh encryption |
| [`bitchat/ViewModels/ChatViewModel.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/ViewModels/ChatViewModel.swift) | Message ingest pipeline orchestration |
| [`scripts/check-perf-floors.sh`](https://github.com/permissionlesstech/bitchat/blob/main/scripts/check-perf-floors.sh) | CI validation of benchmark regressions |
| [`README.md`](https://github.com/permissionlesstech/bitchat/blob/main/README.md) | High-level architecture and feature overview |

---

## Summary

- **BitChat achieves 11,000 BLE packets/sec** for local mesh deduplication and decoding via zero-copy binary protocols
- **Nostr processing reaches 2,000 fresh events/sec** (30,000/sec for duplicates) through optimized deduplication paths
- **ConversationStore sustains 5,000-12,000 appends/sec** depending on ordering constraints and retention policies
- **LZ4 compression, Noise protocol encryption, and GCS filters** collectively minimize bandwidth, latency, and battery consumption
- **Adaptive battery modes** dynamically balance responsiveness against power efficiency
- **All performance claims are enforced in CI** via `PerformanceBaselineTests` and [`check-perf-floors.sh`](https://github.com/permissionlesstech/bitchat/blob/main/check-perf-floors.sh)

---

## Frequently Asked Questions

### What throughput can I expect for BLE mesh messaging?

Expect approximately **11,000 packets per second** for packet decoding and deduplication on modern hardware. This covers the complete path from raw `Data` through `BitchatPacket.from(_:)` to duplicate detection. Real-world mobile performance is lower due to radio scheduling and OS constraints, but remains well within interactive latency budgets.

### How does BitChat handle duplicate messages efficiently?

The `MessageDeduplicator` class provides **O(1) duplicate detection** using compact 64-bit keys stored in a hash set. Duplicate events bypass expensive cryptographic validation entirely, achieving **30,000 events/sec** versus 2,000/sec for fresh events that require full processing.

### Why is steady-state append faster than initial append in ConversationStore?

Steady-state append (12,000 messages/sec) operates under a fixed 1,337-message retention cap with streamlined eviction logic. Initial append (5,000 messages/sec) handles out-of-order inserts requiring binary search positioning and array expansion. The steady-state path avoids these ordering overheads.

### How do I run performance benchmarks in my own environment?

Set `BITCHAT_PERF_LOG=perf.log` and execute `swift test --filter PerformanceBaselineTests`. The output includes formatted throughput lines like `PERF[category.metric]: X ops/sec` that [`scripts/check-perf-floors.sh`](https://github.com/permissionlesstech/bitchat/blob/main/scripts/check-perf-floors.sh) can validate against expected floors defined in the test source.