Exposing power capping values as a sensor
This implementation introduces support for power capping values provided
by hwmon. Values are read from files with suffix cap, cap_max and cap_min
and are exposed as properties of the interface xyz.openbmc_project.Sensor.Value
The property Value is taken from the power[N]_cap file in a standard way.
While the MaxValue and MinValue are periodically read from the corresponding
files: power[N]_cap_max and power[N]_cap_min. If cap_max, cap_min files cannot
be read properties MinValue/MaxValue are set to 0 unless the power is OFF then
NaN is returned. For other types of files than ‘cap’ default CPUSensor MinValue,
MaxValue values are used as it was before this change.
Link to sysfs file descriptions:
https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
Tested: Test were done manually, no regression detected.
Signed-off-by: Zbigniew Kurzynski <zbigniew.kurzynski@intel.com>
Change-Id: I72fd85f3f441b8a430b9dadd47c874eec52b7829
diff --git a/include/CPUSensor.hpp b/include/CPUSensor.hpp
index 0bcf3ed..e76ec89 100644
--- a/include/CPUSensor.hpp
+++ b/include/CPUSensor.hpp
@@ -48,6 +48,10 @@
void setupRead(void);
void handleResponse(const boost::system::error_code& err);
void checkThresholds(void) override;
+ void updateMinMaxValues(void);
+ bool areDifferent(const double& lVal, const double& rVal);
+ void genericUpdateValue(double& oldValue, const double& newValue,
+ const char* dbusParamName);
};
extern boost::container::flat_map<std::string, std::unique_ptr<CPUSensor>>
diff --git a/include/Thresholds.hpp b/include/Thresholds.hpp
index fe27474..56bb541 100644
--- a/include/Thresholds.hpp
+++ b/include/Thresholds.hpp
@@ -131,6 +131,8 @@
// This function returns optionally these 3 elements as a tuple.
std::optional<std::tuple<std::string, std::string, std::string>>
splitFileName(const std::filesystem::path& filePath);
+std::optional<double> readFile(const std::string& thresholdFile,
+ const double& scaleFactor);
bool parseThresholdsFromConfig(
const SensorData& sensorData,
diff --git a/src/CPUSensor.cpp b/src/CPUSensor.cpp
index ea869c9..6a803e2 100644
--- a/src/CPUSensor.cpp
+++ b/src/CPUSensor.cpp
@@ -51,7 +51,6 @@
{
nameTcontrol = labelTcontrol;
nameTcontrol += " CPU" + std::to_string(cpuId);
-
if (show)
{
if (auto fileParts = thresholds::splitFileName(path))
@@ -114,6 +113,83 @@
std::size_t /*bytes_transfered*/) { handleResponse(ec); });
}
+void CPUSensor::updateMinMaxValues(void)
+{
+ const boost::container::flat_map<
+ std::string,
+ std::vector<std::tuple<const char*, std::reference_wrapper<double>,
+ const char*>>>
+ map = {
+ {
+ "cap",
+ {
+ std::make_tuple("cap_max", std::ref(maxValue), "MaxValue"),
+ std::make_tuple("cap_min", std::ref(minValue), "MinValue"),
+ },
+ },
+ };
+
+ if (auto fileParts = thresholds::splitFileName(path))
+ {
+ auto [fileType, fileNr, fileItem] = *fileParts;
+ const auto mapIt = map.find(fileItem);
+ if (mapIt != map.cend())
+ {
+ for (const auto& vectorItem : mapIt->second)
+ {
+ auto [suffix, oldValue, dbusName] = vectorItem;
+ auto attrPath = boost::replace_all_copy(path, fileItem, suffix);
+ if (auto newVal = thresholds::readFile(
+ attrPath, CPUSensor::sensorScaleFactor))
+ {
+ genericUpdateValue(oldValue, *newVal, dbusName);
+ }
+ else
+ {
+ if (isPowerOn())
+ {
+ genericUpdateValue(oldValue, 0, dbusName);
+ }
+ else
+ {
+ genericUpdateValue(
+ oldValue, std::numeric_limits<double>::quiet_NaN(),
+ dbusName);
+ }
+ }
+ }
+ }
+ }
+}
+
+bool CPUSensor::areDifferent(const double& lVal, const double& rVal)
+{
+ if (std::isnan(lVal) || std::isnan(rVal))
+ {
+ return !(std::isnan(lVal) && std::isnan(rVal));
+ }
+ double diff = std::abs(lVal - rVal);
+ if (diff > hysteresisPublish)
+ {
+ return true;
+ }
+ return false;
+}
+
+void CPUSensor::genericUpdateValue(double& oldValue, const double& newValue,
+ const char* dbusParamName)
+{
+ if (areDifferent(oldValue, newValue))
+ {
+ oldValue = newValue;
+ if (!(sensorInterface->set_property(dbusParamName, newValue)))
+ {
+ std::cerr << "Error setting property " << dbusParamName << " to "
+ << newValue << "\n";
+ }
+ }
+}
+
void CPUSensor::handleResponse(const boost::system::error_code& err)
{
if (err == boost::system::errc::bad_file_descriptor)
@@ -140,6 +216,7 @@
{
value = nvalue;
}
+ updateMinMaxValues();
double gTcontrol = gCpuSensors[nameTcontrol]
? gCpuSensors[nameTcontrol]->value
diff --git a/src/CPUSensorMain.cpp b/src/CPUSensorMain.cpp
index 6b04fd1..42336c6 100644
--- a/src/CPUSensorMain.cpp
+++ b/src/CPUSensorMain.cpp
@@ -267,7 +267,7 @@
auto directory = hwmonNamePath.parent_path();
std::vector<fs::path> inputPaths;
- if (!findFiles(directory, R"((temp|power)\d+_(input|average)$)",
+ if (!findFiles(directory, R"((temp|power)\d+_(input|average|cap)$)",
inputPaths, 0))
{
std::cerr << "No temperature sensors in system\n";