diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2155a19..0764254 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,5 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-dockerfile { - "name": "Existing Dockerfile", + "name": "LTTng Traced ROS2 Scheduling Experiments", "build": { // Sets the run context to one level up instead of the .devcontainer folder. "context": "..", @@ -29,7 +27,7 @@ // "forwardPorts": [], // Uncomment the next line to run commands after the container is created. - // "postCreateCommand": "cat /etc/os-release", + "postCreateCommand": "bash postCreate.sh", // Uncomment the next line to run commands after the container is created and started. "postStartCommand": "sudo modprobe lttng-tracer && sudo modprobe lttng-ring-buffer-client-discard && sudo modprobe lttng-probe-sched && sudo modprobe lttng-probe-irq && sudo modprobe lttng-probe-timer && (sudo lttng-sessiond --daemonize || true)", @@ -38,6 +36,7 @@ "customizations": { "vscode": { "settings": { + "terminal.integrated.shell.linux": "/bin/bash", "terminal.integrated.defaultProfile.linux": "bash", "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools" }, @@ -59,8 +58,19 @@ "ms-python.vscode-python-envs" ] } - } + }, + + "features": { + // optional but convenient + "ghcr.io/devcontainers/features/common-utils:2": {} + }, + + "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/${localWorkspaceFolderBasename},type=bind,consistency=cached", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "containerEnv": { + "TRACETOOLS_TRACEPOINTS_ENABLED": "1" + }, // Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "devcontainer" + "remoteUser": "dev" } \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 97f37eb..5c5e335 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,11 +1,23 @@ [submodule "src/ros_edf"] path = src/ros_edf url = git@git.niklashalle.net:niklas/ROS-Dynamic-Executor.git -[submodule "src/tools/ros2_tracing"] - path = src/tools/ros2_tracing - url = git@git.niklashalle.net:niklas/ros2_tracing.git - branch = foxy [submodule "src/tools/tracetools_analysis"] - path = src/tools/tracetools_analysis + path = src/tracetools_analysis url = git@git.niklashalle.net:niklas/tracetools_analysis.git branch = foxy +[submodule "src/rcl"] + path = src/rcl + url = git@git.niklashalle.net:niklas/rcl.git + branch = foxy +[submodule "src/rclcpp"] + path = src/rclcpp + url = git@git.niklashalle.net:niklas/rclcpp.git + branch = foxy +[submodule "src/ros2_tracing"] + path = src/ros2_tracing + url = git@git.niklashalle.net:niklas/ros2_tracing.git + branch = foxy +[submodule "src/rmw_cyclonedds"] + path = src/rmw_cyclonedds + url = git@git.niklashalle.net:niklas/rmw_cyclonedds.git + branch = foxy diff --git a/Dockerfile b/Dockerfile index 6af618f..45c0958 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,11 +37,8 @@ RUN apt-get update -q && \ apt-get install -yq --no-install-recommends \ apt-utils wget curl git build-essential vim sudo \ lsb-release locales bash-completion tzdata gosu \ - gedit htop nano libserial-dev ninja-build clang-18 - -# Update packages and install dependencies -RUN apt-get update && \ - apt-get install -y software-properties-common curl build-essential && \ + gedit htop nano libserial-dev ninja-build clang-18 \ + software-properties-common && \ add-apt-repository ppa:deadsnakes/ppa && \ apt-get update && \ apt-get install -y \ @@ -57,7 +54,8 @@ RUN apt-get update && \ # These packages help with building and managing ROS 2 workspaces RUN apt-get update -q && \ apt-get install -y gnupg2 iputils-ping usbutils \ - python3-argcomplete python3-colcon-common-extensions python3-networkx python3-pip python3-rosdep python3-vcstool + python3-argcomplete python3-colcon-common-extensions \ + python3-networkx python3-pip python3-rosdep python3-vcstool # Set up the ROS 2 environment # This ensures that ROS 2 commands are available in the shell @@ -72,18 +70,13 @@ RUN curl -sS https://bootstrap.pypa.io/pip/3.8/get-pip.py | python3.8 # Set Python 3.8 as default Python3 RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 1 -# Install modern nodejs (optional but good practice for JupyterLab widgets) -RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ - apt-get install -y nodejs && \ - npm install -g npm - -# Install JupyterLab globally -RUN python3 -m pip install --upgrade jupyterlab - # Install dependencies for ros2_tracing -RUN apt-get update -q && \ - apt-get install -y lttng-tools lttng-modules-dkms liblttng-ust-dev -RUN apt-get install -y python3-babeltrace python3-lttng python3-pytest python3-pytest-cov python3-pandas +RUN add-apt-repository ppa:lttng/stable-2.13 && \ + apt-get update -q && \ + apt-get install -y lttng-tools lttng-modules-dkms liblttng-ust-dev && \ + apt-get install -y python3-babeltrace python3-lttng python3-pytest \ + python3-pytest-cov python3-pandas ros-foxy-rmw-cyclonedds-cpp && \ + rm -rf /var/lib/apt/lists/* # Python bokeh is not available in the default apt repository # So we install it using pip diff --git a/README.md b/README.md index 19740c0..9d62b0b 100644 --- a/README.md +++ b/README.md @@ -157,3 +157,13 @@ Contributions are welcome! Please follow these steps: ## License Apache License 2.0 - See LICENSE file for details + +--- + +colcon build +# later also just: +colcon build --packages-select full_topology +source install/setup.bash +ros2 launch full_topology trace_full_topology.launch.py +ros2 trace-analysis convert ./analysis/tracing/full_topology_tracing +ros2 trace-analysis process ./analysis/tracing/full_topology_tracing \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..6b64257 --- /dev/null +++ b/build.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +colcon build --packages-select tracetools +source install/setup.bash +colcon build --packages-select rmw_cyclonedds_cpp +source install/setup.bash +colcon build --packages-select rcl rcl_yaml_param_parser +source install/setup.bash +colcon build --packages-select rclcpp +source install/setup.bash +colcon build +source install/setup.bash +export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp diff --git a/colcon_defaults.yaml b/colcon_defaults.yaml index a371b8c..21a4048 100755 --- a/colcon_defaults.yaml +++ b/colcon_defaults.yaml @@ -8,6 +8,8 @@ # clang "-DCMAKE_C_COMPILER=clang-18", "-DCMAKE_CXX_COMPILER=clang++-18", + # no tests + "-DBUILD_TESTING=OFF", ], "event-handlers": ["console_cohesion+"], # "mixin": "clang", diff --git a/debug.sh b/debug.sh new file mode 100755 index 0000000..9aa7ad8 --- /dev/null +++ b/debug.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +export TRACETOOLS_TRACEPOINTS_ENABLED=1 +ros2 run full_topology full_topology & +pid=$! + +sleep 2 +sudo lttng create test --output=/tmp/test +sudo lttng enable-event --userspace 'ros2:rclcpp_publish' +sudo lttng enable-event --userspace 'ros2:rmw_take' +sudo lttng start +sleep 5 # let the node run a bit +sudo lttng stop; sudo lttng destroy +kill $pid + +sudo chown dev: -R /tmp/test + +python - <<'PY' +from tracetools_analysis.loading import load_file +ev = load_file('/tmp/test/ust') +print({e['_name'] for e in ev}) +PY diff --git a/postCreate.sh b/postCreate.sh new file mode 100755 index 0000000..a4384e0 --- /dev/null +++ b/postCreate.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -e + +echo "▶ Setting up tracing overlay workspaces" + +############################################################################### +# 0. fresh terminal +############################################################################### +source /opt/ros/foxy/setup.bash + +############################################################################### +# 1. build the tracing stack only (workspace: trace_ws) +############################################################################### +mkdir -p ~/trace_ws/src && cd ~/trace_ws/src + +git clone -b iron git@github.com:ros2/ros2_tracing.git + +# ament will generate tracetools_config.h with TRACEPOINTS enabled by default +cd ~/trace_ws +colcon build --symlink-install --cmake-args -DBUILD_TESTING=OFF + +# make the new tracetools *override* the distro one for everything we compile +source install/setup.bash +echo "overlay order ✔ (tracetools version = $(pkg-config --modversion tracetools))" + +############################################################################### +# 2. build rclcpp, rcl, rmw… against that new tracetools (core_ws) +############################################################################### +mkdir -p ~/core_ws/src && cd ~/core_ws/src + +git clone -b iron git@github.com:ros2/rosidl_dynamic_typesupport.git +git clone -b iron git@github.com:ros2/rclcpp.git +git clone -b iron git@github.com:ros2/rcl.git +git clone -b iron git@github.com:ros2/rmw.git +git clone -b iron git@github.com:ros2/rmw_fastrtps.git +# add any other core packages you really need (rclcpp_action, rclcpp_components…) + +cd ~/core_ws +colcon build --symlink-install --cmake-args -DBUILD_TESTING=OFF + +############################################################################### +# 3. use it +############################################################################### +source install/setup.bash # rclcpp, rcl… now come from the overlay + +echo "overlay order ✔ (rclcpp version = $(pkg-config --modversion rclcpp))" + +echo "Source the following in your terminal to use the new tracing stack:" +echo "~/trace_ws/install/setup.bash" +echo "~/core_ws/install/setup.bash" diff --git a/src/casestudy/CMakeLists.txt b/src/casestudy/CMakeLists.txt index f5fdb11..8c9e324 100755 --- a/src/casestudy/CMakeLists.txt +++ b/src/casestudy/CMakeLists.txt @@ -13,6 +13,7 @@ endif() # Find dependencies find_package(ament_cmake REQUIRED) +find_package(tracetools REQUIRED) find_package(rclcpp REQUIRED) find_package(priority_executor REQUIRED) find_package(simple_timer REQUIRED) @@ -39,6 +40,7 @@ function(new_experiment experiment_name) # Add dependencies with ament ament_target_dependencies(${experiment_name} + tracetools simple_timer casestudy_tools rclcpp diff --git a/src/casestudy/package.xml b/src/casestudy/package.xml index 3d2c33d..c82d8b6 100755 --- a/src/casestudy/package.xml +++ b/src/casestudy/package.xml @@ -12,6 +12,7 @@ ament_cmake + tracetools rclcpp priority_executor simple_timer diff --git a/src/casestudy_tools/CMakeLists.txt b/src/casestudy_tools/CMakeLists.txt index a56249f..6b4c541 100755 --- a/src/casestudy_tools/CMakeLists.txt +++ b/src/casestudy_tools/CMakeLists.txt @@ -13,6 +13,7 @@ endif() # Find dependencies find_package(ament_cmake REQUIRED) +find_package(tracetools REQUIRED) find_package(rclcpp REQUIRED) find_package(priority_executor REQUIRED) find_package(simple_timer REQUIRED) @@ -26,6 +27,7 @@ target_include_directories(primes_workload PUBLIC $ ) ament_target_dependencies(primes_workload + tracetools simple_timer rclcpp priority_executor @@ -38,6 +40,7 @@ target_include_directories(test_nodes PUBLIC ) target_link_libraries(test_nodes primes_workload) ament_target_dependencies(test_nodes + tracetools rclcpp simple_timer ) @@ -53,6 +56,7 @@ target_link_libraries(experiment_host test_nodes ) ament_target_dependencies(experiment_host + tracetools rclcpp simple_timer priority_executor diff --git a/src/casestudy_tools/package.xml b/src/casestudy_tools/package.xml index 22574e5..33bb1bd 100755 --- a/src/casestudy_tools/package.xml +++ b/src/casestudy_tools/package.xml @@ -11,6 +11,7 @@ ament_cmake + tracetools rclcpp priority_executor simple_timer diff --git a/src/full_topology/CMakeLists.txt b/src/full_topology/CMakeLists.txt index 1ff30a6..b3f816f 100644 --- a/src/full_topology/CMakeLists.txt +++ b/src/full_topology/CMakeLists.txt @@ -16,7 +16,10 @@ find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(std_msgs REQUIRED) +add_compile_definitions(RCLCPP_ENABLE_TRACEPOINTS) + add_executable(${PROJECT_NAME} src/full_topology.cpp) +#add_executable(${PROJECT_NAME} src/test.cpp) target_include_directories(${PROJECT_NAME} PUBLIC $ $ @@ -26,6 +29,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC ament_target_dependencies(${PROJECT_NAME} rclcpp std_msgs + tracetools ) # Installation diff --git a/src/full_topology/launch/trace_full_topology.launch.py b/src/full_topology/launch/trace_full_topology.launch.py index 0c340d9..2a40d95 100644 --- a/src/full_topology/launch/trace_full_topology.launch.py +++ b/src/full_topology/launch/trace_full_topology.launch.py @@ -1,22 +1,60 @@ -from launch import LaunchDescription +import os +import launch +from pathlib import Path from launch_ros.actions import Node from tracetools_launch.action import Trace def generate_launch_description(): - return LaunchDescription([ + length_arg = launch.actions.DeclareLaunchArgument( + 'length', + default_value='60.0', + description='length of execution in seconds', + ) + + file_dir = Path(__file__).resolve().parent + target_path = file_dir.parents[2] / 'analysis' / 'tracing' + + return launch.LaunchDescription([ + length_arg, Trace( session_name='full_topology_tracing', + append_timestamp=True, + base_path=target_path, events_ust=[ - 'rclcpp:*', 'rcl:*', 'rmw:*', 'ros2:*', 'rclcpp:*callback*', 'rclcpp:*executor*' + 'dds:*', + 'ros2:*', + 'rcl:*', + 'rmw:*', + 'rclcpp:*', + 'rclcpp:*callback*', + 'rclcpp:*executor*', + 'rmw_cyclonedds:*', + # explicit list of message‑flow events + 'ros2:rclcpp_publish', + 'ros2:rclcpp_subscription_callback', + 'ros2:rclcpp_timer_callback', + 'ros2:rclcpp_executor_execute', + 'ros2:rclcpp_intra_publish', + 'ros2:rmw_take', + 'ros2:callback_start', + 'ros2:callback_end', + # ---- (optional) add whatever else you like ---- + # scheduling / executor / memory events: + 'ros2:rclcpp_executor_*', + 'ros2:*callback_added', ], events_kernel=[ 'sched_switch', 'sched_wakeup' ], ), - Node( package='full_topology', executable='full_topology', output='screen', ), + # Shut down after some time, otherwise the system would run indefinitely + launch.actions.TimerAction( + period=launch.substitutions.LaunchConfiguration(length_arg.name), + actions=[launch.actions.Shutdown(reason='stopping system')], + ), ]) diff --git a/src/full_topology/package.xml b/src/full_topology/package.xml index 4de6334..0afe9fe 100644 --- a/src/full_topology/package.xml +++ b/src/full_topology/package.xml @@ -17,6 +17,7 @@ rclcpp std_msgs + tracetools ament_copyright ament_flake8 diff --git a/src/full_topology/src/full_topology.cpp b/src/full_topology/src/full_topology.cpp index 84b373a..41689c3 100644 --- a/src/full_topology/src/full_topology.cpp +++ b/src/full_topology/src/full_topology.cpp @@ -5,12 +5,14 @@ #include #include #include -#include "rclcpp/rclcpp.hpp" +// the order here matters +#include "tracetools/utils.hpp" + +#include #include "std_msgs/msg/string.hpp" using namespace std::chrono_literals; -constexpr int RUN_DURATION_SECONDS = 20; constexpr bool DEBUG = false; // A generic sensor node that publishes at a given rate @@ -138,12 +140,13 @@ public: RCLCPP_INFO(get_logger(), "%s received: %s", name.c_str(), msg->data.c_str()); } + /* TODO // random: 1 in 5 it will be 10s instead of delay_ms if (rand() % 5 == 0) { std::this_thread::sleep_for(std::chrono::milliseconds(10000)); } else { std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms)); - } + }*/ // Custom transformation of data auto out = std_msgs::msg::String(); @@ -255,6 +258,7 @@ int main(int argc, char **argv) auto fusion = std::make_shared( "sensor_fusion_node", std::vector{"/gps/fix", "/imu/data", "/baro/alt"}, "/sensors/fused", 10); auto lidar = std::make_shared("lidar_node", "/lidar/scan", 15); + // TODO: operator or autonomous flight plan auto cmd = std::make_shared("operator_cmd_node", "/operator/commands", 1); auto mgmt = std::make_shared( "flight_mgmt_node", std::vector{"/sensors/fused", "/lidar/scan", "/operator/commands"}, "/flight/plan", 20); @@ -283,13 +287,7 @@ int main(int argc, char **argv) executor.add_node(telemetry); executor.add_node(radio); - // ToDo: find a better way to handle time limited executions - auto start_time = std::chrono::steady_clock::now(); - while (rclcpp::ok() && (std::chrono::steady_clock::now() - start_time) < std::chrono::seconds(RUN_DURATION_SECONDS)) - { - executor.spin_some(); - std::this_thread::sleep_for(1ms); - } + executor.spin(); rclcpp::shutdown(); return 0; diff --git a/src/full_topology/src/test.cpp b/src/full_topology/src/test.cpp new file mode 100644 index 0000000..1a3f3e9 --- /dev/null +++ b/src/full_topology/src/test.cpp @@ -0,0 +1,9 @@ +#include "tracetools/utils.hpp" +#include + +int main(int argc, char** argv) { + rclcpp::init(argc, argv); + auto node = std::make_shared("test_node"); + rclcpp::shutdown(); + return 0; +} \ No newline at end of file diff --git a/src/rcl b/src/rcl new file mode 160000 index 0000000..5da7e19 --- /dev/null +++ b/src/rcl @@ -0,0 +1 @@ +Subproject commit 5da7e193371c25cf1ebd2489978768327c382c04 diff --git a/src/rclcpp b/src/rclcpp new file mode 160000 index 0000000..e57a3a3 --- /dev/null +++ b/src/rclcpp @@ -0,0 +1 @@ +Subproject commit e57a3a393e46f0c0e0e5cc64090ac34e5cef32bc diff --git a/src/rmw_cyclonedds b/src/rmw_cyclonedds new file mode 160000 index 0000000..79e0792 --- /dev/null +++ b/src/rmw_cyclonedds @@ -0,0 +1 @@ +Subproject commit 79e07924d66b205838d28da4c9df6a941df6795c diff --git a/src/ros2_tracing b/src/ros2_tracing new file mode 160000 index 0000000..c0a5cf2 --- /dev/null +++ b/src/ros2_tracing @@ -0,0 +1 @@ +Subproject commit c0a5cf2d1dc8706a62bae59123e2c71a6707ac33 diff --git a/src/ros2trace b/src/ros2trace deleted file mode 120000 index c5f88e9..0000000 --- a/src/ros2trace +++ /dev/null @@ -1 +0,0 @@ -tools/ros2_tracing/ros2trace \ No newline at end of file diff --git a/src/ros2trace_analysis b/src/ros2trace_analysis deleted file mode 120000 index c82add4..0000000 --- a/src/ros2trace_analysis +++ /dev/null @@ -1 +0,0 @@ -tools/tracetools_analysis/ros2trace_analysis \ No newline at end of file diff --git a/src/ros_edf b/src/ros_edf index d7ecdf0..c44b7b8 160000 --- a/src/ros_edf +++ b/src/ros_edf @@ -1 +1 @@ -Subproject commit d7ecdf0108d8decdda33b6dd7fb1bbc5f1d3ac43 +Subproject commit c44b7b8c3c527a8d16739349b50340a7de9b6f51 diff --git a/src/simple_topology/CMakeLists.txt b/src/simple_topology/CMakeLists.txt index 027a67f..bfc47b6 100644 --- a/src/simple_topology/CMakeLists.txt +++ b/src/simple_topology/CMakeLists.txt @@ -13,6 +13,7 @@ endif() # find dependencies find_package(ament_cmake REQUIRED) +find_package(tracetools REQUIRED) find_package(rclcpp REQUIRED) find_package(std_msgs REQUIRED) @@ -24,6 +25,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC # Add dependencies with ament ament_target_dependencies(${PROJECT_NAME} + tracetools rclcpp std_msgs ) diff --git a/src/simple_topology/package.xml b/src/simple_topology/package.xml index 2ec3890..22cfbca 100644 --- a/src/simple_topology/package.xml +++ b/src/simple_topology/package.xml @@ -11,6 +11,7 @@ launch launch_ros + tracetools tracetools_trace tracetools_launch diff --git a/src/tools/ros2_tracing b/src/tools/ros2_tracing deleted file mode 160000 index 449a012..0000000 --- a/src/tools/ros2_tracing +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 449a0123fd12032519ca6bea2209cc0505304771 diff --git a/src/tools/tracetools_analysis b/src/tools/tracetools_analysis deleted file mode 160000 index d99bb40..0000000 --- a/src/tools/tracetools_analysis +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d99bb4041665d77d6f9502d614af498d31d7b6de diff --git a/src/tracetools b/src/tracetools deleted file mode 120000 index 30b8302..0000000 --- a/src/tracetools +++ /dev/null @@ -1 +0,0 @@ -tools/ros2_tracing/tracetools \ No newline at end of file diff --git a/src/tracetools_analysis b/src/tracetools_analysis deleted file mode 120000 index 32def9e..0000000 --- a/src/tracetools_analysis +++ /dev/null @@ -1 +0,0 @@ -tools/tracetools_analysis/tracetools_analysis \ No newline at end of file diff --git a/src/tracetools_analysis b/src/tracetools_analysis new file mode 160000 index 0000000..0feb705 --- /dev/null +++ b/src/tracetools_analysis @@ -0,0 +1 @@ +Subproject commit 0feb705d5bf8e3578a28a6a5f9397695228c2f26 diff --git a/src/tracetools_launch b/src/tracetools_launch deleted file mode 120000 index 52a5f7f..0000000 --- a/src/tracetools_launch +++ /dev/null @@ -1 +0,0 @@ -tools/ros2_tracing/tracetools_launch \ No newline at end of file diff --git a/src/tracetools_read b/src/tracetools_read deleted file mode 120000 index 7899a84..0000000 --- a/src/tracetools_read +++ /dev/null @@ -1 +0,0 @@ -tools/ros2_tracing/tracetools_read \ No newline at end of file diff --git a/src/tracetools_test b/src/tracetools_test deleted file mode 120000 index 883d309..0000000 --- a/src/tracetools_test +++ /dev/null @@ -1 +0,0 @@ -tools/ros2_tracing/tracetools_test \ No newline at end of file diff --git a/src/tracetools_trace b/src/tracetools_trace deleted file mode 120000 index 7975110..0000000 --- a/src/tracetools_trace +++ /dev/null @@ -1 +0,0 @@ -tools/ros2_tracing/tracetools_trace \ No newline at end of file