ProcessWatcher.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package ArmarX::
19 * @author Mirko Waechter ( mirko.waechter at kit dot edu)
20 * @date 2013
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24 
25 #include <IceUtil/Handle.h> // for HandleBase
26 
27 #include <SimoxUtility/algorithm/string/string_tools.h>
28 
29 #include <ctype.h> // for isspace
30 #include <ext/alloc_traits.h>
31 
32 #include <memory> // for allocator, operator==
33 #include <sstream> // for operator<<, ifstream, etc
34 #include <fstream>
35 #include <unordered_set>
36 
37 #include "ArmarXCore/core/logging/LogSender.h" // for LogSender
38 #include "ArmarXCore/core/logging/Logging.h" // for ARMARX_WARNING_S
41 #include "ArmarXCore/interface/core/ThreadingIceBase.h" // for upCast
42 
43 #include "../exceptions/local/ExpressionException.h"
44 
45 #include "ProcessWatcher.h"
46 
47 #include <sys/utsname.h> // for uname, utsname
48 #include <malloc.h> // for mallinfo
49 #include <unistd.h> // for sysconf, _SC_CLK_TCK
50 
51 namespace armarx
52 {
54  profiler(profiler)
55  {
56  long pid = LogSender::getProcessId();
57  Hertz = sysconf(_SC_CLK_TCK);
58  std::stringstream ss;
59  ss << "/proc/" << pid << "/stat";
60  processCpuDataFilename = ss.str();
61  processCpuUsage.processId = pid;
62  cpuUsageFromProcFile();
63  }
64 
66  {
67  if (!watcherTask)
68  {
69  watcherTask = new PeriodicTask<ProcessWatcher>(this, &ProcessWatcher::watch, 300, false);
70  }
71 
72  watcherTask->start();
73  }
74 
76  {
77  watcherTask->stop();
78  watcherTask = nullptr;
79  }
80 
81  void ProcessWatcher::addThread(int processId, int threadId)
82  {
84  std::unique_lock lock(threadWatchListMutex);
85  ThreadUsage usage;
86  usage.processId = processId;
87  usage.threadId = threadId;
88  usage.lastJiffies = GetThreadJiffies(processId, threadId);
89  usage.lastUpdate = IceUtil::Time::now();
90  usage.load = 0;
91  threadWatchList.insert(usage);
92  }
93 
94  void ProcessWatcher::addThread(int threadId)
95  {
97  }
98 
99  void ProcessWatcher::watch()
100  {
101  ARMARX_TRACE;
102  runThreadWatchList();
103  cpuUsageFromProcFile();
104  getMemoryUsage();
105  reportCpuUsage();
107  }
108 
109  void ProcessWatcher::runThreadWatchList()
110  {
111  ARMARX_TRACE;
112  std::unique_lock lock(threadWatchListMutex);
113  std::unordered_set<ThreadUsage> newset;
114  std::unordered_set<ThreadUsage>::iterator it = threadWatchList.begin();
115 
116  for (; it != threadWatchList.end(); it++)
117  {
118  ARMARX_TRACE;
119  ThreadUsage usage = *it;
120  IceUtil::Time queryTime = IceUtil::Time::now();
121  int curJiffies = GetThreadJiffies(usage.processId, usage.threadId);
122 
123  if (GetHertz() != -1)
124  {
125  usage.load = (curJiffies - usage.lastJiffies) / ((queryTime - usage.lastUpdate).toSecondsDouble() * GetHertz());
126  }
127  else
128  {
129  usage.load = 0;
130  }
131 
132  usage.lastJiffies = curJiffies;
133  usage.lastUpdate = queryTime;
134  newset.insert(usage);
135  }
136 
137  threadWatchList.swap(newset);
138  }
139 
140 
141 #if !defined(_WIN32) && !defined(__APPLE__)
143  {
144  ARMARX_TRACE;
145  static std::mutex mutex;
146  std::unique_lock lock(mutex);
147  static int value = -2;
148 
149  if (value == -2) // init value
150  {
151  ARMARX_TRACE;
152  static std::string _release;
153 
154  if (_release.empty())
155  {
156  struct utsname utsinfo;
157  uname(&utsinfo);
158  _release = utsinfo.release;
159  }
160 
161  std::string fileName = "/boot/config-" + _release;
162  std::ifstream configFile(fileName.c_str());
163 
164  ARMARX_TRACE;
165  // procFile.open(fileName, ios::out);
166  if (!configFile.is_open())
167  {
168  ARMARX_WARNING_S << "Cannot open " << fileName << " for reading the cpu hertz value";
169  value = -1;
170  }
171  else
172  {
173  value = -1;
174  std::string line;
175  const std::string searchString = "CONFIG_HZ=";
176 
177  while (getline(configFile, line))
178  {
179  ARMARX_TRACE;
180  std::size_t pos = line.find(searchString);
181 
182  if (pos != std::string::npos)
183  {
184  std::string hzString = line.substr(pos + searchString.length());
185  value = std::stoi(hzString);
186  break;
187  }
188  }
189  }
190  }
191 
192  return value;
193 
194 
195  }
196 
197  void ProcessWatcher::cpuUsageFromProcFile()
198  {
199  ARMARX_TRACE;
200  std::string line;
201 
202  std::ifstream file(processCpuDataFilename);
203 
204  if (!file.is_open())
205  {
206  ARMARX_WARNING_S << "File " << processCpuDataFilename << " does not exist";
207  }
208 
209 
210  std::getline(file, line);
211  file.close();
212 
213  std::vector<std::string> pidElements = simox::alg::split(line, "\t ");
214 
215  int currentUtime = std::stoi(pidElements.at(eUTime));
216  int currentStime = std::stoi(pidElements.at(eSTime));
217 
218  int currentCUtime = std::stoi(pidElements.at(eCUTIME));
219  int currentCStime = std::stoi(pidElements.at(eCSTIME));
220  {
221  ARMARX_TRACE;
222  std::unique_lock guard{processCpuUsageMutex};
223 
224  IceUtil::Time queryTime = IceUtil::Time::now();
225 
226  processCpuUsage.proc_total_time = 100 * (double)((currentStime + currentCStime - processCpuUsage.lastStime - processCpuUsage.lastCStime) + (currentUtime + currentCUtime - processCpuUsage.lastCUtime - processCpuUsage.lastUtime)) / ((queryTime - processCpuUsage.lastUpdate).toSecondsDouble() * Hertz);
227 
228  processCpuUsage.lastUpdate = queryTime;
229  processCpuUsage.lastUtime = currentUtime;
230  processCpuUsage.lastStime = currentStime;
231 
232  processCpuUsage.lastCUtime = currentCUtime;
233  processCpuUsage.lastCStime = currentCStime;
234  }
235  }
236 
237  void ProcessWatcher::getMemoryUsage()
238  {
239  ARMARX_TRACE;
240  struct mallinfo _mallinfo;
241 
242  _mallinfo = mallinfo();
243 
244  {
245  std::unique_lock guard{processMemoryUsageMutex};
246  memoryUsage.fastbinBlocks = _mallinfo.fsmblks;
247  memoryUsage.totalAllocatedSpace = _mallinfo.uordblks;
248  memoryUsage.totalFreeSpace = _mallinfo.fordblks;
249 
250  }
251 
252  }
253 
254 
255  std::map<int, int> ProcessWatcher::GetThreadListJiffies(int processId, std::vector<int> threadIds)
256  {
257  ARMARX_TRACE;
258  std::map<int, int> resultMap;
259  for (int threadId : threadIds)
260  {
261  ARMARX_TRACE;
262  resultMap[threadId] = 0;
263  std::stringstream fileName;
264  fileName << "/proc/" << threadId << "/task/" << threadId << "/stat";
265  std::ifstream statFile(fileName.str().c_str());
266 
267  if (!statFile.is_open())
268  {
269  ARMARX_WARNING_S << "Cannot open " << fileName.str() << " for reading the hertz value";
270  resultMap[threadId] = 0;
271  continue;
272  }
273 
274  std::string line;
275 
276  while (getline(statFile, line))
277  {
278  ARMARX_TRACE;
279  simox::alg::trim(line);
280 
281  std::vector<std::string> stringVec = simox::alg::split(line, " ");
282 
283  ARMARX_CHECK_LESS(14, stringVec.size());
284  int userTimeJiffies = atoi(stringVec.at(13).c_str());
285  int kernelTimeJiffies = atoi(stringVec.at(14).c_str());
286 
287  resultMap[threadId] = userTimeJiffies + kernelTimeJiffies;
288  }
289  }
290 
291  return resultMap;
292  }
293 #else
294 
296  {
297  return -1;
298  }
299 
300  std::map<int, int> ProcessWatcher::GetThreadListJiffies(int processId, std::vector<int> threadIds)
301  {
302  return std::map<int, int>();
303  }
304 
305  void ProcessWatcher::cpuUsageFromProcFile()
306  {
307  }
308 
309  void ProcessWatcher::getMemoryUsage()
310  {
311  }
312 
313 #endif
314 
315  bool ThreadUsage::operator <(const ThreadUsage& rhs) const
316  {
317  if (processId < rhs.processId)
318  {
319  return true;
320  }
321 
322  if (threadId < rhs.threadId)
323  {
324  return true;
325  }
326 
327  return false;
328  }
329 
330  bool ThreadUsage::operator ==(const ThreadUsage& rhs) const
331  {
332  if (processId == rhs.processId && threadId == rhs.threadId)
333  {
334  return true;
335  }
336 
337  return false;
338  }
339 
340  int ProcessWatcher::GetThreadJiffies(int processId, int threadId)
341  {
342  ARMARX_TRACE;
343  std::map<int, int> result = GetThreadListJiffies(processId, std::vector<int>(1, threadId));
344  std::map<int, int>::iterator it = result.find(threadId);
345 
346  if (it == result.end())
347  {
348  return 0;
349  }
350 
351  return it->second;
352  }
353 
354 
356  {
357  std::unique_lock guard{processCpuUsageMutex};
358  profiler->logProcessCpuUsage(processCpuUsage.proc_total_time);
359  }
360 
362  {
363  std::unique_lock guard{processMemoryUsageMutex};
364  profiler->logProcessMemoryUsage(memoryUsage.totalFreeSpace);
365  }
366 
367  double ProcessWatcher::getThreadLoad(int threadId)
368  {
369  return getThreadLoad(LogSender::getProcessId(), threadId);
370  }
371 
372 
373  double ProcessWatcher::getThreadLoad(int processId, int threadId)
374  {
375  ARMARX_TRACE;
376  ThreadUsage query;
377  query.processId = processId;
378  query.threadId = threadId;
379  std::unique_lock lock(threadWatchListMutex);
380  auto it = threadWatchList.find(query);
381 
382  ARMARX_TRACE;
383  if (it != threadWatchList.end())
384  {
385  return it->load * 100;
386  }
387  else
388  {
389  return 0.0;
390  }
391  }
392 
394  {
395  std::unique_lock guard{processCpuUsageMutex};
396  return processCpuUsage;
397  }
398 
399 
400  void ProcessWatcher::removeThread(int processId, int threadId)
401  {
402  ARMARX_TRACE;
403  ThreadUsage query;
404  query.processId = processId;
405  query.threadId = threadId;
406  std::unique_lock lock(threadWatchListMutex);
407  threadWatchList.erase(query);
408  }
409 
410  void ProcessWatcher::removeThread(int threadId)
411  {
413  }
414 }
armarx::ProcessWatcher::stop
void stop()
Definition: ProcessWatcher.cpp:75
armarx::CpuUsage::lastCUtime
int lastCUtime
Definition: ProcessWatcher.h:55
armarx::ThreadUsage::lastUpdate
IceUtil::Time lastUpdate
Definition: ProcessWatcher.h:43
ProcessWatcher.h
armarx::CpuUsage
Definition: ProcessWatcher.h:50
armarx::ProcessWatcher::GetThreadJiffies
static int GetThreadJiffies(int processId, int threadId)
Definition: ProcessWatcher.cpp:340
armarx::ProcessWatcher::GetHertz
static int GetHertz()
Definition: ProcessWatcher.cpp:142
armarx::ProcessWatcher::reportMemoryUsage
void reportMemoryUsage()
Definition: ProcessWatcher.cpp:361
armarx::MemoryUsage::fastbinBlocks
int fastbinBlocks
Definition: ProcessWatcher.h:63
armarx::ProcessWatcher::getThreadLoad
double getThreadLoad(int processId, int threadId)
Definition: ProcessWatcher.cpp:373
PeriodicTask.h
ARMARX_CHECK_LESS
#define ARMARX_CHECK_LESS(lhs, rhs)
This macro evaluates whether lhs is less (<) than rhs and if it turns out to be false it will throw a...
Definition: ExpressionException.h:102
armarx::ProcessWatcher::removeThread
void removeThread(int processId, int threadId)
Definition: ProcessWatcher.cpp:400
armarx::ThreadUsage::operator<
bool operator<(const ThreadUsage &rhs) const
Definition: ProcessWatcher.cpp:315
ARMARX_TRACE
#define ARMARX_TRACE
Definition: trace.h:69
armarx::CpuUsage::proc_total_time
double proc_total_time
Definition: ProcessWatcher.h:58
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:926
armarx::CpuUsage::lastStime
int lastStime
Definition: ProcessWatcher.h:54
armarx::ProcessWatcher::ProcessWatcher
ProcessWatcher(Profiler::ProfilerPtr profiler)
Definition: ProcessWatcher.cpp:53
armarx::ProcessWatcher::GetThreadListJiffies
static std::map< int, int > GetThreadListJiffies(int processId, std::vector< int > threadIds)
Definition: ProcessWatcher.cpp:255
armarx::ThreadUsage::processId
int processId
Definition: ProcessWatcher.h:42
armarx::ProcessWatcher::addThread
void addThread(int processId, int threadId)
Definition: ProcessWatcher.cpp:81
armarx::ThreadUsage::load
double load
Definition: ProcessWatcher.h:45
ARMARX_WARNING_S
#define ARMARX_WARNING_S
Definition: Logging.h:206
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::ProcessWatcher::getProcessCpuUsage
armarx::CpuUsage getProcessCpuUsage()
Definition: ProcessWatcher.cpp:393
armarx::CpuUsage::lastUtime
int lastUtime
Definition: ProcessWatcher.h:53
armarx::LogSender::getProcessId
static long getProcessId()
Definition: LogSender.cpp:452
armarx::CpuUsage::lastCStime
int lastCStime
Definition: ProcessWatcher.h:56
armarx::ThreadUsage::lastJiffies
int lastJiffies
Definition: ProcessWatcher.h:44
armarx::CpuUsage::processId
long processId
Definition: ProcessWatcher.h:52
Profiler.h
armarx::ThreadUsage::threadId
int threadId
Definition: ProcessWatcher.h:41
armarx::MemoryUsage::totalAllocatedSpace
int totalAllocatedSpace
Definition: ProcessWatcher.h:64
LogSender.h
armarx::Profiler::ProfilerPtr
std::shared_ptr< Profiler > ProfilerPtr
Definition: ManagedIceObject.h:75
armarx::ProcessWatcher::reportCpuUsage
void reportCpuUsage()
Definition: ProcessWatcher.cpp:355
armarx::ProcessWatcher::start
void start()
Definition: ProcessWatcher.cpp:65
armarx::PeriodicTask
Definition: ArmarXManager.h:70
Logging.h
armarx::ThreadUsage
Definition: ProcessWatcher.h:39
armarx::MemoryUsage::totalFreeSpace
int totalFreeSpace
Definition: ProcessWatcher.h:65
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::CpuUsage::lastUpdate
IceUtil::Time lastUpdate
Definition: ProcessWatcher.h:57
armarx::ThreadUsage::operator==
bool operator==(const ThreadUsage &rhs) const
Definition: ProcessWatcher.cpp:330
armarx::split
std::vector< std::string > split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
Definition: StringHelpers.cpp:36