Optimizations cpp ROS2 node. colcon build

I’ve been using ROS2 for a year. Maybe previously you guys talked about this. However I’ve done experimental tests about the optimization C++ code ROS2 node and wrote a simple node.

#include "rclcpp/rclcpp.hpp"

class HelloWorldNode : public rclcpp::Node
{
public:
    HelloWorldNode() : Node("hello_world_node")
    {
        RCLCPP_INFO(this->get_logger(), "Hello, World! This is a ROS2 node.");
    }
};

int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    rclcpp::spin(std::make_shared<HelloWorldNode>());
    rclcpp::shutdown();
    return 0;
}

Then by simply building the above code by using

colcon build

I got hello_node then explored assemble code

objdump -d <path>/hello_node > hello_node.asm

got around 5000 lines of instruction code in hello_node.asm, it seems like it didn’t do any optimization to the code. Then run the following command

colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release
///alternative
colcon build --cmake-args -DCMAKE_CXX_FLAGS="-O3 -march=native"

then looked number instructions lines the number dramatically decreased from 5000 to 1700. the number of instruction lines in assemble doesn’t always mean it’s optimized yet it’s good factor.

“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”"
simple by adding “set(CMAKE_BUILD_TYPE Release)” to your CMakeLists.txt is enough. then you can simply use colcon build.
Optimizations flags

1 Like

Please, don’t do this in any publicly available packages. Let the users decide about the build type.

If you really want to prefer Release builds, but still allow the user to choose, you can do it like here: geometric_shapes/CMakeLists.txt at noetic-devel · moveit/geometric_shapes · GitHub .

This can be very dangerous with ROS. As soon as your package uses (or exports) any Eigen, PCL or OpenCV interfaces, it leads to hard-to-debug memory segfaults, because native optimizations can change memory layout of some optimized data structures. You always have to either compile whole your system with this flag (meaning, at least whole ROS, PCL library and OpenCV), or you have to live without it.

The only safe place where you can use it is if you are absolutely sure your node doesn’t use any of Eigen/PCL/OpenCV directly. Then you can compile it to gain speed without risking memory issues.

Things get even more complicated if you want to release your package on the buildfarm. Because then march=native actually optimizes for the buildfarm machine HW, which is not what you want. I have a released node that uses this here: ros-utils/cras_cpp_common/CMakeLists.txt at master · ctu-vras/ros-utils · GitHub . Basically, it just detects x86 vs arm64 and adds some basic SIMD flags, not all march=native.

1 Like

Just for completion, a more convenient way to set the build type using colcon is:

For installation of the mixins (one time only per workspace)

colcon mixin add default https://raw.githubusercontent.com/colcon/colcon-mixin-repository/master/index.yaml
colcon mixin update default

after this you can use:

colcon build --mixin release

Also note, that ‘release’ sets the -O3 compiler flag, which might be dangerous, if your code relies on undefined behavior.

A further way of optimizing is, to use LTO. This is only useful, if your code is separated into multiple compile units.

2 Likes

If you do not want to go through the “hassle” of installing the mixins and using a command line option for every colcon build call, and, more importantly, want to use different settings for different packages, you can create a .meta file.

colcon build will use the default file colcon.meta, if it exists in the workspace. Otherwise, you can point to another file with the --metas option.

Example: Create the file colcon.meta in your workspace and set package-specific build arguments:

names:
  my_library_package_name:
    cmake-args:
      - "-D CMAKE_BUILD_TYPE=Release"
  my_ros_node_package_name:
    cmake-args:
      - "-D CMAKE_BUILD_TYPE=Debug"

Now, when you run colcon build in the workspace, it will build package my_library_package_name in release mode and my_ros_node_package_name and debug mode. This is very useful if you are developing and only need to debug a part of your packages.

2 Likes

And to provide one more option, colcon more recently supports workspace-specific defaults files, so you can turn on a release build for individual workspaces vs packages if preferred.

2 Likes

Is this the correct format for that option @jdlangs? (Seems to work…)

my_workspace/colcon_defaults.yaml

{
    "build": {
        "cmake-args": "-DCMAKE_BUILD_TYPE=Release"
    }
}
1 Like

Consider -DCMAKE_BUILD_TYPE=RelWithDebInfo for development builds (along with the colcon options, --symlink-install).

However for release builds that get packaged you do not want to install with symlinks.

See
https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
https://stackoverflow.com/questions/48754619/what-are-cmake-build-type-debug-release-relwithdebinfo-and-minsizerel

1 Like