Skip to content

Commit 2a5c60d

Browse files
authored
Calculate memory usage percentage instead of using ps command (#59)
1 parent 808a618 commit 2a5c60d

File tree

4 files changed

+40
-30
lines changed

4 files changed

+40
-30
lines changed

README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ See table below to find out how to create `URI` for each backend:
104104
| InfoLogger | - | `infologger` | - |
105105
| Flume | UDP | `flume` | - |
106106
107+
Multiple backends may be used at the same time, URLs should be separated by `,` (comma).
108+
107109
### Sending metric
108110
109111
```cpp
@@ -197,16 +199,13 @@ Glabal tags are tags that are added to each metric. The following tags are set t
197199
You can add your own global tag by calling `addGlobalTag(std::string name, std::string value)`.
198200

199201
### Monitoring process
200-
Currently process monitoring is supported only on Linux. To enable it use:
201202
```cpp
202203
enableProcessMonitoring([interval in seconds]);
203204
```
204205
The following metrics are generated every interval:
205-
+ **cpuUsedPercentage** - percentage of a core usage over time interval (from `gerrusage`)
206-
+ **involuntaryContextSwitches** - involuntary context switches over time interval (from `gerrusage`)
207-
+ **memoryUsagePercentage** - ratio of the process's resident set size to the physical memory on the machine, expressed as a percentage (from `ps`)
208-
+ **bytesReceived** - the total number of bytes of data received by the process per interface (from `/proc/[PID]/net/dev`)
209-
+ **bytesTransmitted** - the total number of bytes of data transmitted by the process per interface (from `/proc/[PID]/net/dev`).
206+
+ **cpuUsedPercentage** - percentage of a core usage over time interval
207+
+ **involuntaryContextSwitches** - involuntary context switches over time interval
208+
+ **memoryUsagePercentage** - ratio of the process's resident set size to the physical memory on the machine, expressed as a percentage (Linux only)
210209
211210
## Code snippets
212211
Code snippets are available in [examples](examples/) directory.

include/Monitoring/ProcessMonitor.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,11 @@ class ProcessMonitor
4747
/// PIDs that are monitored
4848
unsigned int mPid;
4949

50-
/// Executes terminal command
51-
std::string exec(const char* cmd);
50+
/// Total memory size
51+
unsigned int mTotalMemory;
52+
53+
/// Retrievs total memory size from /proc/meminfo
54+
void setTotalMemory();
5255

5356
/// 'getrusage' values from last execution
5457
struct rusage mPreviousGetrUsage;

src/Monitoring.cxx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ void Monitoring::flushBuffer() {
5959
}
6060

6161
void Monitoring::enableProcessMonitoring(const unsigned int interval) {
62-
#ifdef _OS_LINUX
6362
mMonitorRunning = true;
6463
mMonitorThread = std::thread(&Monitoring::processMonitorLoop, this, interval);
64+
#ifdef _OS_LINUX
6565
MonLogger::Get() << "Process Monitor : Automatic updates enabled" << MonLogger::End();
6666
#else
67-
MonLogger::Get() << "!! Process Monitor : Automatic updates not supported" << MonLogger::End();
67+
MonLogger::Get() << "!! Process Monitor : Limited metrics available" << MonLogger::End();
6868
#endif
6969
}
7070

@@ -123,8 +123,9 @@ void Monitoring::processMonitorLoop(int interval)
123123
std::this_thread::sleep_for (std::chrono::milliseconds(interval*10));
124124
if ((++loopCount % 100) != 0) continue;
125125
send(mProcessMonitor->getCpuAndContexts());
126-
send(mProcessMonitor->getNetworkUsage());
126+
#ifdef _OS_LINUX
127127
send(mProcessMonitor->getMemoryUsage());
128+
#endif
128129
loopCount = 0;
129130
}
130131
}

src/ProcessMonitor.cxx

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,36 @@ ProcessMonitor::ProcessMonitor()
2424
mPid = static_cast<unsigned int>(::getpid());
2525
getrusage(RUSAGE_SELF, &mPreviousGetrUsage);
2626
mTimeLastRun = std::chrono::high_resolution_clock::now();
27+
#ifdef _OS_LINUX
28+
setTotalMemory();
29+
#endif
30+
}
31+
32+
void ProcessMonitor::setTotalMemory()
33+
{
34+
std::ifstream memInfo("/proc/meminfo");
35+
std::string totalString;
36+
std::getline(memInfo, totalString);
37+
std::istringstream iss(totalString);
38+
std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
39+
std::istream_iterator<std::string>{}};
40+
mTotalMemory = std::stoi(tokens[1]);
2741
}
2842

2943
Metric ProcessMonitor::getMemoryUsage()
3044
{
31-
std::string command = "ps --no-headers -o pmem --pid " + std::to_string(mPid);
32-
std::string output = exec(command.c_str());
33-
boost::trim(output);
34-
return Metric{std::stod(output), "memoryUsagePercentage"};
45+
std::ifstream statusStream("/proc/self/status");
46+
std::string rssString;
47+
rssString.reserve(50);
48+
49+
// Scan for VmRSS
50+
for(int i = 0; i < 18; i++) {
51+
std::getline(statusStream, rssString);
52+
}
53+
std::istringstream iss(rssString);
54+
std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
55+
std::istream_iterator<std::string>{}};
56+
return Metric{(std::stod(tokens[1])*100)/mTotalMemory, "memoryUsagePercentage"};
3557
}
3658

3759
std::vector<Metric> ProcessMonitor::getCpuAndContexts() {
@@ -85,20 +107,5 @@ std::vector<Metric> ProcessMonitor::getNetworkUsage()
85107
return metrics;
86108
}
87109

88-
std::string ProcessMonitor::exec(const char* cmd)
89-
{
90-
char buffer[128];
91-
std::string result = "";
92-
std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
93-
if (!pipe) {
94-
throw MonitoringInternalException("Process Monitor exec", "Issue encountered when running 'ps' (popen)");
95-
}
96-
while (!feof(pipe.get())) {
97-
if (fgets(buffer, 128, pipe.get()) != NULL)
98-
result += buffer;
99-
}
100-
return result;
101-
}
102-
103110
} // namespace monitoring
104111
} // namespace o2

0 commit comments

Comments
 (0)