I am working on optimizing subscriber-side delays in ROS 2. When handling large data samples, I noticed that most delays occur during the std::vector::resize() operation in the FastCDR library while subscribing to data of type std_msgs::msg::ByteMultiArray. After inspecting the data structure in the ROS 2 build folder, I believe initializing the vector with a fixed size could help reduce delays caused by runtime memory allocation. I want to experiment with the std::vector::reserve() operation for this specific type.
The below code represents the ByteMultiArray_ in byte_multi_array__struct.hpp file
// message struct
template<class ContainerAllocator>
struct ByteMultiArray_
{
using Type = ByteMultiArray_<ContainerAllocator>;
explicit ByteMultiArray_(rosidl_runtime_cpp::MessageInitialization _init = rosidl_runtime_cpp::MessageInitialization::ALL)
: layout(_init)
{
(void)_init;
}
explicit ByteMultiArray_(const ContainerAllocator & _alloc, rosidl_runtime_cpp::MessageInitialization _init = rosidl_runtime_cpp::MessageInitialization::ALL)
: layout(_alloc, _init)
{
(void)_init;
}
// field types and members
using _layout_type =
std_msgs::msg::MultiArrayLayout_<ContainerAllocator>;
_layout_type layout;
using _data_type =
std::vector<unsigned char, typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<unsigned char>>;
_data_type data;
// setters for named parameter idiom
Type & set__layout(
const std_msgs::msg::MultiArrayLayout_<ContainerAllocator> & _arg)
{
this->layout = _arg;
return *this;
}
The msg__struct.hpp.em file in rosidl_generator_cpp which used to create the file byte_multi_array__struct.hpp
explicit @(message.structure.namespaced_type.name)_(const ContainerAllocator & _alloc, rosidl_runtime_cpp::MessageInitialization _init = rosidl_runtime_cpp::MessageInitialization::ALL)
@[if alloc_list]@
: @(',\n '.join(alloc_list))
@[end if]@
{
@[if not member_list]@
(void)_init;
@[end if]@
@[if not alloc_list]@
(void)_alloc;
@[end if]@
@[if default_value_members]@
if (rosidl_runtime_cpp::MessageInitialization::ALL == _init ||
rosidl_runtime_cpp::MessageInitialization::DEFAULTS_ONLY == _init)
{
@[ for membset in default_value_members]@
@[ for line in generate_default_string(membset)]@
@(line)
@[ end for]@
@[ end for]@
@[ if zero_value_members]@
} else if (rosidl_runtime_cpp::MessageInitialization::ZERO == _init) {
@[ for membset in zero_value_members]@
@[ for line in generate_zero_string(membset, '_alloc, _init')]@
@(line)
@[ end for]@
@[ end for]@
@[ end if]@
}
@[end if]@
@[if non_defaulted_zero_initialized_members]@
if (rosidl_runtime_cpp::MessageInitialization::ALL == _init ||
rosidl_runtime_cpp::MessageInitialization::ZERO == _init)
{
@[ for membset in non_defaulted_zero_initialized_members]@
@[ for line in generate_zero_string(membset, '_alloc, _init')]@
@(line)
@[ end for]@
@[ end for]@
}
@[end if]@
}
// field types and members
@[for member in message.structure.members]@
using _@(member.name)_type =
@(msg_type_to_cpp(member.type));
_@(member.name)_type @(member.name);
@[end for]@c
How can I include this modification? Do I need to update the.em file, and if so, how should I proceed?
Is there other efficient methods for this optimization in FastCDR?