32#include <unordered_set>
34#include <sys/utsname.h>
37#include <IceUtil/Handle.h>
39#include <SimoxUtility/algorithm/string/string_tools.h>
45#include "ArmarXCore/interface/core/ThreadingIceBase.h"
48#include <ext/alloc_traits.h>
56 Hertz = sysconf(_SC_CLK_TCK);
58 ss <<
"/proc/" << pid <<
"/stat";
59 processCpuDataFilename = ss.str();
60 processCpuUsage.processId = pid;
61 cpuUsageFromProcFile();
80 watcherTask =
nullptr;
87 std::unique_lock lock(threadWatchListMutex);
94 threadWatchList.insert(usage);
104 ProcessWatcher::watch()
107 runThreadWatchList();
108 cpuUsageFromProcFile();
115 ProcessWatcher::runThreadWatchList()
118 std::unique_lock lock(threadWatchListMutex);
119 std::unordered_set<ThreadUsage> newset;
120 std::unordered_set<ThreadUsage>::iterator it = threadWatchList.begin();
122 for (; it != threadWatchList.end(); it++)
125 ThreadUsage usage = *it;
126 IceUtil::Time queryTime = IceUtil::Time::now();
131 usage.load = (curJiffies - usage.lastJiffies) /
132 ((queryTime - usage.lastUpdate).toSecondsDouble() *
GetHertz());
139 usage.lastJiffies = curJiffies;
140 usage.lastUpdate = queryTime;
141 newset.insert(usage);
144 threadWatchList.swap(newset);
148#if !defined(_WIN32) && !defined(__APPLE__)
153 static std::mutex mutex;
154 std::unique_lock lock(mutex);
155 static int value = -2;
160 static std::string _release;
162 if (_release.empty())
164 struct utsname utsinfo;
166 _release = utsinfo.release;
169 std::string fileName =
"/boot/config-" + _release;
170 std::ifstream configFile(fileName.c_str());
174 if (!configFile.is_open())
177 <<
" for reading the cpu hertz value";
184 const std::string searchString =
"CONFIG_HZ=";
186 while (getline(configFile, line))
189 std::size_t pos = line.find(searchString);
191 if (pos != std::string::npos)
193 std::string hzString = line.substr(pos + searchString.length());
194 value = std::stoi(hzString);
205 ProcessWatcher::cpuUsageFromProcFile()
210 std::ifstream file(processCpuDataFilename);
218 std::getline(file, line);
221 std::vector<std::string> pidElements = simox::alg::split(line,
"\t ");
223 int currentUtime = std::stoi(pidElements.at(eUTime));
224 int currentStime = std::stoi(pidElements.at(eSTime));
226 int currentCUtime = std::stoi(pidElements.at(eCUTIME));
227 int currentCStime = std::stoi(pidElements.at(eCSTIME));
230 std::unique_lock guard{processCpuUsageMutex};
232 IceUtil::Time queryTime = IceUtil::Time::now();
234 processCpuUsage.proc_total_time =
236 (double)((currentStime + currentCStime - processCpuUsage.lastStime -
237 processCpuUsage.lastCStime) +
238 (currentUtime + currentCUtime - processCpuUsage.lastCUtime -
239 processCpuUsage.lastUtime)) /
240 ((queryTime - processCpuUsage.lastUpdate).toSecondsDouble() * Hertz);
242 processCpuUsage.lastUpdate = queryTime;
243 processCpuUsage.lastUtime = currentUtime;
244 processCpuUsage.lastStime = currentStime;
246 processCpuUsage.lastCUtime = currentCUtime;
247 processCpuUsage.lastCStime = currentCStime;
252 ProcessWatcher::getMemoryUsage()
255 struct mallinfo _mallinfo;
257 _mallinfo = mallinfo();
260 std::unique_lock guard{processMemoryUsageMutex};
261 memoryUsage.fastbinBlocks = _mallinfo.fsmblks;
262 memoryUsage.totalAllocatedSpace = _mallinfo.uordblks;
263 memoryUsage.totalFreeSpace = _mallinfo.fordblks;
271 std::map<int, int> resultMap;
272 for (
int threadId : threadIds)
275 resultMap[threadId] = 0;
276 std::stringstream fileName;
277 fileName <<
"/proc/" << threadId <<
"/task/" << threadId <<
"/stat";
278 std::ifstream statFile(fileName.str().c_str());
280 if (!statFile.is_open())
283 <<
" for reading the hertz value";
284 resultMap[threadId] = 0;
290 while (getline(statFile, line))
293 simox::alg::trim(line);
295 std::vector<std::string> stringVec = simox::alg::split(line,
" ");
298 int userTimeJiffies = atoi(stringVec.at(13).c_str());
299 int kernelTimeJiffies = atoi(stringVec.at(14).c_str());
301 resultMap[threadId] = userTimeJiffies + kernelTimeJiffies;
318 return std::map<int, int>();
322 ProcessWatcher::cpuUsageFromProcFile()
327 ProcessWatcher::getMemoryUsage()
365 std::map<int, int>::iterator it = result.find(threadId);
367 if (it == result.end())
378 std::unique_lock guard{processCpuUsageMutex};
379 profiler->logProcessCpuUsage(processCpuUsage.proc_total_time);
385 std::unique_lock guard{processMemoryUsageMutex};
386 profiler->logProcessMemoryUsage(memoryUsage.totalFreeSpace);
402 std::unique_lock lock(threadWatchListMutex);
403 auto it = threadWatchList.find(query);
406 if (it != threadWatchList.end())
408 return it->load * 100;
419 std::unique_lock guard{processCpuUsageMutex};
420 return processCpuUsage;
430 std::unique_lock lock(threadWatchListMutex);
431 threadWatchList.erase(query);
static long getProcessId()
The periodic task executes one thread method repeatedly using the time period specified in the constr...
ProcessWatcher(Profiler::ProfilerPtr profiler)
void removeThread(int processId, int threadId)
static std::map< int, int > GetThreadListJiffies(int processId, std::vector< int > threadIds)
static int GetThreadJiffies(int processId, int threadId)
armarx::CpuUsage getProcessCpuUsage()
double getThreadLoad(int processId, int threadId)
void addThread(int processId, int threadId)
#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...
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
std::shared_ptr< Profiler > ProfilerPtr
This file offers overloads of toIce() and fromIce() functions for STL container types.
bool operator==(const ThreadUsage &rhs) const
bool operator<(const ThreadUsage &rhs) const