ROS 2 can deliver a topic correctly while leaving you unsure whether Fast DDS used UDP, Shared Memory Transport, or Data Sharing. Topic rate alone cannot answer that question.
-
Predict the route: use
ros2 transport list -v --explain. -
Measure UDP or SHM: on Jazzy or Kilted, enable Fast DDS statistics before the nodes start and add
--stats. - Do not equate SHM with zero-copy: Data Sharing and loaned samples must be checked separately.
This workflow uses the open-source fastdds_transport_viz command for Linux systems running rmw_fastrtps_cpp.
Quick Check: Is ROS 2 Using UDP or Shared Memory?
1. Confirm the RMW implementation
Start by checking which ROS middleware implementation the current environment reports:
ros2 doctor --report
Find the RMW MIDDLEWARE section. Continue with this method only when it identifies rmw_fastrtps_cpp.
The RMW_IMPLEMENTATION environment variable is an override, not a complete test. When it is unset, ROS 2 may load its default RMW implementation.
2. Install the transport checker once
Build the tool in a separate workspace. The example uses Jazzy; change the ROS setup path only when you are deliberately testing Humble or Kilted.
mkdir -p ~/fastdds_transport_viz_ws/src cd ~/fastdds_transport_viz_ws git clone -b v1.0.0 https://github.com/atinfinity/fastdds_transport_viz.git src/fastdds_transport_viz source /opt/ros/jazzy/setup.bash rosdep install --from-paths src --ignore-src -y colcon build --symlink-install source install/setup.bash
If this is the first use of rosdep on the machine, run sudo rosdep init once, followed by rosdep update. If initialization already exists, run only the update.
3. Predict the route from discovery
Start the publisher and subscriber. In another terminal with the same domain and discovery settings, filter the check to the topic you care about:
source /opt/ros/jazzy/setup.bash source ~/fastdds_transport_viz_ws/install/setup.bash ros2 transport list -v --explain --topic '^/camera/image_raw$'
The result lists each writer-to-reader pair, its predicted transport, and the reason codes behind the decision. An empty result means discovery must be fixed before transport can be diagnosed.
TOPIC PUBS SUBS TRANSPORT /camera/image_raw 1 1 SHM x1 /camera -> /processor SHM same-host-guid,both-shm-locators
Prediction describes what the discovered locators and QoS imply. It does not prove which path carried the current samples.
4. Measure the route on Jazzy or Kilted
Fast DDS statistics must be enabled before the observed participants are created. Export the variables first, then restart the target publisher and subscriber from that environment.
export FASTDDS_STATISTICS="RTPS_SENT_TOPIC;RTPS_LOST_TOPIC;HISTORY_LATENCY_TOPIC;PHYSICAL_DATA_TOPIC;DATA_COUNT_TOPIC;PUBLICATION_THROUGHPUT_TOPIC;RESENT_DATAS_TOPIC;HEARTBEAT_COUNT_TOPIC;ACKNACK_COUNT_TOPIC;NACKFRAG_COUNT_TOPIC;GAP_COUNT_TOPIC" export FASTRTPS_DEFAULT_PROFILES_FILE="$(ros2 pkg prefix fastdds_transport_viz)/share/fastdds_transport_viz/config/statistics.xml" # Start or restart the publisher and subscriber from this shell. ros2 transport list -v --stats --topic '^/camera/image_raw$'
A pair using Shared Memory Transport can now show measured=SHM. A network path can show measured=UDPv4 or another configured transport.
Read the predicted route, measured route, and reason code for the same writer-reader pair.
Seeing stats-not-enabled-on-writer? Stop the target nodes, export the statistics variables, and start the nodes again. Adding --stats after startup cannot create their statistics writers.
How to Read the Transport Result
The result is useful only when you distinguish a prediction from a measurement. Use the following table before making a performance or zero-copy claim.
| Result | Meaning | What you can claim |
|---|---|---|
| UDPv4 / UDPv6 | Fast DDS uses a network transport for this pair. | The path is IP-based. UDP is expected across physical hosts and in many isolated container layouts. |
| SHM | Fast DDS Shared Memory Transport is available or carried traffic. | The pair uses the local SHM transport. This is not proof of full application zero-copy. |
| DATA_SHARING? | Discovery data suggests that Data Sharing is eligible. | The path is likely, but statistics have not confirmed delivery without transport data. |
| DATA_SHARING | Delivery was observed while the expected transport data packets or DATA submessages were absent. | Fast DDS Data Sharing was confirmed for the tested pair. Application-level loaning still needs separate proof. |
Fast DDS zero-copy combines Data Sharing with sample loans at the writer and reader.
A plain SHM result therefore means Shared Memory Transport, not end-to-end zero-copy. A confirmed DATA_SHARING result proves the DDS delivery path, but not every copy inside your application.
What Works on Humble, Jazzy and Kilted?
| ROS 2 release | Prediction | Measurement with --stats
|
How to report the result |
|---|---|---|---|
| Humble | Supported | Not supported by v1.0.0 | Predicted route only |
| Jazzy | Supported | Supported | Compare predicted and measured transport |
| Kilted | Supported | Supported | Compare predicted and measured transport |
On Humble, stop after the discovery-based check. Do not describe the result as measured traffic. On Jazzy or Kilted, use statistics when the actual path matters.
Why Is ROS 2 Using UDP Instead of SHM?
UDP is not automatically a fault. First compare the result with the deployment topology.
- Two physical hosts: UDP or another configured network transport is expected because the processes cannot share one local memory segment.
- Separate Docker bridge containers: Fast DDS can see different network and IPC contexts, so the participants may communicate over UDP.
- Host networking without shared IPC: the participants may look local but still cannot access the same shared-memory mechanism.
- Custom Fast DDS XML: a profile may disable SHM, restrict locators, or force a different built-in transport.
For Linux containers intended to share SHM, Fast DDS documents both --network=host and --ipc=host. Host networking alone does not provide the shared IPC context.
See the Fast DDS Docker SHM guidance before changing a container layout.
Why Does the Measurement Not Match the Prediction?
Work from the first missing signal instead of changing several DDS settings at once.
| What you see | Likely cause | Next check |
|---|---|---|
| No writer-reader pair | The observer cannot discover the endpoints. | Match ROS_DOMAIN_ID, Discovery Server or static peers, network namespace, and XML settings. |
| Prediction but no measurement | Statistics were unavailable or enabled too late. | Use Jazzy/Kilted, export the variables, and restart the observed nodes. |
shm-not-visible |
The observer and nodes see different shared-memory spaces. | Run the observer in the same IPC namespace and inspect /dev/shm. |
stats-writer-instance-limit-suspected |
The Fast DDS 2.14 statistics writer may have reached its default keyed-instance limit. | Use the shipped statistics.xml, narrow the observation, and restart the participants. |
| One participant pair carries several topics | Fast DDS statistics are participant-level. | Isolate the test topic or separate endpoints before claiming a per-topic measurement. |
If predicted SHM becomes measured UDP, inspect the reason code and the IPC boundary. If predicted UDP becomes measured SHM, check whether the observer and nodes loaded different Fast DDS settings.
How to Verify Data Sharing and Zero Copy
Data Sharing bypasses the normal transport layer. The project includes a bounded-message example and a profile that enables compatible endpoints with the automatic policy.
Use the statistics-enabled example on Jazzy or Kilted:
source /opt/ros/jazzy/setup.bash source ~/fastdds_transport_viz_ws/install/setup.bash export FASTRTPS_DEFAULT_PROFILES_FILE="$(ros2 pkg prefix fastdds_transport_viz)/share/fastdds_transport_viz/config/datasharing_auto_stats.xml" export RMW_FASTRTPS_USE_QOS_FROM_XML=1 export FASTDDS_STATISTICS="RTPS_SENT_TOPIC;RTPS_LOST_TOPIC;HISTORY_LATENCY_TOPIC;PHYSICAL_DATA_TOPIC;DATA_COUNT_TOPIC;PUBLICATION_THROUGHPUT_TOPIC;RESENT_DATAS_TOPIC;HEARTBEAT_COUNT_TOPIC;ACKNACK_COUNT_TOPIC;NACKFRAG_COUNT_TOPIC;GAP_COUNT_TOPIC" ros2 run fastdds_transport_viz bounded_pub & bounded_pub_pid=$! ros2 run fastdds_transport_viz bounded_sub & bounded_sub_pid=$! ros2 transport list -v --stats --topic '^/bounded$' kill "$bounded_pub_pid" "$bounded_sub_pid" wait "$bounded_pub_pid" "$bounded_sub_pid" 2>/dev/null || true
DATA_SHARING? means the route is likely from discovery. A confirmed result appears as DATA_SHARING with a reason such as datasharing-confirmed-no-traffic.
The alternative reason datasharing-confirmed-no-data-submessages uses delivery evidence plus the absence of DATA submessages. It is not displayed as measured=DATA_SHARING.
Zero-copy needs one more check: verify that the message type meets the required constraints and that the publisher and subscriber use the supported loaning APIs.
What This Check Cannot Prove
- It does not replace application latency, CPU, memory, or throughput benchmarks.
- Humble results from this tool are predictions, not measured traffic.
- SROS2 is not a supported or tested path in the v1.0.0 project.
- Participant-level statistics may be ambiguous when the same node pair exchanges several active topics.
- The observer must share the relevant ROS domain, discovery configuration, network context, and IPC view with the nodes.
A useful diagnosis names the topic, writer, reader, topology, predicted route, measured route, and reason code. For a zero-copy claim, add type eligibility and loaning evidence from both application endpoints.
