Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement intra process communications for Pub/Sub #73

Merged
merged 6 commits into from
Aug 21, 2015
Merged

Conversation

wjwwood
Copy link
Member

@wjwwood wjwwood commented Aug 4, 2015

This is a work in progress and isn't ready for review, but feedback about the approach is ok.

Connects to ros2/ros2#59

Things left to do (in no particular order):

  • Write unit tests for the "mapped" ring buffer.
  • Write (figure out how to make) integration/system tests for the entire intra process pipeline.
  • More acceptance testing of the intra process pub/sub in a single node.
  • Review message memory management through the pipeline (print out pointers and instrument [copy] constructors).
  • Investigate cause of memory corruption (maybe?) in the message data (related to previous item).
  • Consider thread safety of intra process manager, ring buffer, other parts of the intra process chain. (Audit intra process comms for thread safety ros2#92)
  • Refactor RCLCPP_MAKE_SHARED_DEFINITIONS macros.
  • Write a theory of operation for the intra process system, describing how it works.
  • Make intra process comms optional and off by default (for now).

Open issues:

  • How to prevent subscriptions from receiving redundant messages through the non-intra process topic.
  • How to size the ring buffer in order to minimize subscribers asking for intra process messages which no longer are being buffered.

Things that I think are out of scope:

  • Considering real-time safety
  • Considering memory strategy integration

@wjwwood
Copy link
Member Author

wjwwood commented Aug 13, 2015

I made intra process optional, with an optional argument to the node constructor. We can consider other ways to control this (maybe through the context construction) later, but this is a temporary way to control it. It currently defaults to intra process off. I think it needs to stay that way until we figure out how to avoid subscriptions receiving messages from intra process as well as from inter process.

I've also written up a "theory of operation" as doxygen comments on the intra process manager class:

https://github.com/ros2/rclcpp/blob/df9d9d1d83ec09ee7a27ff8a0e3858ca96ccc3ae/rclcpp/include/rclcpp/intra_process_manager.hpp#L36-L112

I can move them later, but this was convenient since it was inline with the code I was describing.

I also have a few questions that are unresolved as todo's which would be good if you guys look at them and comment:

Next I'm going to split a few of the changes here off into separate pr's to make them easier to review and merge. Then I'll rebase since it's not currently merge-able. I also have some new tests, but I'm still working out a set of integration tests which actually prove something about the intra process working properly.

@wjwwood
Copy link
Member Author

wjwwood commented Aug 14, 2015

I will just expand on one of the questions I have about the current approach.

In the case where you have something like latching (some amount of messages which subscribers should be caught up on when they late join), I think our ring buffer will handle that situation. But I currently have a check where a message is not yielded when the subscription which asks for it was not available at publish time. The reason for this is that I keep track of which subscriptions have taken the intra process message and then on the last one I return the ownership, avoiding one copy. In the case of one publisher and one intra process subscriber then this is a nice optimization because it means no copies are made.

Now for latching this is obviously a problem since the subscription would not have been at the present during publishing. Therefore when latching is on we'll need to keep the message around until it is replaced by incoming data to the ring buffer, i.e. we can never allow a call to take_intra_process_message cause a message to leave the ring buffer since later a new subscription might ask for it and expect it because of latching.

The question is should we change from:

  • If a subscription which is not in the list of intended subscriptions asks for a message, return nullptr

to:

  • If a subscription which is not in the list of intended subscriptions asks for a message, return the message, but do not "decrement the reference count" on the message.

The count I'm talking about is the number of subscriptions which were present when the message was published. Also when this count reaches zero and latching is not enabled, we can return the ownership of the message rather than a copy (effectively removing it from the intra process manager's storage).

@wjwwood
Copy link
Member Author

wjwwood commented Aug 18, 2015

After talking with @dirk-thomas about the previous post, I've decided to keep the existing behavior of not giving messages out to subscriptions which did not exist when the message was published. I've also decided to leave TODO's where ever things will need to be changed in order to support something like latching so that we can move forward without that for now.

I've also added tests for the intra process manager and tests into the test_rclcpp package.

@gerkey
Copy link
Member

gerkey commented Aug 18, 2015

@jacquelinekay to review some of the open points

@wjwwood wjwwood force-pushed the intra_process branch 2 times, most recently from 5e4f3ed to baba234 Compare August 19, 2015 01:35
changes how the default context is gotten and
adds an option for enabling/disabling intra
process comms
this involves changes in the executor, node,
publisher, and subscription classes

I'd like a more decoupled way to integrate this
into the executor and node but I was unable to
find a good way to do so.
@wjwwood
Copy link
Member Author

wjwwood commented Aug 19, 2015

Ok I've rebased and rewritten the commit history to something that's slightly easier to digest.

sub_context = std::shared_ptr<SubContext>(
new SubContext(std::forward<Args>(args) ...),
[] (SubContext * sub_context_ptr) {
delete sub_context_ptr;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why the custom deleter here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because it stores it as a void * and I believe it is necessary to ensure that the destructor is called even if the last reference is a shared_ptr of type void *, but I don't know that for sure.

// *INDENT-ON*
}
}
if (store_intra_process_message_) {
Copy link
Contributor

Choose a reason for hiding this comment

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

why not else here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because I intend to remove the first conditional later.


ament_add_gtest(test_mapped_ring_buffer test/test_mapped_ring_buffer.cpp)
ament_add_gtest(test_intra_process_manager test/test_intra_process_manager.cpp)
target_include_directories(test_intra_process_manager PUBLIC "${rcl_interfaces_INCLUDE_DIRS}")
Copy link
Member

Choose a reason for hiding this comment

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

This must be wrapped in a condition:

if(TARGET test_intra_process_manager)

@esteve
Copy link
Member

esteve commented Aug 21, 2015

+1, though I have to admit I haven't done a deep review. I can read the code with more detail after it's been merged.

wjwwood added a commit that referenced this pull request Aug 21, 2015
Implement intra process communications for Pub/Sub
@wjwwood wjwwood merged commit 7f016cd into master Aug 21, 2015
@wjwwood wjwwood removed the in progress Actively being worked on (Kanban column) label Aug 21, 2015
@wjwwood wjwwood deleted the intra_process branch August 21, 2015 20:29
DensoADAS pushed a commit to DensoADAS/rclcpp that referenced this pull request Aug 5, 2022
* ros2GH-61 Read topic directly from message when playing and allow to play multiple topics

* ros2GH-61 Add test for SqliteStorage and update old ones

* ros2GH-62 Extend function to poll for any number of specified topics

* ros2GH-62 Allow subscription to several topics

* ros2GH-61 Obtain the topic name directly from the database

- Uses a JOIN instead of mapping the topic_id to the name in code

* ros2GH-61 Cache read row in result iterator

This allows repeated dereferencing on same row without quering the
database again.

* ros2GH-62 Change demo-record to allow specifying multiple topics

* ros2GH-62 Add test to write non-string topic + refactoring

* ros2GH-62 Add test for subscription to multiple topics

* ros2GH-62 Cleanup

* ros2GH-62 Simplify test setup

* ros2GH-61 Cleanup

* ros2GH-61 consolidate storage integration test

* ros2GH-62 Consolidate write integration tests

* ros2GH-61 enhance read integration test to check multiple topics

* ros2GH-62 Improve rosbag integration test

* ros2GH-62: Polish rosbag2_rosbag_node_test

* ros2GH-62 Fix cpplint

* ros2GH-62 Fix memory leak in rosbag helper

* ros2GH-62 Cleanup of subscriptions

* ros2GH-62 do not use flaky timers in rosbag2_write_integration_test

* ros2GH-62 Use rmw_serialize_message_t consistently in test helper classes

* ros2GH-73 Use test_msgs in read_integration_test

* ros2GH-26 Cleanup: fix alphabetic orderung
DensoADAS pushed a commit to DensoADAS/rclcpp that referenced this pull request Aug 5, 2022
* add ros1_bridge dependency

* update maintainer email

* add git as build dependency
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.

5 participants