Performance & Interoperabilität

Performance & Interoperabilität

Ausschließlich unsere eigenen Messwerte, mit der Methodik dahinter — damit jede Zahl einzuordnen ist. Keine Marketing-Grafiken, keine extrapolierten Vergleiche: gemessen wird auf denselben Hosts, mit denselben Tools, gegen die etablierten DDS-Implementierungen.

Alle Latenz-Zahlen sind Roundtrips (Request → Response, halbiert ergibt sich die One-Way-Latenz nicht — wir berichten den vollen Roundtrip). Perzentile statt Mittelwert, weil bei Echtzeit-Systemen der Schwanz zählt. Wo nicht anders genannt: voller DCPS-Pfad (Discovery + RTPS + Reader/Writer-Matching), RELIABLE, KEEP_LAST(64), UDPv4 über Loopback, vanilla Linux ohne RT-Tuning — also der konservative Fall, nicht das getunte Schaufenster.

Roundtrip-Latenz im Vergleich von sechs Stacks

Selber Host, selbe Pipeline für alle sechs Stacks — jeder mit seinem eigenen Code-Generator und seiner nativen DCPS-API. Selbstpaar (Ping und Pong derselbe Stack), n=2000, RELIABLE, bester von fünf Runs, jedes Paar über UDPv4. Stand 02.10.2026.

Stackp50p90p99p99.9maxp50 8 KBTransport
Cyclone DDS25.133.347.063.179.936.6UDPv4
RTI Connext30.136.245.269.099.737.3UDPv4
ZeroDDS32.635.846.856.460.041.9UDPv4
Fast DDS41.455.472.088.689.842.4UDPv4
OpenSplice CE68.177.197.3121145117UDPv4, XCDR1
OpenDDS200311351445479317UDPv4

Values in µs. p50 = median. 0-Byte-Payload bis auf die Spalte „p50 8 KB“ (8192 Byte). Host: Linux-Container (LXC, AMD Threadripper PRO, 16 Threads), vanilla (kein PREEMPT_RT, kein CPU-Pinning). ZeroDDS läuft mit transport.same_host_shm=false: auch sein Selbstpaar geht über UDPv4 und nicht über ZeroDDS' Shared-Memory-Träger.

Cross-Vendor-Interop

Volle 6×6-Roundtrip-Matrix: jeder Stack als Pinger gegen jeden als Ponger, echte Wire-Interop (Discovery + RTPS + QoS-Matching), nicht nur Discovery-Sichtbarkeit.

Ping ↓ / Pong →ZeroDDSCycloneFast DDSRTIOpenDDSOpenSpliceScore
ZeroDDS3336343776606/6 ✅
Cyclone3425403271446/6 ✅
Fast DDS33444139188606/6 ✅
RTI31263530—·4/5
OpenDDS6676130—200—4/6
OpenSplice494760·—684/5

p50 µs, 0-Byte-Payload. 30 von 34 gemessenen Zellen grün; ZeroDDS matcht mit allen fünf anderen Stacks in beiden Richtungen. — = kein Match: RTI ↔ OpenDDS (OpenDDS zählt die Type-Consistency-Stufen ab 1 statt ab 0, liest RTIs ALLOW_TYPE_COERCION als DISALLOW_TYPE_COERCION und verlangt dann gleiche Minimal-Typ-Hashes, die RTI und OpenDDS verschieden bilden) und OpenDDS ↔ OpenSplice (OpenDDS verbindet einen Endpunkt erst, wenn dessen Teilnehmer die SEDP-Ankündigung bestätigt hat; bei OpenSplice tut das ein anderer Teilnehmer derselben Federation). · = mit unserer RTI-Lizenz nicht messbar: sie lässt höchstens 12 DataReader und 12 DataWriter zu, und OpenSplice kündigt mehr eigene an (RTI ↔ OpenSplice). Paare mit OpenSplice laufen in XCDR1, alle anderen in XCDR2.

ROS 2: rmw_zerodds ↔ rmw_cyclonedds Talker/Listener bidirektional 20/20 grün. Live-SPDP-Discovery erkennt Cyclone und Fast-DDS auf demselben Subnetz.

DDS-Security (Cross-Vendor, verschlüsselt)

Roundtrip mit eingeschaltetem data_protection=ENCRYPT (AES-GCM auf User-Payload), 64-Byte-Payload. Interessant ist der Crypto-Aufschlag relativ zur eigenen Plain-Baseline.

StackPlain p50Encrypted p50Overhead
ZeroDDS2565+40 µs absolut, sauberste Kurve
Cyclone3644+22 %
Fast-DDS58109+88 %
OpenDDS~90132+47 %

Cross-Vendor verschlüsselt: ZeroDDS matcht in beiden Richtungen über das volle 13-Profil-Governance-Spektrum — 13/13 mit Cyclone, 13/13 mit Fast-DDS, 9/13 mit OpenDDS (das ZeroDDS-Maximum; die vier Lücken sind OpenDDS-Spec-Grenzen, kein ZeroDDS-Bug). Die roten Zellen der Vollmatrix sind ausschließlich Fremd↔Fremd-Paare (Vendor-Löcher zwischen den anderen Stacks). Das ist echte 4-Vendor-DDS-Security-Interop auf User-Payload-Crypto-Ebene.

Rich-Typed XCDR2 — Member-Codec unter Last

Statt opaker Bytes ein maximal verschachtelter Typ: string<64>, double transform[16], sequence<Waypoint,32> (je 2 verschachtelte Vec3 + String + Skalare, 8 Waypoints/Sample). Das isoliert die XCDR2-Member-Codec-Arbeit vom Transport. p50 µs, Payload 64, Ping (Zeile) → Pong (Spalte); ✗ = NO_DATA.

Ping ↓ / Pong →ZeroDDSCycloneFast-DDSRTIOpenDDS
ZeroDDS2041356160
Cyclone627077✗✗
Fast-DDS70916476123
RTI23✗6756✗
OpenDDS103✗79✗226

Values in µs. ZeroDDS interoperiert auf dem rich-Typ mit allen vier anderen Vendoren — neben Fast-DDS der einzige voll-verbundene Stack. Die Codec-Kosten (rich vs. basis) liegen im LXC-Rauschen, daher ist nur das Ranking belastbar, kein absoluter Codec-Vorsprung. Leere Zellen sind ausschließlich Fremd↔Fremd, kein ZeroDDS beteiligt: Cyclone, RTI und OpenDDS bilden für die verschachtelten Structs verschiedene Minimal-Typ-Hashes, und Cyclone wie OpenDDS lehnen die Zuweisbarkeit dann ab.

Verschlüsselt + rich (DDS-Security 1.2 + rich-Typ)

Ping ↓ / Pong →ZeroDDSCycloneFast-DDSOpenDDS
ZeroDDS7393141145
Cyclone90118✗✗
Fast-DDS120✗176✗
OpenDDS143✗✗181

Values in µs; RTI omitted (security licence not purchased). ZeroDDS interoperiert verschlüsselt + rich mit Cyclone, Fast-DDS und OpenDDS in beiden Richtungen, mit EC-P-256-Identitäten. Die Paare zwischen den anderen Stacks kommen nicht zustande (✗: kein Match in fünf Läufen). Security läuft über SRTPS-über-UDP (der SHM-Carrier wird bei aktiver Crypto umgangen). Jede Zelle ist der beste p50 von fünf Läufen; die Lastmittel des geteilten Hosts lagen während der Messung zwischen 4,5 und 12, im Mittel 7.

TSN — RTPS direkt über Ethernet

Roundtrip des Live-AF_PACKET-Transports (DDS-TSN Annex A, RTPS im Ethernet-Frame, EtherType 0x88B5) gegen eine UDP-Baseline über denselben Link.

Transportp50p90p99maxJitter (p99−p50)
TSN / AF_PACKET 0x88B511.9522.4929.5828117.62
UDP (same link)17.1021.0734.9092817.79

µs, 64-Byte-Payload. Der Raw-Ethernet-Pfad liegt unter UDP, weil er den IP/UDP-Stack umgeht.

Wichtig zur Einordnung: das ist eine Host-Pfad-Messung ohne TSN-Switch. Der eigentliche TSN-Vorteil — deterministische, eng begrenzte Latenz unter Last — entsteht im Netz (Time-Aware Shaper / gPTP), nicht im Host-Socket. Diese Zahl belegt nur, dass unser Ethernet-Transport keinen Overhead-Nachteil gegenüber UDP hat.

CORBA (Migrations-Pfad)

Für den CORBA-Koexistenz-Stack: IIOP-Roundtrip über TCP-Loopback gegen die etablierten ORBs, plus bidirektionale Cross-ORB-Interop.

ORBp50 (32 B)Cross-ORB-Interop
ZeroDDS16.3schnellster ORB im Vergleich
omniORB17.9✅
TAO36.7✅
JacORB57.1✅ inkl. Big-Endian-Konvertierung

Alle sechs Client/Server-Kombinationen gegen omniORB, TAO und JacORB sind bidirektional grün (Echo + Bench), einschließlich Byte-Order-Konvertierung.

Microbenchmarks (Hot-Path)

Writer-Dispatch — die reine Sample-Send-Kette über RTPS, Criterion-gemessen. Zero-Copy-Fan-out über Arc<[u8]> (kein Payload-Kopieren beim Fan-out):

PayloadVec (copy)Arc (zero-copy)Δ
64 B390 ns390 ns±0 %
1 KB525 ns489 ns−6.9 %
4 KB959 ns974 ns+1.6 %
16 KB3.18 µs3.09 µs−2.8 %
64 KB11.49 µs11.04 µs−3.9 %

Methodik — wie gemessen wird

Offene Punkte & Grenzen (ehrlich)

Reproduzierbarkeit

Alle Messungen sind reproduzierbar dokumentiert. Wenn du die Zahlen in deiner Umgebung nicht reproduzierst, ist das ein Issue wert. Roh-Daten und Skripte:


Weiter: Features · Hard Truths · Kontakt