Skip to main content

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
info

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

MethodDescription
.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:

  1. Batch multiple samples into a single network packet
  2. Defer transmission to coalesce with other pending writes
  3. 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 BudgetReader BudgetMatch?
0ms0msYes
0ms100msYes
100ms0msYes
100ms200msYes

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 BudgetReliabilityBehavior
0msreliable()Immediate send + ACK/NACK overhead
100msreliable()May batch, but retransmission still applies
0msbest_effort()Immediate fire-and-forget
100msbest_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:

PriorityBudgetNet Effect
High0msImmediate send, preferential network handling
High100msMay batch, but packets get priority when sent
Low0msImmediate send, but lower network priority

Common Pitfalls

  1. Treating it as a guarantee: Latency Budget is advisory. The middleware may not honor it exactly, especially under load.

  2. 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.

  3. Conflicting with Deadline: If Deadline is 100ms and Latency Budget is 200ms, the middleware might delay past the deadline. Ensure latency_budget < deadline when both are used.

  4. 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