monitor.cpp
Go to the documentation of this file.
1 // Monitors execution of a launch file
2 // Author: Max Schwarz <max.schwarz@uni-bonn.de>
3 
4 #include "monitor.h"
5 
6 #include <ros/package.h>
7 #include <ros/node_handle.h>
8 #include <ros/param.h>
9 
10 #include <cstdarg>
11 #include <cstdio>
12 #include <fstream>
13 
14 #include <boost/regex.hpp>
15 #include <boost/algorithm/string/trim.hpp>
16 #include <boost/filesystem.hpp>
17 
18 #include <yaml-cpp/yaml.h>
19 
20 #include <fmt/format.h>
21 
22 #include "linux_process_info.h"
23 
24 template<typename... Args>
25 std::runtime_error error(const char* fmt, const Args& ... args)
26 {
27  return std::runtime_error(fmt::format(fmt, args...));
28 }
29 
30 namespace rosmon
31 {
32 namespace monitor
33 {
34 
36  : m_config(std::move(config))
37  , m_fdWatcher(std::move(watcher))
38  , m_ok(true)
39 {
40  for(auto& launchNode : m_config->nodes())
41  {
42  auto node = std::make_shared<NodeMonitor>(launchNode, m_fdWatcher, m_nh);
43 
44  node->logMessageSignal.connect(logMessageSignal);
45 
46  if(launchNode->required())
47  {
48  node->exitedSignal.connect(
49  boost::bind(&Monitor::handleRequiredNodeExit, this, _1)
50  );
51  }
52 
53  m_nodes.push_back(node);
54  }
55 
56 #if HAVE_STEADYTIMER
58 #else
60 #endif
61  ros::WallDuration(1.0),
62  boost::bind(&Monitor::updateStats, this, _1)
63  );
64 }
65 
67 {
68  {
69  std::vector<std::string> paramNames;
70 
71  for(auto& node : m_config->nodes())
72  {
73  if(node->clearParams())
74  {
75  std::string paramNamespace = node->namespaceString() + "/" + node->name() + "/";
76 
77  logTyped(LogEvent::Type::Info, "Deleting parameters in namespace {}", paramNamespace.c_str());
78 
79  if(paramNames.empty())
80  {
81  if(!ros::param::getParamNames(paramNames))
82  throw error("Could not get list of parameters for clear_param");
83  }
84 
85  for(auto& param : paramNames)
86  {
87  if(param.substr(0, paramNamespace.length()) == paramNamespace)
88  {
90  }
91  }
92  }
93  }
94  }
95 
96  for(auto& param : m_config->parameters())
97  m_nh.setParam(param.first, param.second);
98 }
99 
101 {
102  for(auto& node : m_nodes)
103  {
104  node->start();
105  }
106 }
107 
109 {
110  for(auto& node : m_nodes)
111  node->shutdown();
112 }
113 
115 {
116  logTyped(LogEvent::Type::Warning, "Killing the following nodes, which are refusing to exit:\n");
117  for(auto& node : m_nodes)
118  {
119  if(node->running())
120  {
121  logTyped(LogEvent::Type::Warning, " - {}\n", node->name());
122  node->forceExit();
123  }
124  }
125 }
126 
128 {
129  bool allShutdown = true;
130  for(auto& node : m_nodes)
131  {
132  if(node->running())
133  allShutdown = false;
134  }
135 
136  return allShutdown;
137 }
138 
140 {
141  double timeout = 0.0;
142  // Find the biggest timeout
143  for(auto& node : m_nodes)
144  if(node->stopTimeout() > timeout)
145  timeout = node->stopTimeout();
146  return timeout;
147 }
148 
149 
150 void Monitor::handleRequiredNodeExit(const std::string& name)
151 {
152  logTyped(LogEvent::Type::Info, "Required node '{}' exited, shutting down...", name);
153  m_ok = false;
154 }
155 
156 template<typename... Args>
157 void Monitor::log(const char* fmt, Args&& ... args)
158 {
160  "[rosmon]",
161  fmt::format(fmt, std::forward<Args>(args)...)
162  });
163 }
164 
165 template<typename... Args>
166 void Monitor::logTyped(LogEvent::Type type, const char* fmt, Args&& ... args)
167 {
169  "[rosmon]",
170  fmt::format(fmt, std::forward<Args>(args)...),
171  type
172  });
173 }
174 
175 #if HAVE_STEADYTIMER
177 #else
179 #endif
180 {
181  namespace fs = boost::filesystem;
182 
183  fs::directory_iterator it("/proc");
184  fs::directory_iterator end;
185 
186  std::map<int, NodeMonitor::Ptr> nodeMap;
187  for(auto& node : m_nodes)
188  {
189  if(node->pid() != -1)
190  nodeMap[node->pid()] = node;
191 
192  node->beginStatUpdate();
193  }
194 
195  for(auto& procInfo : m_processInfos)
196  procInfo.second.active = false;
197 
198  for(; it != end; ++it)
199  {
200  fs::path statPath = (*it) / "stat";
201 
203  if(!process_info::readStatFile(statPath.c_str(), &stat))
204  continue;
205 
206  // Find corresponding node by the process group ID
207  // (= process ID of the group leader process)
208  auto it = nodeMap.find(stat.pgrp);
209  if(it == nodeMap.end())
210  continue;
211 
212  auto& node = it->second;
213 
214  // We need to store the stats and subtract the last one to get a time
215  // delta
216  auto infoIt = m_processInfos.find(stat.pid);
217  if(infoIt == m_processInfos.end())
218  {
219  ProcessInfo info;
220  info.stat = stat;
221  info.active = true;
222  m_processInfos[stat.pid] = info;
223  continue;
224  }
225 
226  const auto& oldStat = infoIt->second.stat;
227 
228  node->addCPUTime(stat.utime - oldStat.utime, stat.stime - oldStat.stime);
229  node->addMemory(stat.mem_rss);
230 
231  infoIt->second.active = true;
232  infoIt->second.stat = stat;
233  }
234 
235  double elapsedTime = (event.current_real - event.last_real).toSec();
236 
237  for(auto& node : m_nodes)
238  node->endStatUpdate(elapsedTime * process_info::kernel_hz());
239 
240  // Clean up old processes
241  for(auto it = m_processInfos.begin(); it != m_processInfos.end();)
242  {
243  if(!it->second.active)
244  it = m_processInfos.erase(it);
245  else
246  it++;
247  }
248 }
249 
250 }
251 }
ros::WallTimer m_statTimer
Definition: monitor.h:83
ROSCPP_DECL bool getParamNames(std::vector< std::string > &keys)
boost::signals2::signal< void(LogEvent)> logMessageSignal
Definition: monitor.h:49
bool param(const std::string &param_name, T &param_val, const T &default_val)
jiffies_t stime
Total time spent in kernel space.
std::runtime_error error(const char *fmt, const Args &...args)
Definition: monitor.cpp:25
std::map< int, ProcessInfo > m_processInfos
Definition: monitor.h:86
process_info::ProcessStat stat
Definition: monitor.h:53
void log(const char *fmt, Args &&...args)
Definition: monitor.cpp:157
bool readStatFile(const char *filename, ProcessStat *stat)
SteadyTimer createSteadyTimer(WallDuration period, void(T::*callback)(const SteadyTimerEvent &), T *obj, bool oneshot=false, bool autostart=true) const
std::vector< NodeMonitor::Ptr > m_nodes
Definition: monitor.h:76
Monitor(launch::LaunchConfig::ConstPtr config, FDWatcher::Ptr watcher)
Definition: monitor.cpp:35
WallTimer createWallTimer(WallDuration period, void(T::*callback)(const WallTimerEvent &), T *obj, bool oneshot=false, bool autostart=true) const
void logTyped(LogEvent::Type type, const char *fmt, Args &&...args)
Definition: monitor.cpp:166
ros::NodeHandle m_nh
Definition: monitor.h:73
FDWatcher::Ptr m_fdWatcher
Definition: monitor.h:74
std::shared_ptr< const LaunchConfig > ConstPtr
ROSCPP_DECL bool del(const std::string &key)
jiffies_t utime
Total time spent in userspace.
jiffies_t kernel_hz()
Number of kernel jiffies per second.
std::size_t mem_rss
Resident memory size in bytes.
void handleRequiredNodeExit(const std::string &name)
Definition: monitor.cpp:150
void updateStats(const ros::WallTimerEvent &event)
Definition: monitor.cpp:178
launch::LaunchConfig::ConstPtr m_config
Definition: monitor.h:71
unsigned long pgrp
Process group ID.
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const


rosmon_core
Author(s): Max Schwarz
autogenerated on Sat Jan 9 2021 03:35:43