Skip to content
This repository has been archived by the owner on Jun 10, 2021. It is now read-only.

Commit

Permalink
refactor cpu measurement utilities and tests (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
mm318 committed Dec 19, 2019
1 parent 93f269f commit d24b001
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 186 deletions.
Expand Up @@ -20,6 +20,7 @@

#include "../../src/system_metrics_collector/linux_cpu_measurement_node.hpp"
#include "../../src/system_metrics_collector/periodic_measurement_node.hpp"
#include "../../src/system_metrics_collector/utilities.hpp"

#include "rclcpp/rclcpp.hpp"
#include "rcutils/logging_macros.h"
Expand All @@ -30,55 +31,11 @@ namespace
{
constexpr const char MEASUREMENT_TYPE[] = "system_cpu_percent_used";
constexpr const char PROC_STAT_FILE[] = "/proc/stat";
constexpr const char CPU_LABEL[] = "cpu";
} // namespace

namespace system_metrics_collector
{

system_metrics_collector::ProcCpuData processStatCpuLine(const std::string & stat_cpu_line)
{
system_metrics_collector::ProcCpuData parsed_data;

if (!stat_cpu_line.empty()) {
if (!stat_cpu_line.compare(0, strlen(CPU_LABEL), CPU_LABEL)) {
std::istringstream ss(stat_cpu_line);

if (!ss.good()) {
return system_metrics_collector::ProcCpuData();
}
ss >> parsed_data.cpu_label;

for (int i = 0;
i < static_cast<int>(system_metrics_collector::ProcCpuStates::kNumProcCpuStates); ++i)
{
if (!ss.good()) {
return system_metrics_collector::ProcCpuData();
}
ss >> parsed_data.times[i];
}
return parsed_data;
}
}
return parsed_data;
}

double computeCpuActivePercentage(
const system_metrics_collector::ProcCpuData & measurement1,
const system_metrics_collector::ProcCpuData & measurement2)
{
if (measurement1.isMeasurementEmpty() || measurement2.isMeasurementEmpty()) {
RCUTILS_LOG_ERROR_NAMED("computeCpuActivePercentage",
"a measurement was empty, unable to compute cpu percentage");
return std::nan("");
}
const double active_time = measurement2.getActiveTime() - measurement1.getActiveTime();
const double total_time = (measurement2.getIdleTime() + measurement2.getActiveTime()) -
(measurement1.getIdleTime() + measurement1.getActiveTime());

return 100.0 * active_time / total_time;
}

LinuxCpuMeasurementNode::LinuxCpuMeasurementNode(
const std::string & name,
const std::chrono::milliseconds measurement_period,
Expand Down
Expand Up @@ -26,25 +26,6 @@
namespace system_metrics_collector
{

/**
* Parse a line read from /proc/stat
*
* @param stat_cpu_line a line from /proc/stat
* @return ProcCpuData struct populated if parsed, otherwise empty
*/
system_metrics_collector::ProcCpuData processStatCpuLine(const std::string & stat_cpu_line);

/**
* Compute the percentage of CPU active.
*
* @param measurement1 the first measurement
* @param measurement2 the second measurement (made after the first)
* @return percentage of CPU active
*/
double computeCpuActivePercentage(
const system_metrics_collector::ProcCpuData & measurement1,
const system_metrics_collector::ProcCpuData & measurement2);

/**
* Node that periodically calculates the % of active CPU by
* reading /proc/stat.
Expand Down
Expand Up @@ -28,10 +28,20 @@ namespace system_metrics_collector

namespace
{

constexpr const char CPU_LABEL[] = "cpu";
constexpr const char MEM_TOTAL[] = "MemTotal:";
constexpr const char MEM_AVAILABLE[] = "MemAvailable:";
constexpr const char EMPTY_FILE[] = "";
constexpr const int INVALID_MEMORY_SAMPLE = -1;

double computeCpuTotalTime(const ProcCpuData measurement1, const ProcCpuData measurement2)
{
const double total_time = (measurement2.getIdleTime() + measurement2.getActiveTime()) -
(measurement1.getIdleTime() + measurement1.getActiveTime());
return total_time;
}

} // namespace

std::string readFileToString(const std::string & file_name)
Expand All @@ -48,6 +58,49 @@ std::string readFileToString(const std::string & file_name)
return to_return;
}

ProcCpuData processStatCpuLine(const std::string & stat_cpu_line)
{
ProcCpuData parsed_data;

if (!stat_cpu_line.empty()) {
if (!stat_cpu_line.compare(0, strlen(CPU_LABEL), CPU_LABEL)) {
std::istringstream ss(stat_cpu_line);

if (!ss.good()) {
return ProcCpuData();
}
ss >> parsed_data.cpu_label;

for (int i = 0;
i < static_cast<int>(ProcCpuStates::kNumProcCpuStates); ++i)
{
if (!ss.good()) {
return ProcCpuData();
}
ss >> parsed_data.times[i];
}
return parsed_data;
}
}
return parsed_data;
}

double computeCpuActivePercentage(
const ProcCpuData & measurement1,
const ProcCpuData & measurement2)
{
if (measurement1.isMeasurementEmpty() || measurement2.isMeasurementEmpty()) {
RCUTILS_LOG_ERROR_NAMED("computeCpuActivePercentage",
"a measurement was empty, unable to compute cpu percentage");
return std::nan("");
}

const double active_time = measurement2.getActiveTime() - measurement1.getActiveTime();
const double total_time = computeCpuTotalTime(measurement1, measurement2);

return 100.0 * active_time / total_time;
}

double processMemInfoLines(const std::string & lines)
{
std::istringstream process_lines_stream(lines);
Expand Down
Expand Up @@ -17,6 +17,8 @@

#include <string>

#include "../../src/system_metrics_collector/proc_cpu_data.hpp"

namespace system_metrics_collector
{
/**
Expand All @@ -28,6 +30,25 @@ namespace system_metrics_collector
*/
std::string readFileToString(const std::string & file_name);

/**
* Parse a line read from /proc/stat
*
* @param stat_cpu_line a line from /proc/stat
* @return ProcCpuData struct populated if parsed, otherwise empty
*/
ProcCpuData processStatCpuLine(const std::string & stat_cpu_line);

/**
* Compute the percentage of CPU active.
*
* @param measurement1 the first measurement
* @param measurement2 the second measurement (made after the first)
* @return percentage of CPU active
*/
double computeCpuActivePercentage(
const ProcCpuData & measurement1,
const ProcCpuData & measurement2);

/**
* Process input lines from the /proc/meminfo file. The expected format to
* compute memory used is
Expand Down
Expand Up @@ -24,6 +24,23 @@ constexpr const std::chrono::milliseconds TEST_DURATION{250};
constexpr const std::chrono::milliseconds MEASURE_PERIOD{50};
constexpr const std::chrono::milliseconds PUBLISH_PERIOD{80};

constexpr const char PROC_SAMPLE_RESOLUTION_TEST[] =
"cpu 57211920 335926 18096939 2526329830 14818556 0 1072048 0 0 0\n";
constexpr const std::array<const char *, 10> PROC_SAMPLES = {
"cpu 22451232 118653 7348045 934943300 5378119 0 419114 0 0 0\n",
"cpu 22451360 118653 7348080 934949227 5378120 0 419117 0 0 0\n",
"cpu 24343452 61856 6484430 10645595 58695 0 683052 0 0 0\n",
"cpu 6051294 43322 1611333 9021635 47400 0 177494 0 0 0\n",
"cpu 6092443 6217 1623536 535731 4143 0 232286 0 0 0\n",
"cpu 6097071 6498 1612044 544445 3484 0 135942 0 0 0\n",
"cpu 6102643 5818 1637516 543782 3666 0 137329 0 0 0\n",
"cpu 24513632 62372 6527524 11205004 62394 0 687176 0 0 0\n",
"cpu 6093617 43419 1621953 9161570 48047 0 178792 0 0 0\n",
"cpu 6134250 6371 1634411 675446 5285 0 233478 0 0 0\n"
};
constexpr const double CPU_ACTIVE_PROC_SAMPLE_0_1 = 2.7239908106334099;


constexpr const char EMPTY_SAMPLE[] = "";
constexpr const char GARBAGE_SAMPLE[] = "this is garbage\n";
constexpr const char INCOMPLETE_SAMPLE[] =
Expand Down

0 comments on commit d24b001

Please sign in to comment.