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

Optimized large binary array publishing #819

Merged
merged 2 commits into from
Oct 21, 2022
Merged

Conversation

tsender
Copy link
Contributor

@tsender tsender commented Oct 21, 2022

Public API Changes
None

Description
In my use case for rosbridge, I am sending rosbridge a lot of sensor data (using bson) from an external simulator and want to publish the data on ROS. I recently noticed that publishing large binary arrays (size on the order of 10^5 or larger) is extremely slow on the ros2 branch (compared to using the ros1 branch with python 2). I was able to track down the source of the problem to the rosbridge_library/internal/message_conversion.py file. The issue is that once the bson message has been deserialized, rosbridge actually creates a copy of the binary data into the appropriate ROS message in the function _to_binary_inst(msg), and then publishes the message. The act of copying large arrays from the decoded message into the ROS message is the bottleneck.

The few lines of code I added check if the incoming data array is of type bytes, in which case it leverages Python's buffer protocol to perform a zero copy of the data into the appropriate ROS message. This change applies to anyone wanting to publish large binary arrays of data (i.e. the message field is of type uint8[] or char[]), such as camera or lidar data from an external source.

Without this change, copying an array of size 10^5 would take on the order of 10^-2 seconds. But with the change, the zero copy takes on the order of 10^-5 seconds (for the same amount of data). This is a HUGE speed-up.

Copy link
Contributor

@achim-k achim-k left a comment

Choose a reason for hiding this comment

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

Nice find! LGTM after fixing the linting error.

So in your use case the clients publish large messages? I guess that normally it is the other way round, clients publish small messages but can subscribe to large topics such as point clouds.

@@ -299,6 +299,11 @@ def _to_binary_inst(msg):
return list(standard_b64decode(msg))
if isinstance(msg, list):
return msg
if isinstance(msg, bytes):
# Using the frombytes() method with a memoryview of the data allows for zero copying of data thanks to Python's buffer protocol (HUGE time-saver for large arrays)
data = array.array('B')
Copy link
Contributor

Choose a reason for hiding this comment

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

This line causes the linting CI step to fail, it should be double quotes instead of single quotes.

@tsender
Copy link
Contributor Author

tsender commented Oct 21, 2022

Thanks for approving the PR.

For my usage of this repo, I am using Unreal Engine to run simulations, which natively does not support ROS communication. One group developed a plugin called ROSIntegration for Unreal which connects to rosbridge. And in my case, I am publishing sensor data from Unreal and then subscribing to control commands. So yes, this rosbridge client is primarily used for publishing sensor data (in terms of the network traffic).

@achim-k achim-k merged commit d6a44c7 into RobotWebTools:ros2 Oct 21, 2022
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.

None yet

2 participants