Simple C++ node to get more accurate topic frequency

A data point for #6 and #7, since the observer cost can be measured. On Humble with CycloneDDS, attaching ros2 topic hz to one of fifteen intra-process topics raised the watched process’s CPU from 0.303 s to 0.460 s per 10 s run (+52 %, higher in 10 of 10 trials), because the first out-of-process subscriber makes the publisher serialize every message. hz itself cost 7.1 % of a core on a 100 KB topic at 50 Hz, and echo 31.3 %. Method, CSV and plots: Watching a ROS 2 topic changes it - ros2_pulse

One way around the question of how to subscribe carefully is not to subscribe at all. The tracetools hooks in stock binaries already fire on publish (rclcpp_publish, rclcpp_intra_publish) and on callback start, so counting there gives rates, intra-process included, with no endpoint on the graph and nothing for a publisher to adapt to. I did that as an LD_PRELOAD shim (ros2_pulse, Ros2_pulse: per-topic rates and node liveness, including intra-process, on stock binaries); the measured cost was +1.9 % ± 0.7 % CPU.

The tradeoffs: it has to be loaded into the processes you want to see, so it is not a drop-in for pointing hz at an arbitrary running system, and it only counts, it never sees message contents. For the buffer-aware case in #6 that could be useful, since nothing subscribes there is nothing to trigger a CPU fallback, but I have not tested it with rosidl::Buffer publishers.