linux_process_load.cpp
Go to the documentation of this file.
1/**
2 * @author: Daniel Fuchs
3 * @contact: fuxeysolutions@gmail.com
4 *
5 * distributed under the MIT License (MIT).
6 * Copyright (c) Daniel Fuchs
7 *
8 */
9
11
12#include <algorithm>
13#include <filesystem>
14#include <fstream>
15#include <iostream>
16#include <list>
17#include <memory>
18
19#include "linux_cpuload.hpp"
20#include "linux_memoryload.hpp"
21
22static const std::list<std::string> stats{
23 "pid", "comm", "state", "ppid", "pgrp", "session",
24 "tty_nr", "tpgid", "flags", "minflt", "cminflt", "majflt",
25 "cmajflt", "utime", "stime", "cutime", "cstime", "priority",
26 "nice", "num_threads", "itrealvalue", "starttime", "vsize", "rss",
27 "rsslim", "startcode", "endcode", "startstack", "kstkesp", "kstkeip",
28 "signal", "blocked", "sigignore", "sigcatch", "wchan", "nswap",
29 "cnswap", "exit_signal", "processor", "rt_priority", "policy", "delaycct_blkio_ticks",
30 "guest_time", "cguest_time", "start_data", "end_data", "start_brk", "arg_start",
31 "arg_end", "env_start", "env_end", "exit_code"};
32
33std::map<std::string, double>
35{
36 this->findProcesses();
37 return this->procCPUUsage;
38}
39
40void
41linuxProcessLoad::calculateProcessLoad()
42{
43 auto [cpuTotalUserTime, cpuTotalUserLowTime, cpuTotalSysTime, cpuTotalIdleTime] = CpuTimes;
44
45 auto [oldCpuTotalUserTime, oldCpuTotalUserLowTime, oldCpuTotalSysTime, oldCpuTotalIdleTime] =
46 oldCpuTimes;
47 auto TotalUserTime = cpuTotalUserTime - oldCpuTotalUserTime;
48 auto TotalSysTime = cpuTotalSysTime - oldCpuTotalSysTime;
49
50 this->procCPUUsage.clear();
51 for (const auto& elem : processStat)
52 {
53 auto pid = elem.first;
54 try
55 {
56 auto oldProc = oldProcessStat.at(pid);
57 auto proc = elem.second;
58 auto procName = proc.at("comm");
59 uint64_t cpuTime = 0;
60 cpuTime += (std::stoull(proc.at("utime")) - std::stoull(oldProc.at("utime")));
61 cpuTime += (std::stoull(proc.at("stime")) - std::stoull(oldProc.at("stime")));
62
63
64 double percentage = ((static_cast<double>(cpuTime) * 100.0) /
65 static_cast<double>((TotalUserTime + TotalSysTime)));
66
67 if (percentage > 0.1)
68 {
69 this->procCPUUsage[procName] = percentage;
70 }
71 }
72 catch (...)
73 {
74 std::cerr << "process: " << pid << " disappeared in meantime" << std::endl;
75 }
76 }
77}
78
79void
80linuxProcessLoad::findProcesses()
81{
82
83 auto cpuMonitoring = std::make_unique<cpuLoad>("/proc/stat");
84
85 this->CpuTimes = cpuMonitoring->getCpuTimes();
86
87
88 std::string path{"/proc/"};
89 std::vector<std::string> processes;
90 for (auto& elem : std::filesystem::directory_iterator(path))
91 {
92 auto procPath = elem.path().string();
93 if (elem.exists())
94 {
95 procPath.erase(procPath.begin(), procPath.begin() + static_cast<int32_t>(path.size()));
96 if (std::isdigit(procPath.at(0)))
97 {
98 if (!std::count_if(
99 procPath.begin(), procPath.end(), [](auto c) { return std::isalpha(c); }))
100 {
101 parseProcess(procPath);
102 }
103 }
104 }
105 }
106 this->calculateProcessLoad();
107
108 this->oldProcessStat = this->processStat;
109 this->oldCpuTimes = this->CpuTimes;
110}
111
112void
113linuxProcessLoad::parseProcess(const std::string& pid)
114{
115 std::string path{"/proc/" + pid + "/stat"};
116 std::ifstream ethFile(path);
117
118 std::string strPart;
119 std::unordered_map<std::string, std::string> procStat;
120 auto identifierStart = stats.begin();
121
122 enum state
123 {
124 normal,
125 isProcessParse
126 };
127
128 bool isProcessFound = false;
129 while (ethFile >> strPart)
130 {
131
132 if (identifierStart != stats.end())
133 {
134 if (isProcessFound)
135 {
136 procStat[identifierStart->data()] += " " + strPart;
137 }
138 if (std::count_if(strPart.begin(), strPart.end(), [](auto c) { return c == '('; }))
139 {
140 isProcessFound = true;
141 procStat[identifierStart->data()] = strPart;
142 }
143 if (!isProcessFound)
144 {
145 procStat[identifierStart->data()] = strPart;
146 }
147
148
149 if (std::count_if(strPart.begin(), strPart.end(), [](auto c) { return c == ')'; }))
150 {
151 isProcessFound = false;
152 }
153 }
154 if (!isProcessFound)
155 {
156 identifierStart++;
157 continue;
158 }
159 }
160
161 procStat["comm"].erase(std::remove_if(procStat["comm"].begin(),
162 procStat["comm"].end(),
163 [](auto c) { return c == '(' || c == ')'; }),
164 procStat["comm"].end());
165 processStat[pid] = procStat;
166}
constexpr T c
std::map< std::string, double > getProcessCpuLoad()
get a map of [pid] which contains the cpu load between two calls.