Add rosidl_buffer for native Buffer type support#938
Add rosidl_buffer for native Buffer type support#938nvcyc wants to merge 1 commit intoros2:rollingfrom
Conversation
Signed-off-by: CY Chen <cyc@nvidia.com>
|
|
||
| // Test default construction | ||
| TEST(TestBuffer, default_construction) { | ||
| Buffer<int> buffer; |
There was a problem hiding this comment.
Since the goal of the feature is to handle buffers of uint8_t, I think it makes sense to test with that type instead of int.
There was a problem hiding this comment.
Thanks for the suggestions. Tests are updated to test uint8_t.
| EXPECT_EQ(buffer1.size(), buffer2.size()); | ||
| EXPECT_EQ(buffer1.get_backend_type(), buffer2.get_backend_type()); | ||
| for (size_t i = 0; i < buffer1.size(); ++i) { | ||
| EXPECT_EQ(buffer1[i], buffer2[i]); |
There was a problem hiding this comment.
Shall we check that they are in different addresses?
| EXPECT_EQ(buffer1[i], buffer2[i]); | |
| EXPECT_EQ(buffer1[i], buffer2[i]); | |
| EXPECT_NE(&buffer1[i], &buffer2[i]); |
|
|
||
| EXPECT_EQ(buffer1.size(), buffer2.size()); | ||
| for (size_t i = 0; i < buffer1.size(); ++i) { | ||
| EXPECT_EQ(buffer1[i], buffer2[i]); |
| std::vector<Point> copied = buffer.to_vector(); | ||
| EXPECT_DOUBLE_EQ(3.0, copied[0].z); | ||
| } | ||
|
|
There was a problem hiding this comment.
Add some tests that check std::runtime_exception is thrown for certain operations when the implementation is not cpu
There was a problem hiding this comment.
Added a test implementation class NonCpuBufferImpl and tests to check the throwing exception cases.
There was a problem hiding this comment.
The functions in this file shall be checked in tests.
There was a problem hiding this comment.
Added test_c_helpers.cpp for testing functions in c_helpers.cpp.
| { | ||
| impl_ = std::move(impl); | ||
| backend_type_ = backend_type; | ||
| } |
There was a problem hiding this comment.
If this is called with "cpu" as the backend type, we should check that the implementation can be cast to CpuBufferImpl
| } | |
| void set_impl( | |
| std::unique_ptr<BufferImplBase<T>> impl, | |
| const std::string & backend_type) | |
| { | |
| if ((backend_type == "cpu") && (nullptr == dynamic_cast<CpuBufferImpl<T>*>(impl.get()))) { | |
| throw std::runtime_error("CPU backend shall inherit from CpuBufferImpl."); | |
| } | |
| impl_ = std::move(impl); | |
| backend_type_ = backend_type; | |
| } |
There was a problem hiding this comment.
A follow up question would be, why store the backend identifier here instead of querying the underlying implementation for it? Why not let the underlying implementation decide what it does and doesn't support? You can follow that line of thought and say that rosidl::Buffer could simply forward calls to the implementation +/- CPU backend checks.
There was a problem hiding this comment.
That is a valid suggestion. I'm updating the code so that the buffer implementation is the source of truth for the buffer backend type.
|
Pulls: #938 |
| // Type aliases for std::vector compatibility | ||
| using value_type = T; | ||
| using allocator_type = Allocator; | ||
| using size_type = size_t; |
| <?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> | ||
| <package format="3"> | ||
| <name>rosidl_buffer</name> | ||
| <version>1.0.0</version> |
There was a problem hiding this comment.
version should match with the current packages 5.1.2
| Provides Buffer container type with support for multiple memory backends (CPU, GPU, custom). | ||
| </description> | ||
|
|
||
| <maintainer email="cyc@nvidia.com">CY Chen</maintainer> |
hidmic
left a comment
There was a problem hiding this comment.
First pass, meta comments.
| { | ||
| impl_ = std::move(impl); | ||
| backend_type_ = backend_type; | ||
| } |
There was a problem hiding this comment.
A follow up question would be, why store the backend identifier here instead of querying the underlying implementation for it? Why not let the underlying implementation decide what it does and doesn't support? You can follow that line of thought and say that rosidl::Buffer could simply forward calls to the implementation +/- CPU backend checks.
| /// implementations. | ||
| /// @param impl Backend implementation instance. | ||
| /// @param backend_type Backend identifier string. | ||
| void set_impl( |
There was a problem hiding this comment.
@nvcyc meta: hmm, have we considered passing implementation on buffer construction? Allowing swapping implementations on the fly creates race conditions in the other methods.
There was a problem hiding this comment.
You are right and this is also not allowed by my initial design. Removing this function to keep it clean and aligned.
| /// Resize a Buffer<uint8_t>. Throws for non-CPU backends. | ||
| /// @param buffer_ptr Opaque pointer to an rosidl::Buffer<uint8_t> | ||
| /// @param size New size | ||
| void rosidl_buffer_uint8_resize(void * buffer_ptr, size_t size); |
There was a problem hiding this comment.
@nvcyc hmm, I would've expected a rosidl_uint8_buffer_t, even if it's just a type erased wrapper for rosidl::Buffer<uint8_t>. Mind to explain the use case?
There was a problem hiding this comment.
Thanks for the comment.
These C helpers are mainly for the C introspection typesupport path (in later PLs) but also they are not intended to be used against non-CPU-based buffers (and hence we throw exception if accessed with these APIs). In C path, the current design is that CPU-based uint8[] will always be the data field in rosidl_runtime_c__uint8__Sequence as it originally does, so we won't have the case where CPU-based utin8[] is stored in rosidl::Buffer in the C path.
For this reason, I think we actually don't need these introspection C helper functions here as they are not supported by backend buffers. I'm optimizing from the C introspection typesupport side to simply call rosidl_buffer_uint8_throw_if_not_cpu() as guards there.
I'll make the changes to keep them simple in my new update.
|
Thanks for your review. To facilitate the review process with cleaner future PR dependencies, I'm creating a new PR (#941) that's based on a branch in this repo (in contrast to a fork) to replace this one. All the changes for addressing the comments in this PR have been included in the new PR. Please continue our review in #941 and I'll close this PR subsequently. |
Description
This pull request adds the
rosidl_bufferpackage - core C++ buffer types for the ROS 2 native buffer feature. This package introducesrosidl::Buffer<T>, a polymorphic container that's designed to replacestd::vector<T>foruint8[]message fields (to be adopted in later pull requests; we focus on only the core buffer types in this pull request.) The native buffer type enables vendor-specific memory backends (CUDA, ROCm, etc.) while maintaining backward compatibility for existing CPU-basedstd::vector<T>user code.This pull request consists of the following key components:
Buffer<T>: PIMPL-based container providingstd::vector<T>-compatible API. All vector-compatible operations (element access, iterators, modifiers) are CPU-only and throwstd::runtime_errorfor non-CPU backends. Backend management APIs (get_backend_type(),set_impl(),get_impl(),to_vector()) and copy/move semantics work for all backends.BufferImplBase<T>: Minimal abstract base class of buffer implementation. All backend-specific APIs are to be provided by the vendor-specific backend implementations.CpuBufferImpl<T>: CPU-based buffer implementation wrappingstd::vector<T>.Is this user-facing behavior change?
This pull request does not change existing behavior.
When adopted in later pull requests, message types with
uint8[]fields (e.g.,sensor_msgs/msg/Image.data) will userosidl::Buffer<uint8_t>instead ofstd::vector<uint8_t>. For CPU backends (the default),Buffer<T>is a transparent drop-in replacement.Did you use Generative AI?
Yes. Claude (claude-4.6-opus) via Cursor was used to assist with the
std::vector<T>compatibility feature in therosidl::Buffer<T>class and generate portions of the unit tests.Additional Information
This package/PL is part of the broader ROS2 native buffer feature introduced in this post.