|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |
System Dependencies
Dependant Packages
Launch files
Messages
Services
Plugins
Recent questions tagged rmw_stats_shim at Robotics Stack Exchange
|
rmw_stats_shim package from graph_monitor repormw_stats_shim rosgraph_monitor rosgraph_monitor_msgs rosgraph_monitor_test |
ROS Distro
|
Package Summary
| Version | 0.3.2 |
| License | Apache License 2.0 |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/ros-tooling/graph-monitor.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-11-02 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Maintainers
- Emerson Knapp
Authors
- Emerson Knapp on behalf of Bonsai Robotics
RMW Stats Shim
Depends on a modified version of rmw_implementation to provide topic statistics calculation within the RMW layer of each node, without having to instrument application code.
This component
- Wraps & intercepts some RMW API calls
- Calculates “published period” statistics for every Publisher
- Calculates “received period” statistics for every Subscription
- Calculates “take age” statistics for every Subscription
- This is the different between publish system timestamp and the time at which
rmw_takeis called, so is the sum of network latency plus executor latency
- This is the different between publish system timestamp and the time at which
- Creates a
/topic_statisticsPublisher for every Node and publishes to it periodically about the statistics from within the node
Key points:
- Requires no subscriptions, no extra copies, to do statistics on all topics
- Requires no modification to application code to use
Configuration
Set the following environment variables before launching a node to configure topic statistics
- Required:
RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim -
ROS_TOPIC_STATISTICS_WINDOW_SIZE- how many messages to use in rolling buffer for stats (stores only timestamp information, not contents data)- Default:
50
- Default:
-
ROS_TOPIC_STATISTICS_TOPIC_NAME- name of the topic to publish statistics on- Default:
/topic_statistics
- Default:
-
ROS_TOPIC_STATISTICS_PUBLISH_PERIOD- Interval in seconds at which to periodically publish stats- Default:
1.0
- Default:
Usage
colcon build --packages-select rmw_implementation rmw_stats_shim
source install/setup.bash
export RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim
# run any ROS 2 node/launch/etc
Changelog for package rmw_stats_shim
0.3.2 (2026-11-02)
-
fix(rmw_stats_shim): populate TopicStatistic min and max (#79) Fixes #78. [EndpointStatistics::periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} set only [mean]{.title-ref}, so [min]{.title-ref} and [max]{.title-ref} in every [TopicStatistic]{.title-ref} stayed zero. [RollingMeanAccumulator]{.title-ref} had nothing to fill them from, since it only kept a running sum. This adds [getRollingMin()]{.title-ref} and [getRollingMax()]{.title-ref} to [RollingMeanAccumulator]{.title-ref}. They scan the values still in the window, so they cover the same [ROS_TOPIC_STATISTICS_WINDOW_SIZE]{.title-ref} samples as the mean, and values that leave the window drop out of both. [periodMsg()]{.title-ref} and [ageMsg()]{.title-ref} now fill [min]{.title-ref} and [max]{.title-ref} from them. The scan is linear in the window size and runs once per published statistic, not per message. Tests:
- [test_rolling_mean_accumulator.cpp]{.title-ref} checks min and max on a partly filled window and after the window wraps.
- [EndpointStatistics.MessagesReportWindowMinAndMax]{.title-ref} in [test_stat_collector.cpp]{.title-ref} feeds periods of 10, 20 and 6 ms and ages of 7, 3 and 15 ms, then checks [mean]{.title-ref}, [min]{.title-ref} and [max]{.title-ref} in both messages. Without the change in [stat_collector.cpp]{.title-ref} it fails with [min]{.title-ref} and [max]{.title-ref} at 0. Built with colcon on Jazzy ([rosgraph_monitor_msgs]{.title-ref} and [rmw_stats_shim]{.title-ref} with [BUILD_TESTING=ON]{.title-ref}); [test_rolling_mean_accumulator]{.title-ref}, [test_stat_collector]{.title-ref} and [test_timer]{.title-ref} pass, and the pre-commit hooks pass on the changed files. ---------
-
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76) Follows up #75. [StatCollector]{.title-ref} is a process-wide singleton. Its maps ([nodes_]{.title-ref}, [stat_publishers_]{.title-ref}, [publishers_]{.title-ref}, [subscriptions_]{.title-ref}) were accessed with no locking from three kinds of thread:
- DDS and executor threads: [onPublish]{.title-ref}/[onReceive]{.title-ref}, called from the wrapped [rmw_publish]{.title-ref}/[rmw_take*]{.title-ref}.
- Any thread creating or destroying entities: [add*]{.title-ref}/[remove*]{.title-ref}.
- The stats [Timer]{.title-ref} thread: [publishStatistics]{.title-ref}. A rehash during an insert while another thread ran [find]{.title-ref} caused a SIGSEGV in [StatCollector::onReceive]{.title-ref} ([stat_function.h]{.title-ref}/[find]{.title-ref} frame) during test teardown in a downstream CI. To solve it, add mutex protection for this state. Use separate mutexes for nodes vs endpoints. ## Performance This adds one uncontended mutex lock per publish/take in every process with the shim loaded. The downstream project plans to benchmark it.
-
fix(rmw_stats_shim): make Timer::stop idempotent (#75) ## Problem Since #50, [~StatCollector]{.title-ref} calls [timer_->stop()]{.title-ref} explicitly. Then [~optional<Timer>]{.title-ref} runs [~Timer]{.title-ref}, which calls [stop()]{.title-ref} again. The second call does [thread_.join()]{.title-ref} on an empty [std::thread]{.title-ref}, which throws [std::system_error]{.title-ref} ([Invalid argument]{.title-ref}) during static destruction. As a result, in 0.3.0 every process that loads the shim ([RMW_IMPLEMENTATION_WRAPPER=rmw_stats_shim]{.title-ref}) aborts on a normal exit:
` terminate called after throwing an instance of 'std::system_error' what(): Invalid argument ... Timer::stop timer.cpp:43 ... Timer::~Timer timer.cpp:16 ... StatCollector::~StatCollector stat_collector.cpp:309[ This showed up as 19 failing test executables downstream when we bumped to 0.3.0: the tests passed, but every process SIGABRTed at exit. ## Fix Guard the join with `joinable()]{.title-ref}, matching the header's documented contract for [stop()]{.title-ref} ("No-op if not running"). ## Tests Adds [rmw_stats_shim/test/test_timer.cpp]{.title-ref}, the package's first tests: stop without start, stop twice, destroy after stop, restart after stop. They fail on [main]{.title-ref} and pass with this change (built and run on Jazzy). ## Not in this PR [StatCollector]{.title-ref}'s [nodes_]{.title-ref}, [publishers_]{.title-ref} and [subscriptions_]{.title-ref} maps are still accessed without a lock from DDS listener threads ([onReceive]{.title-ref}/[onPublish]{.title-ref}), the main thread (endpoint add/remove) and the stats timer thread. We've seen a SIGSEGV in [onReceive]{.title-ref} from this. I'll follow up separately. -
fix(rmw_stats_shim): lock StatCollector endpoint maps (#76)
File truncated at 100 lines see the full file
Package Dependencies
| Deps | Name |
|---|---|
| ament_cmake | |
| ament_cmake_gtest | |
| rosgraph_monitor_msgs | |
| rosidl_runtime_cpp | |
| rosidl_typesupport_cpp |