cpusensor: Change cpusensor to intelcpusensor
cpusensor class is specifically used for Intel CPU. The name of this
class and the build option should be changed to reflect with their
role.
The patch set https://gerrit.openbmc.org/c/openbmc/openbmc/+/56096 is
required to prevent the build error in openbmc source.
Tested:
1. No build error.
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: I1f941fffa10222cdac908fd763dccc866ba0e8a6
diff --git a/src/IntelCPUSensor.cpp b/src/IntelCPUSensor.cpp
new file mode 100644
index 0000000..79a51ed
--- /dev/null
+++ b/src/IntelCPUSensor.cpp
@@ -0,0 +1,332 @@
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <unistd.h>
+
+#include <IntelCPUSensor.hpp>
+#include <Utils.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/asio/read_until.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+#include <cstddef>
+#include <iostream>
+#include <istream>
+#include <limits>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+IntelCPUSensor::IntelCPUSensor(
+ const std::string& path, const std::string& objectType,
+ sdbusplus::asio::object_server& objectServer,
+ std::shared_ptr<sdbusplus::asio::connection>& conn,
+ boost::asio::io_service& io, const std::string& sensorName,
+ std::vector<thresholds::Threshold>&& thresholdsIn,
+ const std::string& sensorConfiguration, int cpuId, bool show,
+ double dtsOffset) :
+ Sensor(escapeName(sensorName), std::move(thresholdsIn), sensorConfiguration,
+ objectType, false, false, 0, 0, conn, PowerState::on),
+ objServer(objectServer), inputDev(io), waitTimer(io),
+ nameTcontrol("Tcontrol CPU" + std::to_string(cpuId)), path(path),
+ privTcontrol(std::numeric_limits<double>::quiet_NaN()),
+ dtsOffset(dtsOffset), show(show), pollTime(IntelCPUSensor::sensorPollMs)
+
+{
+ if (show)
+ {
+ if (auto fileParts = splitFileName(path))
+ {
+ auto& [type, nr, item] = *fileParts;
+ std::string interfacePath;
+ const char* units = nullptr;
+ if (type == "power")
+ {
+ interfacePath = "/xyz/openbmc_project/sensors/power/" + name;
+ units = sensor_paths::unitWatts;
+ minValue = 0;
+ maxValue = 511;
+ }
+ else
+ {
+ interfacePath =
+ "/xyz/openbmc_project/sensors/temperature/" + name;
+ units = sensor_paths::unitDegreesC;
+ minValue = -128;
+ maxValue = 127;
+ }
+
+ sensorInterface = objectServer.add_interface(
+ interfacePath, "xyz.openbmc_project.Sensor.Value");
+ for (const auto& threshold : thresholds)
+ {
+ std::string interface =
+ thresholds::getInterface(threshold.level);
+ thresholdInterfaces[static_cast<size_t>(threshold.level)] =
+ objectServer.add_interface(interfacePath, interface);
+ }
+ association = objectServer.add_interface(interfacePath,
+ association::interface);
+
+ setInitialProperties(units);
+ }
+ }
+
+ // call setup always as not all sensors call setInitialProperties
+ setupPowerMatch(conn);
+}
+
+IntelCPUSensor::~IntelCPUSensor()
+{
+ // close the input dev to cancel async operations
+ inputDev.close();
+ waitTimer.cancel();
+ if (show)
+ {
+ for (const auto& iface : thresholdInterfaces)
+ {
+ objServer.remove_interface(iface);
+ }
+ objServer.remove_interface(sensorInterface);
+ objServer.remove_interface(association);
+ objServer.remove_interface(availableInterface);
+ objServer.remove_interface(operationalInterface);
+ }
+}
+
+void IntelCPUSensor::restartRead(void)
+{
+ std::weak_ptr<IntelCPUSensor> weakRef = weak_from_this();
+ waitTimer.expires_from_now(boost::posix_time::milliseconds(pollTime));
+ waitTimer.async_wait([weakRef](const boost::system::error_code& ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ std::cerr << "Failed to reschedule\n";
+ return;
+ }
+ std::shared_ptr<IntelCPUSensor> self = weakRef.lock();
+
+ if (self)
+ {
+ self->setupRead();
+ }
+ });
+}
+
+void IntelCPUSensor::setupRead(void)
+{
+ if (readingStateGood())
+ {
+ inputDev.close();
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
+ fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
+ if (fd < 0)
+ {
+ std::cerr << name << " unable to open fd!\n";
+ return;
+ }
+
+ inputDev.assign(fd);
+ }
+ else
+ {
+ markAvailable(false);
+ updateValue(std::numeric_limits<double>::quiet_NaN());
+ restartRead();
+ return;
+ }
+
+ std::weak_ptr<IntelCPUSensor> weakRef = weak_from_this();
+ inputDev.async_wait(boost::asio::posix::descriptor_base::wait_read,
+ [weakRef](const boost::system::error_code& ec) {
+ std::shared_ptr<IntelCPUSensor> self = weakRef.lock();
+
+ if (self)
+ {
+ self->handleResponse(ec);
+ }
+ });
+}
+
+void IntelCPUSensor::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 = splitFileName(path))
+ {
+ auto& [fileType, fileNr, fileItem] = *fileParts;
+ const auto mapIt = map.find(fileItem);
+ if (mapIt != map.cend())
+ {
+ for (const auto& vectorItem : mapIt->second)
+ {
+ const auto& [suffix, oldValue, dbusName] = vectorItem;
+ auto attrPath = boost::replace_all_copy(path, fileItem, suffix);
+ if (auto newVal =
+ readFile(attrPath, IntelCPUSensor::sensorScaleFactor))
+ {
+ updateProperty(sensorInterface, oldValue, *newVal,
+ dbusName);
+ }
+ else
+ {
+ if (isPowerOn())
+ {
+ updateProperty(sensorInterface, oldValue, 0, dbusName);
+ }
+ else
+ {
+ updateProperty(sensorInterface, oldValue,
+ std::numeric_limits<double>::quiet_NaN(),
+ dbusName);
+ }
+ }
+ }
+ }
+ }
+}
+
+void IntelCPUSensor::handleResponse(const boost::system::error_code& err)
+{
+ if ((err == boost::system::errc::bad_file_descriptor) ||
+ (err == boost::asio::error::misc_errors::not_found))
+ {
+ return; // we're being destroyed
+ }
+ if (err == boost::system::errc::operation_canceled)
+ {
+ if (readingStateGood())
+ {
+ if (!loggedInterfaceDown)
+ {
+ std::cerr << name << " interface down!\n";
+ loggedInterfaceDown = true;
+ }
+ pollTime = static_cast<size_t>(IntelCPUSensor::sensorPollMs) * 10U;
+ markFunctional(false);
+ }
+ return;
+ }
+ loggedInterfaceDown = false;
+
+ if (err)
+ {
+ pollTime = sensorFailedPollTimeMs;
+ incrementError();
+ return;
+ }
+
+ static constexpr uint32_t bufLen = 128;
+ std::string response;
+ response.resize(bufLen);
+ int rdLen = 0;
+
+ if (fd >= 0)
+ {
+ rdLen = pread(fd, response.data(), bufLen, 0);
+ }
+
+ if (rdLen > 0)
+ {
+
+ try
+ {
+ rawValue = std::stod(response);
+ double nvalue = rawValue / IntelCPUSensor::sensorScaleFactor;
+
+ if (show)
+ {
+ updateValue(nvalue);
+ }
+ else
+ {
+ value = nvalue;
+ }
+ if (minMaxReadCounter++ % 8 == 0)
+ {
+ updateMinMaxValues();
+ }
+
+ double gTcontrol = gCpuSensors[nameTcontrol]
+ ? gCpuSensors[nameTcontrol]->value
+ : std::numeric_limits<double>::quiet_NaN();
+ if (gTcontrol != privTcontrol)
+ {
+ privTcontrol = gTcontrol;
+
+ if (!thresholds.empty())
+ {
+ std::vector<thresholds::Threshold> newThresholds;
+ if (parseThresholdsFromAttr(
+ newThresholds, path,
+ IntelCPUSensor::sensorScaleFactor, dtsOffset))
+ {
+ if (!std::equal(thresholds.begin(), thresholds.end(),
+ newThresholds.begin(),
+ newThresholds.end()))
+ {
+ thresholds = newThresholds;
+ if (show)
+ {
+ thresholds::updateThresholds(this);
+ }
+ }
+ }
+ else
+ {
+ std::cerr << "Failure to update thresholds for " << name
+ << "\n";
+ }
+ }
+ }
+ }
+ catch (const std::invalid_argument&)
+ {
+ incrementError();
+ }
+ }
+ else
+ {
+ pollTime = sensorFailedPollTimeMs;
+ incrementError();
+ }
+ restartRead();
+}
+
+void IntelCPUSensor::checkThresholds(void)
+{
+ if (show)
+ {
+ thresholds::checkThresholds(this);
+ }
+}