All benchmarks run on FreeBSD with Tsung load generator. No TLS overhead (benchmarks measure pure protocol performance).
Message Latency#
50 users, 10 messages each, measured end-to-end (client send → server route → client receive).
| Scenario | Workers | Users | Messages | Avg Latency |
|---|---|---|---|---|
| 1:1 Chat | 1 | 50 | 495 | 0.33ms |
| 1:1 Chat | 4 | 50 | 500 | 0.35ms |
| 1:1 Chat | 16 | 50 | 500 | 0.36ms |
| MUC | 1 | 48 | 240 | 0.35ms |
| MUC | 4 | 49 | 245 | 0.31ms |
| MUC | 16 | 47 | 223 | 0.30ms |
| Combo (1:1 + MUC) | 4 | 50 | 413 | 0.37ms |
Key Takeaways#
- Sub-millisecond latency across all configurations
- Adding workers has negligible impact on latency (no contention penalty)
- MUC fan-out is slightly faster with more workers (parallel delivery)
- Zero-copy stanza routing — no serialization between internal components
Throughput#
100 users, aggressive timing (0.05s think time per message).
| Workers | Messages | Peak Rate | Avg Throughput |
|---|---|---|---|
| 1 | 10,000 | 510 msg/s | 476 msg/s |
| 4 | 6,945 | 480 msg/s | 408 msg/s |
Throughput is bottlenecked by Tsung (Erlang overhead + think time), not xmppd. The server CPU remains below 5% during all tests.
Memory Usage#
| Component | Per-Session | Notes |
|---|---|---|
| Session buffers | ~60KB | Read + write + XML state |
| MPSC delivery slot | 4KB | Cross-thread stanza delivery |
| MUC occupant | ~1KB | Nick + JID + role + affiliation |
| SessionMap entry | ~200B | JID string + metadata |
With max_sessions = 4096 (default), expect ~240MB for session buffers plus
storage backend memory.
Binary Size#
| Binary | Size (stripped) |
|---|---|
| xmppd | ~1.8MB |
| xmppd-core | ~4.5MB |
| xmppd-auth | ~2.1MB |
| xmppd-auth-oidc | ~4.3MB |
| xmppd-s2s | ~3.8MB |
| xmppctl | ~1.9MB |
All binaries are statically linked Zig executables. Only OpenSSL is dynamically linked at runtime.