Latency Budget QoS Policy
The Latency Budget policy provides a hint to the DDS middleware about the maximum acceptable delay from the time data is written to when it is received by the reader.
Purpose
Latency Budget allows the middleware to optimize delivery:
- Budget = 0: Deliver immediately, no batching
- Budget > 0: The middleware may batch or defer delivery up to the specified duration for efficiency
- Hint only: The middleware is not required to enforce the budget; it is advisory
Latency Budget is a hint, not a guarantee. The middleware uses it to decide whether to batch messages, flush buffers immediately, or apply other transport-level optimizations. It does not affect QoS compatibility between writers and readers.
Configuration
use hdds::{Participant, QoS, TransportMode};
let participant = Participant::builder("control_app")
.domain_id(0)
.with_transport(TransportMode::UdpMulticast)
.build()?;
// Critical control data: deliver immediately (budget = 0ms)
let writer = participant
.topic::<ControlData>("control/commands")?
.writer()
.qos(QoS::reliable().latency_budget_millis(0))
.build()?;
// Analytics data: batching allowed (budget = 100ms)
let batch_writer = participant
.topic::<AnalyticsData>("analytics/metrics")?
.writer()
.qos(QoS::reliable().latency_budget_millis(100))
.build()?;
#include <hdds.h>
/* Critical data: zero latency budget (deliver immediately) */
struct HddsQoS* qos_rt = hdds_qos_reliable();
hdds_qos_set_latency_budget_ns(qos_rt, 0ULL);
struct HddsDataWriter* writer_rt = hdds_writer_create_with_qos(
participant, "control/commands", qos_rt);
hdds_qos_destroy(qos_rt);
/* Batched data: 100ms latency budget */
struct HddsQoS* qos_batch = hdds_qos_reliable();
hdds_qos_set_latency_budget_ns(qos_batch, 100000000ULL); /* 100ms */
struct HddsDataWriter* writer_batch = hdds_writer_create_with_qos(
participant, "analytics/metrics", qos_batch);
hdds_qos_destroy(qos_batch);
Default Value
Default is zero (no specific latency requirement, deliver as fast as possible):
let qos = QoS::reliable();
// latency_budget = Duration::ZERO (immediate delivery hint)
Fluent Builder Methods
| Method | Description |
|---|---|
.latency_budget_millis(n) | Set latency budget in milliseconds |
.latency_budget_secs(n) | Set latency budget in seconds |
How Latency Budget Affects Delivery
Budget = 0ms (immediate delivery):
Writer: [msg]-----> Middleware -----> Reader
(send now) (instant)
Budget = 100ms (batching allowed):
Writer: [msg1]--+
[msg2]--+--> Middleware ------> Reader
[msg3]--+ (batch up (receives batch
to 100ms) within 100ms)
With a non-zero budget, the middleware can:
- Batch multiple samples into a single network packet
- Defer transmission to coalesce with other pending writes
- Reduce syscalls by writing fewer, larger buffers
Compatibility Rules
Latency Budget does not affect compatibility. Writers and readers always match regardless of their latency budget settings.
| Writer Budget | Reader Budget | Match? |
|---|---|---|
| 0ms | 0ms | Yes |
| 0ms | 100ms | Yes |
| 100ms | 0ms | Yes |
| 100ms | 200ms | Yes |
Use Cases
Real-Time Control vs Analytics
use hdds::{Participant, QoS, TransportMode};
let participant = Participant::builder("mixed_system")
.domain_id(0)
.with_transport(TransportMode::UdpMulticast)
.build()?;
// Control loop: immediate delivery
let control_writer = participant
.topic::<ControlData>("control/commands")?
.writer()
.qos(QoS::reliable().latency_budget_millis(0))
.build()?;
// Diagnostics: batching acceptable
let diag_writer = participant
.topic::<DiagData>("system/diagnostics")?
.writer()
.qos(QoS::best_effort().latency_budget_millis(500))
.build()?;
Emergency Alerts
use hdds::{Participant, QoS, TransportMode};
let participant = Participant::builder("alert_system")
.domain_id(0)
.with_transport(TransportMode::UdpMulticast)
.build()?;
// Emergency: absolute minimum latency
let alert_writer = participant
.topic::<Alert>("system/alerts")?
.writer()
.qos(QoS::reliable().latency_budget_millis(0))
.build()?;
// Status reports: can tolerate delay
let status_writer = participant
.topic::<StatusReport>("system/status")?
.writer()
.qos(QoS::reliable().latency_budget_millis(200))
.build()?;
Bandwidth Optimization
use hdds::{Participant, QoS, TransportMode};
let participant = Participant::builder("bandwidth_demo")
.domain_id(0)
.with_transport(TransportMode::UdpMulticast)
.build()?;
// High-frequency sensor: allow batching for bandwidth efficiency
let writer = participant
.topic::<SensorData>("sensors/temperature")?
.writer()
.qos(QoS::best_effort().keep_last(1).latency_budget_millis(50))
.build()?;
Interaction with Other Policies
Latency Budget + Reliability
| Latency Budget | Reliability | Behavior |
|---|---|---|
| 0ms | reliable() | Immediate send + ACK/NACK overhead |
| 100ms | reliable() | May batch, but retransmission still applies |
| 0ms | best_effort() | Immediate fire-and-forget |
| 100ms | best_effort() | May batch for efficiency |
Latency Budget + Transport Priority
Both are transport-layer hints. Transport Priority affects packet scheduling, while Latency Budget affects send timing:
| Priority | Budget | Net Effect |
|---|---|---|
| High | 0ms | Immediate send, preferential network handling |
| High | 100ms | May batch, but packets get priority when sent |
| Low | 0ms | Immediate send, but lower network priority |
Common Pitfalls
-
Treating it as a guarantee: Latency Budget is advisory. The middleware may not honor it exactly, especially under load.
-
Setting budget on readers only: The budget is most effective on the writer side where batching decisions are made. Setting it on readers indicates the acceptable delivery window.
-
Conflicting with Deadline: If Deadline is 100ms and Latency Budget is 200ms, the middleware might delay past the deadline. Ensure
latency_budget < deadlinewhen both are used. -
Zero budget overhead: A zero-budget hint forces the middleware to flush immediately on each write, which increases syscall frequency. For high-rate publishers, a small non-zero budget can significantly improve throughput.
Performance Notes
- Zero budget: lowest latency, highest syscall overhead
- Non-zero budget: higher latency, better throughput via batching
- The optimal budget depends on your publish rate and latency requirements
- Typical values: 0ms for control, 10-100ms for telemetry, 500ms+ for logs
Next Steps
- Transport Priority - Network priority levels
- Deadline - Periodic update requirements
- Overview - All QoS policies