Carma-platform v4.2.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
monitor-ros-cpu.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2import psutil
3import time
4import csv
5import os
6import argparse
7from datetime import datetime
8
9"""
10CARMA Platform CPU Monitor Script
11Requirements:
12 - Python 3.6 or higher
13 - psutil package (install with: pip3 install psutil)
14Usage:
15 1. Open a new terminal before starting CARMA Platform
16 2. Navigate to the directory containing this script:
17 cd /path/to/script/
18 3. Run this script:
19 python3 monitor-ros-cpu.py
20 4. In a different terminal, start CARMA Platform:
21 carma start all
22 5. The script will automatically monitor and log CPU/memory usage
23 of all ROS2 nodes and related processes during CARMA operation
24 6. To stop monitoring:
25 - Press Ctrl+C ONCE in the monitoring terminal
26 - The CSV output file will be saved in the logs directory following ROS bag naming convention:
27 'logs/cpu_usage_ros2_nodes_YYYY_MM_DD-HH_MM_SS.csv'
28Output:
29 - CSV file containing timestamp, process info, CPU and memory usage
30 - Data can be used to analyze CARMA Platform resource utilization
31"""
32
33# Define ROS-related keywords to filter processes
34ROS_KEYWORDS = {
35 "ros",
36 "node",
37 "rviz",
38 "rqt",
39 "/opt/ros/", # ROS installation path
40 "/opt/carma/", # CARMA ROS installation path
41 "roscore",
42 "rosmaster",
43 "roslaunch",
44 "rostopic",
45 "rosnode",
46 "rosbag",
47 "ros2",
48 "ros1_bridge",
49 "rmw", # ROS middleware
50 "fastrtps",
51 "cyclonedds",
52 "rclcpp",
53 "rclpy",
54 "noetic",
55 "foxy",
56 "humble",
57}
58
59# Define processes to exclude (to avoid false positives)
60# NOTE: Detection of these keywords overwrites the ROS_KEYWORDS
61EXCLUDE_KEYWORDS = {"code", "chrome", "firefox", "vscode", "gnome"}
62
63
65 parser = argparse.ArgumentParser(description="Monitor CPU usage of ROS2 nodes")
66 parser.add_argument(
67 "--output-dir",
68 "-o",
69 default="carma-cpu-usage-logs",
70 help="Directory to store output files (default: carma-cpu-usage-logs)",
71 )
72 parser.add_argument(
73 "--include-pattern",
74 "-i",
75 help="Additional comma-separated patterns to include in process filtering",
76 )
77 return parser.parse_args()
78
79
81 if not os.path.exists(output_dir):
82 os.makedirs(output_dir)
83 timestamp = datetime.now().strftime("%Y_%m_%d-%H_%M_%S")
84 filename = f"cpu_usage_ros2_nodes_{timestamp}.csv"
85 return os.path.join(output_dir, filename)
86
87
88def is_ros_related_process(proc_info, cmdline):
89 """
90 Check if a process is ROS-related based on name and command line
91 """
92 # Convert process information to lowercase for case-insensitive matching
93 name_lower = proc_info["name"].lower()
94 cmdline_lower = cmdline.lower()
95
96 # Check exclusions first
97 if any(excl in name_lower or excl in cmdline_lower for excl in EXCLUDE_KEYWORDS):
98 return False
99
100 # Check for ROS-related keywords in process name and command line
101 return any(
102 keyword in name_lower or keyword in cmdline_lower for keyword in ROS_KEYWORDS
103 )
104
105
107 """
108 Try to get ROS-related environment variables for a process
109 """
110 try:
111 proc = psutil.Process(pid)
112 env = proc.environ()
113 ros_env = {k: v for k, v in env.items() if "ROS" in k}
114 return bool(ros_env)
115 except (psutil.NoSuchProcess, psutil.AccessDenied):
116 return False
117
118
119def main():
120 args = parse_args()
121
122 # Add any additional include patterns from command line
123 if args.include_pattern:
124 additional_patterns = set(args.include_pattern.split(","))
125 ROS_KEYWORDS.update(additional_patterns)
126
127 output_file = setup_logging_directory(args.output_dir)
128
129 with open(output_file, mode="a") as file:
130 writer = csv.writer(file)
131 writer.writerow(
132 [
133 "Timestamp",
134 "PID",
135 "Process Name",
136 "CPU (%)",
137 "Memory (%)",
138 "Command Line",
139 "Total CPU (%)",
140 "Total CPU Num",
141 "Total Memory (%)",
142 "Total Memory (GB)",
143 ]
144 )
145
146 print(f"Starting to monitor the CPU usage data and saving to: {output_file}")
147
148 # Total CPU and memory size in GB doesn't change
149 total_memory_gb = psutil.virtual_memory().total / (1024**3)
150 total_cpus = os.cpu_count()
151
152 while True:
153 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
154 total_cpu_percent = psutil.cpu_percent(interval=None)
155 total_memory_percent = (
156 psutil.virtual_memory().percent
157 ) # Get total memory usage
158
159 for proc in psutil.process_iter(
160 ["pid", "name", "cpu_percent", "memory_percent", "cmdline"]
161 ):
162 try:
163 cmdline = (
164 " ".join(proc.info["cmdline"]) if proc.info["cmdline"] else ""
165 )
166
167 if is_ros_related_process(proc.info, cmdline):
168 pid = proc.info["pid"]
169 name = proc.info["name"]
170 cpu_percent = proc.info["cpu_percent"]
171 memory_percent = proc.info["memory_percent"]
172
173 writer.writerow(
174 [
175 timestamp,
176 pid,
177 name,
178 cpu_percent,
179 memory_percent,
180 cmdline,
181 total_cpu_percent,
182 total_cpus,
183 total_memory_percent,
184 total_memory_gb,
185 ]
186 )
187
188 except (
189 psutil.NoSuchProcess,
190 psutil.AccessDenied,
191 psutil.ZombieProcess,
192 ):
193 continue
194
195 time.sleep(1)
196
197
198if __name__ == "__main__":
199 main()
def is_ros_related_process(proc_info, cmdline)
def get_process_environment(pid)
def setup_logging_directory(output_dir)