1.3.5. How to profile your Code

Depending on the Use Case of the code it is necessary or might be useful to profile ROS Nodes. For example is is rather unimportant whether an GUI for changing Parameters is as fast as possible or not. But since SLAM is executed upto 40-300 times per second it is essential to have very performant Code. Profiling the Code is, when done correctly, a very useful tool to find slow code parts so that they can be improved.

1.3.5.1. How to profile Python scripts

It is rather easy to debug complete python scripts.

You have to do three things in your script:

  1. Import yappi and set cpu type

    import yappi
    yappi.set_clock_type('cpu')
    
  2. Start yappi profiling

    import yappi
    yappi.start()
    
  3. End yappi profiling and save results

    yappi.stop()
    path = '/workspace/as_ros/rosbags/profiling/callgrind.out_<name>'
    yappi.get_func_stats().save(path, type='callgrind')
    
  4. If you want, you can add a functionality to automatically export the profiling to a svg image:

    os.system(f'gprof2dot -w -s -f callgrind {path} | dot -Tsvg -o {path}.svg')
    

    Adapt the path to your liking if you want to save the profiling under a more meaningful path

You are ready to profile you python script by simply executing it.

You can now either use the automatically created svg image to analyze the profiling or analyze it according to Analyze profiling with KCachegrind.

1.3.5.2. How to profile C/C++ programs

Todo

This needs to be tested and correctly documented. Here is one possible approach http://wiki.ros.org/roslaunch/Tutorials/Profiling%20roslaunch%20nodes

1.3.5.3. How to profile ROS Nodes

Another Use Case is to profile ROS Nodes rather than python scripts or c programs.

1.3.5.3.1. Preparing to profile ROS Nodes written in Python

Profiling ROS Nodes written in Python is even simpler than profiling Python scripts.

You just have to add an launch-prefix in the launch file, e.g.:

<node name="slam" pkg="slam" type="slam.py" output="screen" required="$(eval arg('required') == 'yes')"
      launch-prefix="/usr/local/bin/yappi -b -f callgrind -o /workspace/as_ros/rosbags/profiling/callgrind.out_$(anon slam)"/>

To be able to use the same launch file with and without profiling the ROS Node, you should add an profiling argument which controls this behaviour.

This is a minimal working example:

<?xml version="1.0" encoding="utf-8"?>

<launch>
   <arg name="profiling" default="no"/>

   <group if="$(eval arg('profiling') == 'yes')">
      <node name="slam" pkg="slam" type="slam.py" output="screen" required="$(eval arg('required') == 'yes')"
            launch-prefix="/usr/local/bin/yappi -b -f callgrind -o /workspace/as_ros/rosbags/profiling/callgrind.out_$(anon slam)"/>
   </group>
   <group unless="$(eval arg('profiling') == 'yes')">
      <node name="slam" pkg="slam" type="slam.py" output="screen" required="$(eval arg('required') == 'yes')"/>
   </group>
</launch>

1.3.5.3.2. Preparing to profile ROS Nodes written in C/C++

Todo

This needs to be tested and correctly documented. Here is one possible approach http://wiki.ros.org/roslaunch/Tutorials/Profiling%20roslaunch%20nodes

1.3.5.3.3. Profiling ROS Nodes

At this moment every launch file for the pipeline ros modules (inference / perception, local mapping, slam, path_planning, motion planning and control) implemented the above explained profiling functionality. Thus all those launch files can be started with profiling:=yes. Also the general pipeline debug launch file (utilities/debug_pipeline) implements the same interface.

The respective profiling files can be found under rosbags/profiling/callgrind.out_<module_name>_<random_id>. You will need them to How to analyze profiling.

1.3.5.4. How to analyze profiling

There are different tools to visualize the results of profiling. Some of those will be shortly presendet in the following.

1.3.5.4.1. Analyze profiling with gprof2dot

You can use gprof2dot to create dot graphs from profiling files. They are more or less call graphs with timing statistics of the respective functions. An example is shown in Example of Callgraph with timing statistics created with gprof2dot.

You can convert an profiling file within the docker container with:

gprof2dot -w -s -f callgrind "path/to/callgrind.out" | dot -Tsvg -o "path/to/callgrind.out.svg"
Example of call graph with timing statistics created with gprof2dot

Fig. 1.4 Example of Callgraph with timing statistics created with gprof2dot

1.3.5.4.2. Analyze profiling with KCachegrind

KCachegrind is an interactive GUI which offers a rich feature spektrum. You can start KCachegrind by executing in the docker container:

kcachegrind

Remember to follow Using GUIs inside an AS ROS container.

1.3.5.4.3. Analyze profiling with SnakeViz

In theory you can also use SnakeViz to visualize profiling. To use SnakeViz you need to use another profiling format when using yappi: pstats.