mirror of https://github.com/pvnis/srsRAN_4G.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
7.8 KiB
C++
263 lines
7.8 KiB
C++
/**
|
|
*
|
|
* \section COPYRIGHT
|
|
*
|
|
* Copyright 2013-2021 Software Radio Systems Limited
|
|
*
|
|
* By using this file, you agree to the terms and conditions set
|
|
* forth in the LICENSE file which can be found at the top level of
|
|
* the distribution.
|
|
*
|
|
*/
|
|
|
|
#include "srsran/system/sys_metrics_processor.h"
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <sys/sysinfo.h>
|
|
#include <unistd.h>
|
|
|
|
using namespace srsran;
|
|
|
|
static const uint32_t cpu_count = ::sysconf(_SC_NPROCESSORS_CONF);
|
|
static const float ticks_per_second = ::sysconf(_SC_CLK_TCK);
|
|
|
|
sys_metrics_processor::sys_metrics_processor(srslog::basic_logger& logger) : logger(logger)
|
|
{
|
|
if (cpu_count > metrics_max_supported_cpu) {
|
|
logger.warning("Number of cpu is greater than supported. CPU metrics will be disabled.");
|
|
}
|
|
}
|
|
|
|
sys_metrics_processor::proc_stats_info::proc_stats_info()
|
|
{
|
|
std::string line;
|
|
{
|
|
std::ifstream file("/proc/self/stat");
|
|
if (!file) {
|
|
return;
|
|
}
|
|
|
|
std::getline(file, line);
|
|
}
|
|
|
|
std::istringstream reader(line);
|
|
reader >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr >> tpgid >> flags >> minflt >> cminflt >>
|
|
majflt >> cmajflt >> utime >> stime >> cutime >> cstime >> priority >> nice >> num_threads >> itrealvalue >>
|
|
starttime >> vsize >> rss >> rsslim >> startcode >> endcode >> startstack >> kstkeip >> signal >> blocked >>
|
|
sigignore >> sigcatch >> wchan >> nswap >> cnswap >> exit_signal >> processor >> rt_priority >> policy >>
|
|
delaycct_blkio_ticks >> guest_time >> cguest_time >> start_data >> end_data >> start_brk >> arg_start >>
|
|
arg_end >> env_start >> env_end >> exit_code;
|
|
}
|
|
|
|
/// Returns a null sys_metrics_t with the cpu count field filled.
|
|
static sys_metrics_t create_null_metrics()
|
|
{
|
|
sys_metrics_t metrics;
|
|
|
|
if (cpu_count > metrics_max_supported_cpu) {
|
|
return metrics;
|
|
}
|
|
|
|
metrics.cpu_count = cpu_count;
|
|
metrics.cpu_load.fill(0.f);
|
|
return metrics;
|
|
}
|
|
|
|
sys_metrics_t sys_metrics_processor::get_metrics()
|
|
{
|
|
auto current_time = std::chrono::steady_clock::now();
|
|
uint32_t measure_interval_ms =
|
|
std::chrono::duration_cast<std::chrono::milliseconds>(current_time - last_query_time).count();
|
|
|
|
// The time elapsed between 2 measures must be greater that 10 milliseconds.
|
|
if (measure_interval_ms < 10u) {
|
|
logger.info("Interval less than 10ms, skipping measurement.");
|
|
return create_null_metrics();
|
|
}
|
|
|
|
sys_metrics_t metrics;
|
|
|
|
// Get the memory metrics.
|
|
calculate_mem_usage(metrics);
|
|
|
|
// Calculate cpu metrics.
|
|
calculate_cpu_metrics(metrics, measure_interval_ms / 1000.f);
|
|
|
|
// Get the stats from the proc.
|
|
proc_stats_info current_query;
|
|
metrics.thread_count = current_query.num_threads;
|
|
metrics.process_cpu_usage = calculate_cpu_usage(current_query, measure_interval_ms / 1000.f);
|
|
|
|
// Update the last values.
|
|
last_query_time = current_time;
|
|
last_query = std::move(current_query);
|
|
|
|
return metrics;
|
|
}
|
|
|
|
float sys_metrics_processor::calculate_cpu_usage(const proc_stats_info& current_query,
|
|
float delta_time_in_seconds) const
|
|
{
|
|
// Error current value has to be greater than last value.
|
|
if (current_query.stime < last_query.stime || current_query.utime < last_query.utime) {
|
|
return -1.f;
|
|
}
|
|
|
|
// If current and last tick counter equals, means that the process didn't used CPU.
|
|
if (current_query.stime == last_query.stime && current_query.utime == last_query.utime) {
|
|
return 0.f;
|
|
}
|
|
|
|
return ((current_query.stime + current_query.utime) - (last_query.stime + last_query.utime)) * 100.f /
|
|
(cpu_count * ticks_per_second * delta_time_in_seconds);
|
|
}
|
|
|
|
sys_metrics_processor::cpu_metrics_t sys_metrics_processor::read_cpu_idle_from_line(const std::string& line) const
|
|
{
|
|
std::istringstream reader(line);
|
|
cpu_metrics_t m;
|
|
|
|
reader >> m.name >> m.user >> m.nice >> m.system >> m.idle >> m.iowait >> m.irq >> m.softirq;
|
|
|
|
return m;
|
|
}
|
|
|
|
void sys_metrics_processor::calculate_cpu_metrics(sys_metrics_t& metrics, float delta_time_in_seconds)
|
|
{
|
|
// When the number of cpu is higher than system_metrics_t supports, skip the cpu metrics.
|
|
if (cpu_count > metrics_max_supported_cpu) {
|
|
return;
|
|
}
|
|
|
|
metrics.cpu_count = cpu_count;
|
|
|
|
std::ifstream file("/proc/stat");
|
|
std::string line;
|
|
|
|
if (!file) {
|
|
return;
|
|
}
|
|
|
|
int count = -1;
|
|
while (std::getline(file, line)) {
|
|
// First line is the CPU field that contains all the cores and thread. For now, we skip this one.
|
|
if (count < 0) {
|
|
++count;
|
|
continue;
|
|
}
|
|
|
|
// Parse all the cpus.
|
|
if (line.find("cpu") != std::string::npos) {
|
|
auto tmp = read_cpu_idle_from_line(line);
|
|
auto index = count++;
|
|
if (tmp.idle < last_cpu_thread[index].idle) {
|
|
metrics.cpu_load[index] = 0.f;
|
|
continue;
|
|
}
|
|
|
|
metrics.cpu_load[index] = std::max(
|
|
(1.f - (tmp.idle - last_cpu_thread[index].idle) / (ticks_per_second * delta_time_in_seconds)) * 100.f, 0.f);
|
|
|
|
last_cpu_thread[index] = std::move(tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Sets the memory parameters of the given metrics to zero.
|
|
static void set_mem_to_zero(sys_metrics_t& metrics)
|
|
{
|
|
metrics.process_realmem_kB = 0;
|
|
metrics.process_virtualmem_kB = 0;
|
|
metrics.process_realmem = 0;
|
|
metrics.system_mem = 0;
|
|
}
|
|
|
|
/// Extracts and returns the memory size from the given line.
|
|
static int32_t read_memory_value_from_line(const std::string& line)
|
|
{
|
|
std::istringstream reader(line);
|
|
std::string label, unit;
|
|
int32_t value;
|
|
|
|
reader >> label >> value >> unit;
|
|
|
|
return value;
|
|
}
|
|
|
|
static void calculate_percentage_memory(sys_metrics_t& metrics)
|
|
{
|
|
std::ifstream file("/proc/meminfo");
|
|
std::string line;
|
|
|
|
if (!file) {
|
|
set_mem_to_zero(metrics);
|
|
return;
|
|
}
|
|
|
|
struct meminfo_t {
|
|
uint32_t total_kB = 0;
|
|
uint32_t free_kB = 0;
|
|
uint32_t buffers_kB = 0;
|
|
uint32_t cached_kB = 0;
|
|
uint32_t slab_kB = 0;
|
|
};
|
|
|
|
// Retrieve the data
|
|
meminfo_t m_info;
|
|
while (std::getline(file, line)) {
|
|
// Looks for Virtual memory.
|
|
if (line.find("MemTotal:") != std::string::npos) {
|
|
m_info.total_kB = std::max(read_memory_value_from_line(line), 0);
|
|
}
|
|
if (line.find("MemFree:") != std::string::npos) {
|
|
m_info.free_kB = std::max(read_memory_value_from_line(line), 0);
|
|
}
|
|
if (line.find("Buffers:") != std::string::npos) {
|
|
m_info.buffers_kB = std::max(read_memory_value_from_line(line), 0);
|
|
}
|
|
if (line.find("Cached:") != std::string::npos) {
|
|
m_info.cached_kB = std::max(read_memory_value_from_line(line), 0);
|
|
}
|
|
if (line.find("Slab:") != std::string::npos) {
|
|
m_info.slab_kB = std::max(read_memory_value_from_line(line), 0);
|
|
}
|
|
}
|
|
|
|
// Calculate the metrics.
|
|
metrics.process_realmem = (metrics.process_realmem_kB <= m_info.total_kB)
|
|
? 100.f * (float(metrics.process_realmem_kB) / m_info.total_kB)
|
|
: 0;
|
|
metrics.system_mem =
|
|
(1.f - float(m_info.buffers_kB + m_info.cached_kB + m_info.free_kB + m_info.slab_kB) / float(m_info.total_kB)) *
|
|
100.f;
|
|
}
|
|
|
|
void sys_metrics_processor::calculate_mem_usage(sys_metrics_t& metrics) const
|
|
{
|
|
std::ifstream file("/proc/self/status");
|
|
std::string line;
|
|
|
|
if (!file) {
|
|
set_mem_to_zero(metrics);
|
|
return;
|
|
}
|
|
|
|
while (std::getline(file, line)) {
|
|
// Looks for Virtual memory.
|
|
if (line.find("VmSize:") != std::string::npos) {
|
|
// NOTE: std::max will clamp negative values to 0.
|
|
metrics.process_virtualmem_kB = std::max(read_memory_value_from_line(line), 0);
|
|
continue;
|
|
}
|
|
// Looks for physical memory.
|
|
if (line.find("VmRSS:") != std::string::npos) {
|
|
// NOTE: std::max will clamp negative values to 0.
|
|
metrics.process_realmem_kB = std::max(read_memory_value_from_line(line), 0);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Now calculate the memory usage in percentage.
|
|
calculate_percentage_memory(metrics);
|
|
}
|