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

Refactor CPU measurement utilities and tests #45

Merged
merged 1 commit into from Dec 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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