Skip to content

Conversation

@mauropasse
Copy link
Collaborator

Usage example:

auto options = rclcpp::ExecutorOptions();
options.queue_options.queue_strategy = rclcpp::QueueStrategy::LIMITED_EVENTS_WITH_TIME_ORDERING;
auto executor1 = std::make_shared<rclcpp::executors::EventsExecutor>(options);

options.queue_options.queue_strategy = rclcpp::QueueStrategy::BOUNDED;
options.queue_options.max_events = 100;
auto executor2 = std::make_shared<rclcpp::executors::EventsExecutor>(options);

// Use default strategy: QueueStrategy::CPU_PERFORMANCE, no need to pass options
auto executor3 = std::make_shared<rclcpp::executors::EventsExecutor>();

I ended up creating 3 policies:
CPU_PERFORMANCE the default policy, it should peform as good as without this PR (to confirm soon)
LIMITED_EVENTS_WITH_TIME_ORDERING checks before pushing is there are more events than QoS->depth and reorders
BOUNDED the queue is hard bounded to a limit. In case of more events, a prune of the queue happens based on QoS.

TODO:

  • Run some tests on the single core platform to create some graphs with performances comparison between the different modes.
  • Implement for clients, services and events

@alsora
Copy link
Collaborator

alsora commented Feb 3, 2021

Some early comments:

  • The events executor should not have any knowledge of which types of queues are available. The current implementation prevents users to define their own policy without modifying the rclcpp code, which is not good.
    A possible solution would be to have a base class EventsQueue and then let the users define their own derivate class from that.
    This can be passed to the events executor then.

  • It looks to me that a lot of functionalities are being moved from the executor to the queue, is that really needed? It makes the code hard to follow and basically requires the queue to know about which spin implementations are available.
    The queue should only expose very basic API such as push and pop

: memory_strategy(rclcpp::memory_strategies::create_default_strategy()),
context(rclcpp::contexts::get_global_default_context()),
max_conditions(0)
max_conditions(0), queue_options(QueueOptions())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ExecutorOption structure should only contain stuff that is used by all executors

{
QueueOptions()
: queue_strategy(QueueStrategy::CPU_PERFORMANCE),
max_events(1000)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following my comments above, max_events should be an internal detail of a bounded queue class

RCLCPP_DISABLE_COPY(EventsExecutor)

using EventQueue = std::queue<rmw_listener_event_t>;
using EventQueue = std::deque<rmw_listener_event_t>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks not needed anymore now (and also you can remove the queue/deque include)

// Notify that the event queue has some events in it.
this_executor->event_queue_cv_.notify_one();
// Push event and notify the queue it has some events
this_executor->events_queue_->push_and_notify(event);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be just a simple push, then the notify should still be done here

*/
RCLCPP_PUBLIC
rmw_qos_profile_t
get_actual_qos() const
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand what this is.
Why a waitable has a QOS?

waitable_events_in_queue_map_.clear();
}

void EventsQueue::swap(EventQueue & event_queue)
Copy link
Collaborator

@alsora alsora Feb 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to expose that we are doing a swap. That's just an optimization.
This API should have a signature like:

std::queue<rmw_listener_event_t> EventsQueue::get_all_events()

clear_stats_implem_();
}

void EventsQueue::wait_for_event(std::chrono::nanoseconds timeout)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait_for_event and wait_for_event_and_swap seem not needed to me.
The executor should manage the wait, then call swap (or its renamed version as I suggest above).
It's also ok to have this class without any mutex and let the executor manage that

clear_stats_implem_();
}

bool EventsQueue::wait_and_get_first_event(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.
If the executor manages the wait and the mutex, the queue only need to expose empty() and front() APIs

@mauropasse
Copy link
Collaborator Author

Created a new PR based on this comments: #40

@mauropasse mauropasse closed this Feb 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants