0
$\begingroup$

Rosanswers logo

I am studying ROS2 dashing. I 'd like to create many simple subscribers which subscribe same topic and test CPU performance. Now I am trying as follws. This is a example which two subscribers run. I'd like to test a case in which ,for example, 100 subscribers are running. Is there any better way to realize multiple such ? Thanks.

//subnodes.hpp
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/int16.hpp>

class MinimalSubscriber1:public rclcpp::Node{
private:
    rclcpp::Subscription<std_msgs::msg::Int16>::SharedPtr subscription_;
    void topic_callback_(const std_msgs::msg::Int16::SharedPtr msg);
public:
    MinimalSubscriber1();
};

class MinimalSubscriber2:public rclcpp::Node{
private:
    rclcpp::Subscription<std_msgs::msg::Int16>::SharedPtr subscription_;
    void topic_callback_(const std_msgs::msg::Int16::SharedPtr msg);
public:
    MinimalSubscriber2();
};

//subnodes.cpp
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/int16.hpp>
#include "subnodes.hpp"

void MinimalSubscriber1::topic_callback_(const std_msgs::msg::Int16::SharedPtr msg){
    RCLCPP_INFO(this->get_logger(), "No.1 heard:%d",msg->data);
}
 MinimalSubscriber1::MinimalSubscriber1()
:Node("minimal_subscriber_test1"){
    subscription_ = this->create_subscription<std_msgs::msg::Int16>(
        "testtopic",
        std::bind(&MinimalSubscriber1::topic_callback_,this,std::placeholders::_1)
    );
}

void MinimalSubscriber2::topic_callback_(const std_msgs::msg::Int16::SharedPtr msg){
    RCLCPP_INFO(this->get_logger(), "No.2 heard:%d",msg->data);
}
 MinimalSubscriber2::MinimalSubscriber2()
:Node("minimal_subscriber_test2"){
    subscription_ = this->create_subscription<std_msgs::msg::Int16>(
        "testtopic",
        std::bind(&MinimalSubscriber2::topic_callback_,this,std::placeholders::_1)
    );
}

//main.cpp
#include <rclcpp/rclcpp.hpp>
#include "subnodes.hpp"

int main(int argc,char*argv[]){
  rclcpp::init(argc,argv);
  rclcpp::executors::SingleThreadedExecutor exec;

  auto node1 = std::make_shared<MinimalSubscriber1>();
  auto node2 = std::make_shared<MinimalSubscriber2>();
  exec.add_node(node1);
  exec.add_node(node2);
  exec::spin();
  rclcpp::shutdown();
  return 0;
}

Originally posted by marney on ROS Answers with karma: 3 on 2020-01-13

Post score: 0


Original comments

Comment by MCornelis on 2020-01-13:
Long answer: Have a look here: https://discourse.ros.org/t/singlethreadedexecutor-creates-a-high-cpu-overhead-in-ros-2/10077 And here: https://github.com/nobleo/ros2_performance

Short answer: You can create subscribers in a loop but you have to save a pointer to the subscribers outside of the loop

std::vector<rclcpp::Subscription<String>::SharedPtr> sub_refs;

for (int s = 0; s < amount of subs; ++s) {
      auto sub = node->create_subscription<String>("topic_name", qos,
                                                   [](String::SharedPtr) {});
      sub_refs.push_back(sub);
    }

I'm not sure if the example is using the dashing API, but a similar implementation should be possible in dashing. The important thing is that you have the sub_refs declared outside of the loop.

Full example of source code can be found at the nobleo github on the dashing branch in the source folder. Look for ros.cc , that one partly does what you want.

Comment by MCornelis on 2020-01-13:
Just a heads up, working with CPU utilization is not as straight-forward as some people might think. Especially when dealing with big.LITTLE configurations and other factors that might influence CPU utilization. The results you can find in the discourse post and on the nobleo github are all hardware and software specific and the tests may return different results on your setup.

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

Simple example to make n nodes that all have 1 subscriber that subscribes to the topic "topic_name":

  #include <rclcpp/rclcpp.hpp>
  #include <std_msgs/msg/string.hpp>

  int main() {
  using namespace std_msgs::msg;
  rclcpp::init(0, nullptr);
 
  n = 100; // create this many nodes
 
  rclcpp::executors::SingleThreadedExecutor exec; // create executor
  std::vector<rclcpp::Node::SharedPtr> node_refs; // create vector to store node references
  std::vector<rclcpp::Subscription<String>::SharedPtr> sub_refs; // create vector to store sub references

  for (int i = 0; i < n; i++) { 
    auto node = std::make_shared<rclcpp::Node>("node_" + std::to_string(i)); // create a node
    auto sub = node->create_subscription<String>("topic_name", qos,
                                                   [](String::SharedPtr) {}); // add a sub to the node
    sub_refs.push_back(sub); // save a referene to the sub
    node_refs.push_back(node); // save  a reference to the node
    exec.add_node(node); // add the node with the sub to executor
  } 
  exec.spin(); // spin everything
  rclcpp::shutdown();
  return 0;
}

Originally posted by MCornelis with karma: 331 on 2020-01-13

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by MCornelis on 2020-01-13:
Nodes also add CPU overhead btw. An explanation can be found here: https://discourse.ros.org/t/reconsidering-1-to-1-mapping-of-ros-nodes-to-dds-participants/10062/22 So you could also consider creating 1 node and adding n subscribers to it (instead of n nodes with 1 sub each).

Comment by marney on 2020-01-16:
Thank you so much for reply. I could test the case in multiple nodes

you could also consider creating 1 node and adding n subscribers to it

Yes, the idea should be considered.

Thanks.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.