Add kernel and user CPU utilization
This adds two utilization sensors, "CPU_Kernel" and "CPU_User" that
are populated with the fraction of CPU processing spent in kernel space
and user space.
The intended use case is BMCWeb can read those sensors from
phosphor-health-monitor and report them in a RedFish response.
The RedFish resources are:
* ManagerDiagnosticData.ProcessorStatistics.KernelPercent
* ManagerDiagnosticData.ProcessorStatistics.UserPercent
Tested: Installed on a QEMU-emulated BMC
bmc# busctl tree xyz.openbmc_project.HealthMon
`-/xyz
`-/xyz/openbmc_project
`-/xyz/openbmc_project/sensors
`-/xyz/openbmc_project/sensors/utilization
|-/xyz/openbmc_project/sensors/utilization/CPU
|-/xyz/openbmc_project/sensors/utilization/CPU_Kernel
`-/xyz/openbmc_project/sensors/utilization/CPU_User
signed-off-by: Sui Chen <suichen@google.com>
Change-Id: Ic6792e4c7cd8eba144eb9adec9366c1bc15b1a44
diff --git a/bmc_health_config.json b/bmc_health_config.json
index b969676..99dde39 100644
--- a/bmc_health_config.json
+++ b/bmc_health_config.json
@@ -4,18 +4,54 @@
"Window_size": 120,
"Threshold":
{
- "Critical":
- {
- "Value": 90.0,
- "Log": true,
- "Target": ""
- },
- "Warning":
- {
- "Value": 80.0,
- "Log": false,
- "Target": ""
- }
+ "Critical":
+ {
+ "Value": 90.0,
+ "Log": true,
+ "Target": ""
+ },
+ "Warning":
+ {
+ "Value": 80.0,
+ "Log": false,
+ "Target": ""
+ }
+ }
+ },
+ "CPU_User" : {
+ "Frequency" : 1,
+ "Window_size": 120,
+ "Threshold": {
+ "Critical":
+ {
+ "Value": 90.0,
+ "Log": true,
+ "Target": ""
+ },
+ "Warning":
+ {
+ "Value": 80.0,
+ "Log": false,
+ "Target": ""
+ }
+ }
+ },
+ "CPU_Kernel" : {
+ "Frequency" : 1,
+ "Window_size": 120,
+ "Threshold": {
+ "Critical":
+ {
+ "Value": 90.0,
+ "Log": true,
+ "Target": ""
+ },
+ "Warning":
+ {
+ "Value": 80.0,
+ "Log": false,
+ "Target": ""
+ }
}
},
"Memory" : {
@@ -37,12 +73,12 @@
"Window_size": 120,
"Threshold":
{
- "Critical":
- {
- "Value": 85.0,
- "Log": true,
- "Target": ""
- }
+ "Critical":
+ {
+ "Value": 85.0,
+ "Log": true,
+ "Target": ""
+ }
}
},
"Storage_TMP" : {
diff --git a/healthMonitor.cpp b/healthMonitor.cpp
index 24cd067..0255f5f 100644
--- a/healthMonitor.cpp
+++ b/healthMonitor.cpp
@@ -103,7 +103,14 @@
NUM_CPU_STATES_TIME
};
-double readCPUUtilization([[maybe_unused]] std::string path)
+enum CPUUtilizationType
+{
+ USER = 0,
+ KERNEL,
+ TOTAL
+};
+
+double readCPUUtilization(enum CPUUtilizationType type)
{
auto proc_stat = "/proc/stat";
std::ifstream fileStat(proc_stat);
@@ -142,22 +149,34 @@
return -1;
}
- static double preActiveTime = 0, preIdleTime = 0;
+ static std::unordered_map<enum CPUUtilizationType, double> preActiveTime,
+ preIdleTime;
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];
+ if (type == TOTAL)
+ {
+ 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];
+ }
+ else if (type == KERNEL)
+ {
+ activeTime = timeData[SYSTEM_IDX];
+ }
+ else if (type == USER)
+ {
+ activeTime = timeData[USER_IDX];
+ }
- idleTimeDiff = idleTime - preIdleTime;
- activeTimeDiff = activeTime - preActiveTime;
+ idleTimeDiff = idleTime - preIdleTime[type];
+ activeTimeDiff = activeTime - preActiveTime[type];
/* Store current idle and active time for next calculation */
- preIdleTime = idleTime;
- preActiveTime = activeTime;
+ preIdleTime[type] = idleTime;
+ preActiveTime[type] = activeTime;
totalTime = idleTimeDiff + activeTimeDiff;
@@ -169,6 +188,21 @@
return activePercValue;
}
+auto readCPUUtilizationTotal([[maybe_unused]] const std::string& path)
+{
+ return readCPUUtilization(CPUUtilizationType::TOTAL);
+}
+
+auto readCPUUtilizationKernel([[maybe_unused]] const std::string& path)
+{
+ return readCPUUtilization(CPUUtilizationType::KERNEL);
+}
+
+auto readCPUUtilizationUser([[maybe_unused]] const std::string& path)
+{
+ return readCPUUtilization(CPUUtilizationType::USER);
+}
+
double readMemoryUtilization([[maybe_unused]] const std::string& path)
{
/* Unused var: path */
@@ -283,9 +317,18 @@
constexpr auto storage = "Storage";
constexpr auto inode = "Inode";
-/** Map of read function for each health sensors supported */
+
+/** Map of read function for each health sensors supported
+ *
+ * The following health sensors are read in the ManagerDiagnosticData
+ * Redfish resource:
+ * - CPU_Kernel populates ProcessorStatistics.KernelPercent
+ * - CPU_User populates ProcessorStatistics.UserPercent
+ */
const std::map<std::string, std::function<double(const std::string& path)>>
- readSensors = {{"CPU", readCPUUtilization},
+ readSensors = {{"CPU", readCPUUtilizationTotal},
+ {"CPU_Kernel", readCPUUtilizationKernel},
+ {"CPU_User", readCPUUtilizationUser},
{"Memory", readMemoryUtilization},
{storage, readStorageUtilization},
{inode, readInodeUtilization}};
@@ -582,7 +625,6 @@
{
std::vector<HealthConfig> cfgs;
- HealthConfig cfg;
auto data = parseConfigFile(HEALTH_CONFIG_FILE);
// print values