Skip to content

Commit

Permalink
Calculate memory usage percentage instead of using ps command (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
awegrzyn authored Jul 2, 2018
1 parent 808a618 commit 2a5c60d
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 30 deletions.
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ See table below to find out how to create `URI` for each backend:
| InfoLogger | - | `infologger` | - |
| Flume | UDP | `flume` | - |
Multiple backends may be used at the same time, URLs should be separated by `,` (comma).
### Sending metric
```cpp
Expand Down Expand Up @@ -197,16 +199,13 @@ Glabal tags are tags that are added to each metric. The following tags are set t
You can add your own global tag by calling `addGlobalTag(std::string name, std::string value)`.

### Monitoring process
Currently process monitoring is supported only on Linux. To enable it use:
```cpp
enableProcessMonitoring([interval in seconds]);
```
The following metrics are generated every interval:
+ **cpuUsedPercentage** - percentage of a core usage over time interval (from `gerrusage`)
+ **involuntaryContextSwitches** - involuntary context switches over time interval (from `gerrusage`)
+ **memoryUsagePercentage** - ratio of the process's resident set size to the physical memory on the machine, expressed as a percentage (from `ps`)
+ **bytesReceived** - the total number of bytes of data received by the process per interface (from `/proc/[PID]/net/dev`)
+ **bytesTransmitted** - the total number of bytes of data transmitted by the process per interface (from `/proc/[PID]/net/dev`).
+ **cpuUsedPercentage** - percentage of a core usage over time interval
+ **involuntaryContextSwitches** - involuntary context switches over time interval
+ **memoryUsagePercentage** - ratio of the process's resident set size to the physical memory on the machine, expressed as a percentage (Linux only)
## Code snippets
Code snippets are available in [examples](examples/) directory.
Expand Down
7 changes: 5 additions & 2 deletions include/Monitoring/ProcessMonitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@ class ProcessMonitor
/// PIDs that are monitored
unsigned int mPid;

/// Executes terminal command
std::string exec(const char* cmd);
/// Total memory size
unsigned int mTotalMemory;

/// Retrievs total memory size from /proc/meminfo
void setTotalMemory();

/// 'getrusage' values from last execution
struct rusage mPreviousGetrUsage;
Expand Down
7 changes: 4 additions & 3 deletions src/Monitoring.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ void Monitoring::flushBuffer() {
}

void Monitoring::enableProcessMonitoring(const unsigned int interval) {
#ifdef _OS_LINUX
mMonitorRunning = true;
mMonitorThread = std::thread(&Monitoring::processMonitorLoop, this, interval);
#ifdef _OS_LINUX
MonLogger::Get() << "Process Monitor : Automatic updates enabled" << MonLogger::End();
#else
MonLogger::Get() << "!! Process Monitor : Automatic updates not supported" << MonLogger::End();
MonLogger::Get() << "!! Process Monitor : Limited metrics available" << MonLogger::End();
#endif
}

Expand Down Expand Up @@ -123,8 +123,9 @@ void Monitoring::processMonitorLoop(int interval)
std::this_thread::sleep_for (std::chrono::milliseconds(interval*10));
if ((++loopCount % 100) != 0) continue;
send(mProcessMonitor->getCpuAndContexts());
send(mProcessMonitor->getNetworkUsage());
#ifdef _OS_LINUX
send(mProcessMonitor->getMemoryUsage());
#endif
loopCount = 0;
}
}
Expand Down
45 changes: 26 additions & 19 deletions src/ProcessMonitor.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,36 @@ ProcessMonitor::ProcessMonitor()
mPid = static_cast<unsigned int>(::getpid());
getrusage(RUSAGE_SELF, &mPreviousGetrUsage);
mTimeLastRun = std::chrono::high_resolution_clock::now();
#ifdef _OS_LINUX
setTotalMemory();
#endif
}

void ProcessMonitor::setTotalMemory()
{
std::ifstream memInfo("/proc/meminfo");
std::string totalString;
std::getline(memInfo, totalString);
std::istringstream iss(totalString);
std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
std::istream_iterator<std::string>{}};
mTotalMemory = std::stoi(tokens[1]);
}

Metric ProcessMonitor::getMemoryUsage()
{
std::string command = "ps --no-headers -o pmem --pid " + std::to_string(mPid);
std::string output = exec(command.c_str());
boost::trim(output);
return Metric{std::stod(output), "memoryUsagePercentage"};
std::ifstream statusStream("/proc/self/status");
std::string rssString;
rssString.reserve(50);

// Scan for VmRSS
for(int i = 0; i < 18; i++) {
std::getline(statusStream, rssString);
}
std::istringstream iss(rssString);
std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
std::istream_iterator<std::string>{}};
return Metric{(std::stod(tokens[1])*100)/mTotalMemory, "memoryUsagePercentage"};
}

std::vector<Metric> ProcessMonitor::getCpuAndContexts() {
Expand Down Expand Up @@ -85,20 +107,5 @@ std::vector<Metric> ProcessMonitor::getNetworkUsage()
return metrics;
}

std::string ProcessMonitor::exec(const char* cmd)
{
char buffer[128];
std::string result = "";
std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
throw MonitoringInternalException("Process Monitor exec", "Issue encountered when running 'ps' (popen)");
}
while (!feof(pipe.get())) {
if (fgets(buffer, 128, pipe.get()) != NULL)
result += buffer;
}
return result;
}

} // namespace monitoring
} // namespace o2

0 comments on commit 2a5c60d

Please sign in to comment.