-
Notifications
You must be signed in to change notification settings - Fork 260
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
Exclude topics #105
Exclude topics #105
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the patch. Looks good so far, but I have a few remarks for code reusability.
I request changes for the linters and would ideally like to see an extension of the current tests for play
which tests the new functionality.
rosbag2_transport/src/rosbag2_transport/rosbag2_transport_python.cpp
Outdated
Show resolved
Hide resolved
if (exclude_topics_list.empty() == false) { | ||
auto topic_filter_function = [exclude_topics_list](const std::string& topic) | ||
{ | ||
auto entry = exclude_topics_list.find(topic); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this block just be replaced by
return (exclude_topics_list.find(topic) != exclude_topics_list.end());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would argue, that the current implementation is more readable and therefore more expressive than putting everything into one line. However, if you like to change this, I'll do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought to believe that it's easier for the compiler to inline and optimize this as there is no if and thus no branch prediction and stuff might happen. But it's solely premature optimization thinking :)
@@ -43,4 +46,5 @@ def main(self, *, args): # noqa: D102 | |||
uri=bag_file, | |||
storage_id=args.storage, | |||
node_prefix=NODE_NAME_PREFIX, | |||
read_ahead_queue_size=args.read_ahead_queue_size) | |||
read_ahead_queue_size=args.read_ahead_queue_size, | |||
exclude_topics=args.exclude_topics) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check for unique topic names can be done in python. I guess that's a bit easier and avoids the need of a std::set
.
Something like exclude_topics = list(set(args.exclude_topics))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me a set would be the natural choice of container. I guess at this point it doesn't make a difference, but the idea is to have a O(log n) complexity for excluding topic names.
Using a set on python side, wouldn't guarantee, that the API isn't misused from Python side in the future. Using a sorted vector and binary search for the topic lookup bloats the code. @Karsten1987, are you sure you want to have a std::vector instead of a std::set?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not completely certain that I follow correctly. The idea to filter out duplicates in Python is really just a convenience thing because it's a one-liner in Python. That allows us further to pass in a vector with unique topic names in C++.
I am not so much concerned about a misuse from Python side as the current c++ file relies on receiving PyObjects.
@@ -124,6 +128,32 @@ rosbag2_transport_play(PyObject * Py_UNUSED(self), PyObject * args, PyObject * k | |||
play_options.node_prefix = std::string(node_prefix); | |||
play_options.read_ahead_queue_size = read_ahead_queue_size; | |||
|
|||
std::set<std::string> exclude_topics_list; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the command that the topic names could be filtered for uniqueness on the python side, I believe it makes sense to parse the topics as a vector and reuse the code for converting the PyObject to a vector from the record
function. I believe this conversion can be excluded in a separate function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored the PyObject parser code into a generic parse_python_list() function.
65ed36b
to
ec055cb
Compare
… (Change Request ros2#3)
Jenkins had some build problems I couldn't reproduce on my local system. get_messages_primitives() could not be found.
Currently the Jenkins can not build the new test case for the exclude_topic_filter. The error message is
(http://build.ros2.org/job/Dpr__rosbag2__ubuntu_bionic_amd64/8/consoleText ) I can not reproduce it on my local system. The class I'm out of ideas. @Karsten1987, do you have a clue where I should start looking for this problem? |
The In any case, thanks for iterating over this PR. I'll review your PR as soon as possible. |
Looking at this PR again, I believe you actually have to rebase your branch on top of the latest master. |
Thanks, this was exactly what I was missing. The current rosbag2 master is not compiling using the latest ROS2 stable release anymore. Since I can not build the ROS2 master on my system, I'm trying to fix the build problems in blind mode. Let's see what Jenkins is saying. ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have two comments I would like to iterate over:
- why not exposing a
std::vector<std::string>
in the options? I believe that's a bit more user-friendly than forcing to write a complete lambda/function. - I think it's easier to turn this list of excluded topics into a whitelist. This basically means that you only ask once for a list of all topics, cross-validate this with all available topics and run the code as always just like when a
--topics
is specified. This avoids to iterate over the blacklisted topics every time when calling publish on it.
@@ -43,4 +46,5 @@ def main(self, *, args): # noqa: D102 | |||
uri=bag_file, | |||
storage_id=args.storage, | |||
node_prefix=NODE_NAME_PREFIX, | |||
read_ahead_queue_size=args.read_ahead_queue_size) | |||
read_ahead_queue_size=args.read_ahead_queue_size, | |||
exclude_topics=args.exclude_topics) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not completely certain that I follow correctly. The idea to filter out duplicates in Python is really just a convenience thing because it's a one-liner in Python. That allows us further to pass in a vector with unique topic names in C++.
I am not so much concerned about a misuse from Python side as the current c++ file relies on receiving PyObjects.
{ | ||
ReplayableMessage message; | ||
while (message_queue_.try_dequeue(message) && rclcpp::ok()) { | ||
if (options.exclude_topic_filter(message.message->topic_name)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is that check actually still needed if in prepare_publishers
there are no publishers available for excluded topics?
@@ -22,6 +23,23 @@ | |||
#include "rosbag2_transport/storage_options.hpp" | |||
#include "rmw/rmw.h" | |||
|
|||
|
|||
template<class InserterIterator> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice 👍
if (exclude_topics_list.empty() == false) { | ||
auto topic_filter_function = [exclude_topics_list](const std::string& topic) | ||
{ | ||
auto entry = exclude_topics_list.find(topic); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought to believe that it's easier for the compiler to inline and optimize this as there is no if and thus no branch prediction and stuff might happen. But it's solely premature optimization thinking :)
@@ -104,3 +104,56 @@ TEST_F(RosBag2PlayTestFixture, recorded_messages_are_played_for_all_topics) | |||
Each(Pointee(Field(&test_msgs::msg::Arrays::float32_values, | |||
ElementsAre(40.0f, 2.0f, 0.0f))))); | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
size_t read_ahead_queue_size; | ||
std::string node_prefix = ""; | ||
TopicFilter exclude_topic_filter = [](const std::string &) {return false;}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I am thinking about this, I believe it's a bit overkill to provide a lambda/function for this. Why can't a simple std::vector<std::string>
not suffice? Especially when using this as an user facing option. I believe a list of vectors is easier and we can internally apply a generic lambda.
@danieldube Is there any update from your side on this PR? |
Nope. Didn't have time yet to get back to this. |
@danieldube just a friendly ping for an update |
I will not be able to do the necessary changes right now. I will reopen the request, when there is some progress. @Karsten1987, thanks for the review. |
Changed the PlayOptions class to hold a topic filter function. This function tells the player, whether a topic should be included in the playback or not.
The python API now uses the topic filter to provide an exclude topic feature.