Add sensor read function
Added read functions for CPU and memory utilization and also class
initilization for each sensor.
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
Change-Id: I34de974435b37f45a9a11719959d79b72aea9a46
diff --git a/healthMonitor.cpp b/healthMonitor.cpp
index 9796927..af69ecb 100644
--- a/healthMonitor.cpp
+++ b/healthMonitor.cpp
@@ -7,6 +7,13 @@
#include <fstream>
#include <iostream>
+#include <numeric>
+#include <sstream>
+
+extern "C"
+{
+#include <sys/sysinfo.h>
+}
static constexpr bool DEBUG = false;
@@ -17,17 +24,165 @@
using namespace phosphor::logging;
-void HealthSensor::setSensorThreshold(uint8_t criticalHigh, uint8_t warningHigh)
+enum CPUStatesTime
+{
+ USER_IDX = 0,
+ NICE_IDX,
+ SYSTEM_IDX,
+ IDLE_IDX,
+ IOWAIT_IDX,
+ IRQ_IDX,
+ SOFTIRQ_IDX,
+ STEAL_IDX,
+ GUEST_USER_IDX,
+ GUEST_NICE_IDX,
+ NUM_CPU_STATES_TIME
+};
+
+double readCPUUtilization()
+{
+ std::ifstream fileStat("/proc/stat");
+ if (!fileStat.is_open())
+ {
+ log<level::ERR>("cpu file not available",
+ entry("FILENAME = /proc/stat"));
+ return -1;
+ }
+
+ std::string firstLine, labelName;
+ std::size_t timeData[NUM_CPU_STATES_TIME];
+
+ std::getline(fileStat, firstLine);
+ std::stringstream ss(firstLine);
+ ss >> labelName;
+
+ if (DEBUG)
+ std::cout << "CPU stats first Line is " << firstLine << "\n";
+
+ if (labelName.compare("cpu"))
+ {
+ log<level::ERR>("CPU data not available");
+ return -1;
+ }
+
+ int i;
+ for (i = 0; i < NUM_CPU_STATES_TIME; i++)
+ {
+ if (!(ss >> timeData[i]))
+ break;
+ }
+
+ if (i != NUM_CPU_STATES_TIME)
+ {
+ log<level::ERR>("CPU data not correct");
+ return -1;
+ }
+
+ static double preActiveTime = 0, preIdleTime = 0;
+ double activeTime, activeTimeDiff, idleTime, idleTimeDiff, totalTime,
+ activePercValue;
+
+ idleTime = timeData[IDLE_IDX] + timeData[IOWAIT_IDX];
+ activeTime = timeData[USER_IDX] + timeData[NICE_IDX] +
+ timeData[SYSTEM_IDX] + timeData[IRQ_IDX] +
+ timeData[SOFTIRQ_IDX] + timeData[STEAL_IDX] +
+ timeData[GUEST_USER_IDX] + timeData[GUEST_NICE_IDX];
+
+ idleTimeDiff = idleTime - preIdleTime;
+ activeTimeDiff = activeTime - preActiveTime;
+
+ /* Store current idle and active time for next calculation */
+ preIdleTime = idleTime;
+ preActiveTime = activeTime;
+
+ totalTime = idleTimeDiff + activeTimeDiff;
+
+ activePercValue = activeTimeDiff / totalTime * 100;
+
+ if (DEBUG)
+ std::cout << "CPU Utilization is " << activePercValue << "\n";
+
+ return activePercValue;
+}
+
+double readMemoryUtilization()
+{
+ struct sysinfo s_info;
+
+ sysinfo(&s_info);
+ double usedRam = s_info.totalram - s_info.freeram;
+ double memUsePerc = usedRam / s_info.totalram * 100;
+
+ if (DEBUG)
+ {
+ std::cout << "Memory Utilization is " << memUsePerc << "\n";
+
+ std::cout << "TotalRam: " << s_info.totalram
+ << " FreeRam: " << s_info.freeram << "\n";
+ std::cout << "UseRam: " << usedRam << "\n";
+ }
+
+ return memUsePerc;
+}
+
+/** Map of read function for each health sensors supported */
+std::map<std::string, std::function<double()>> readSensors = {
+ {"CPU", readCPUUtilization}, {"Memory", readMemoryUtilization}};
+
+void HealthSensor::setSensorThreshold(double criticalHigh, double warningHigh)
{
CriticalInterface::criticalHigh(criticalHigh);
WarningInterface::warningHigh(warningHigh);
}
-void HealthSensor::setSensorValueToDbus(const uint8_t value)
+void HealthSensor::setSensorValueToDbus(const double value)
{
ValueIface::value(value);
}
+void HealthSensor::initHealthSensor()
+{
+ std::string logMsg = sensorConfig.name + " Health Sensor initialized";
+ log<level::INFO>(logMsg.c_str());
+
+ /* Look for sensor read functions */
+ if (readSensors.find(sensorConfig.name) == readSensors.end())
+ {
+ log<level::ERR>("Sensor read function not available");
+ return;
+ }
+
+ /* Read Sensor values */
+ auto value = readSensors[sensorConfig.name]();
+
+ if (value < 0)
+ {
+ log<level::ERR>("Reading Sensor Utilization failed",
+ entry("NAME = %s", sensorConfig.name.c_str()));
+ return;
+ }
+
+ /* Initialize value queue with initail sensor reading */
+ for (int i = 0; i < sensorConfig.windowSize; i++)
+ {
+ valQueue.push_back(value);
+ }
+ setSensorValueToDbus(value);
+}
+
+void printConfig(HealthConfig& cfg)
+{
+ std::cout << "Name: " << cfg.name << "\n";
+ std::cout << "Freq: " << (int)cfg.freq << "\n";
+ std::cout << "Window Size: " << (int)cfg.windowSize << "\n";
+ std::cout << "Critical value: " << (int)cfg.criticalHigh << "\n";
+ std::cout << "warning value: " << (int)cfg.warningHigh << "\n";
+ std::cout << "Critical log: " << (int)cfg.criticalLog << "\n";
+ std::cout << "Warning log: " << (int)cfg.warningLog << "\n";
+ std::cout << "Critical Target: " << cfg.criticalTgt << "\n";
+ std::cout << "Warning Target: " << cfg.warningTgt << "\n\n";
+}
+
/* Create dbus utilization sensor object for each configured sensors */
void HealthMon::createHealthSensors()
{
@@ -35,7 +190,7 @@
{
std::string objPath = std::string(HEALTH_SENSOR_PATH) + cfg.name;
auto healthSensor =
- std::make_shared<HealthSensor>(bus, objPath.c_str());
+ std::make_shared<HealthSensor>(bus, objPath.c_str(), cfg);
healthSensors.emplace(cfg.name, healthSensor);
std::string logMsg = cfg.name + " Health Sensor created";
@@ -66,26 +221,17 @@
return data;
}
-void printConfig(HealthMon::HealthConfig& cfg)
-{
- std::cout << "Name: " << cfg.name << "\n";
- std::cout << "Freq: " << cfg.freq << "\n";
- std::cout << "Window Size: " << cfg.windowSize << "\n";
- std::cout << "Critical value: " << cfg.criticalHigh << "\n";
- std::cout << "warning value: " << cfg.warningHigh << "\n";
- std::cout << "Critical log: " << cfg.criticalLog << "\n";
- std::cout << "Warning log: " << cfg.warningLog << "\n";
- std::cout << "Critical Target: " << cfg.criticalTgt << "\n";
- std::cout << "Warning Target: " << cfg.warningTgt << "\n\n";
-}
-
void HealthMon::getConfigData(Json& data, HealthConfig& cfg)
{
static const Json empty{};
- cfg.freq = data.value("Frequency", 0);
- cfg.windowSize = data.value("Window_size", 0);
+ /* Default frerquency of sensor polling is 1 second */
+ cfg.freq = data.value("Frequency", 1);
+
+ /* Default window size sensor queue is 1 */
+ cfg.windowSize = data.value("Window_size", 1);
+
auto threshold = data.value("Threshold", empty);
if (!threshold.empty())
{
@@ -106,7 +252,7 @@
}
}
-std::vector<HealthMon::HealthConfig> HealthMon::getHealthConfig()
+std::vector<HealthConfig> HealthMon::getHealthConfig()
{
std::vector<HealthConfig> cfgs;
@@ -121,7 +267,7 @@
for (auto& j : data.items())
{
auto key = j.key();
- if (std::find(cfgNames.begin(), cfgNames.end(), key) != cfgNames.end())
+ if (readSensors.find(key) != readSensors.end())
{
HealthConfig cfg = HealthConfig();
cfg.name = j.key();
diff --git a/healthMonitor.hpp b/healthMonitor.hpp
index eff0519..e8230fa 100644
--- a/healthMonitor.hpp
+++ b/healthMonitor.hpp
@@ -5,6 +5,7 @@
#include <xyz/openbmc_project/Sensor/Threshold/Warning/server.hpp>
#include <xyz/openbmc_project/Sensor/Value/server.hpp>
+#include <deque>
#include <map>
#include <string>
@@ -26,6 +27,19 @@
sdbusplus::server::object::object<ValueIface, CriticalInterface,
WarningInterface>;
+struct HealthConfig
+{
+ std::string name;
+ uint16_t freq;
+ uint16_t windowSize;
+ double criticalHigh;
+ double warningHigh;
+ bool criticalLog;
+ bool warningLog;
+ std::string criticalTgt;
+ std::string warningTgt;
+};
+
class HealthSensor : public healthIfaces
{
public:
@@ -41,17 +55,26 @@
* @param[in] bus - Handle to system dbus
* @param[in] objPath - The Dbus path of health sensor
*/
- HealthSensor(sdbusplus::bus::bus& bus, const char* objPath) :
- healthIfaces(bus, objPath), bus(bus)
- {}
+ HealthSensor(sdbusplus::bus::bus& bus, const char* objPath,
+ HealthConfig& sensorConfig) :
+ healthIfaces(bus, objPath),
+ bus(bus), sensorConfig(sensorConfig)
+ {
+ initHealthSensor();
+ }
+ /** @brief list of sensor data values */
+ std::deque<double> valQueue;
+
+ void initHealthSensor();
/** @brief Set sensor value utilization to health sensor D-bus */
- void setSensorValueToDbus(const uint8_t value);
+ void setSensorValueToDbus(const double value);
/** @brief Set Sensor Threshold to D-bus at beginning */
- void setSensorThreshold(uint8_t criticalHigh, uint8_t warningHigh);
+ void setSensorThreshold(double criticalHigh, double warningHigh);
private:
sdbusplus::bus::bus& bus;
+ HealthConfig& sensorConfig;
};
class HealthMon
@@ -75,22 +98,6 @@
createHealthSensors();
}
- struct HealthConfig
- {
- std::string name;
- uint16_t freq;
- uint16_t windowSize;
- uint8_t criticalHigh;
- uint8_t warningHigh;
- bool criticalLog;
- bool warningLog;
- std::string criticalTgt;
- std::string warningTgt;
- };
-
- /** @brief List of health sensors supported */
- std::vector<std::string> cfgNames = {"CPU", "Memory"};
-
/** @brief Parsing Health config JSON file */
Json parseConfigFile(std::string configFile);