control: Add net target decrease action
Add the YAML based set_net_speed_decrease action function as an action
class for JSON configs to use.
Change-Id: Ibbd784586318dffd795123128f0988faec46ce8f
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/Makefile.am b/control/Makefile.am
index d6fa5a5..1088ce0 100644
--- a/control/Makefile.am
+++ b/control/Makefile.am
@@ -35,7 +35,8 @@
json/actions/request_target_base.cpp \
json/actions/missing_owner_target.cpp \
json/actions/count_state_target.cpp \
- json/actions/net_target_increase.cpp
+ json/actions/net_target_increase.cpp \
+ json/actions/net_target_decrease.cpp
else
phosphor_fan_control_SOURCES += \
argument.cpp \
diff --git a/control/json/actions/net_target_decrease.cpp b/control/json/actions/net_target_decrease.cpp
new file mode 100644
index 0000000..4664238
--- /dev/null
+++ b/control/json/actions/net_target_decrease.cpp
@@ -0,0 +1,151 @@
+/**
+ * Copyright © 2021 IBM 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 "net_target_decrease.hpp"
+
+#include "../manager.hpp"
+#include "../zone.hpp"
+#include "action.hpp"
+#include "group.hpp"
+
+#include <fmt/format.h>
+
+#include <nlohmann/json.hpp>
+#include <phosphor-logging/log.hpp>
+
+#include <algorithm>
+#include <variant>
+
+namespace phosphor::fan::control::json
+{
+
+using json = nlohmann::json;
+using namespace phosphor::logging;
+
+NetTargetDecrease::NetTargetDecrease(const json& jsonObj) : ActionBase(jsonObj)
+{
+ setState(jsonObj);
+ setDelta(jsonObj);
+}
+
+void NetTargetDecrease::run(Zone& zone, const Group& group)
+{
+ auto netDelta = zone.getDecDelta();
+ for (const auto& member : group.getMembers())
+ {
+ try
+ {
+ auto value = Manager::getObjValueVariant(
+ member, group.getInterface(), group.getProperty());
+ if (std::holds_alternative<int64_t>(value) ||
+ std::holds_alternative<double>(value))
+ {
+ if (value >= _state)
+ {
+ // No decrease allowed for this group
+ netDelta = 0;
+ break;
+ }
+ else
+ {
+ // Decrease factor is the difference in configured state to
+ // the current value's state
+ uint64_t deltaFactor = 0;
+ if (auto dblPtr = std::get_if<double>(&value))
+ {
+ deltaFactor = static_cast<uint64_t>(
+ std::get<double>(_state) - *dblPtr);
+ }
+ else
+ {
+ deltaFactor =
+ static_cast<uint64_t>(std::get<int64_t>(_state) -
+ std::get<int64_t>(value));
+ }
+
+ // Multiply the decrease factor by the configured delta to
+ // get the net decrease delta for the given group member.
+ // The lowest net decrease delta of the entire group is the
+ // decrease requested.
+ if (netDelta == 0)
+ {
+ netDelta = deltaFactor * _delta;
+ }
+ else
+ {
+ netDelta = std::min(netDelta, deltaFactor * _delta);
+ }
+ }
+ }
+ else if (std::holds_alternative<bool>(value) ||
+ std::holds_alternative<std::string>(value))
+ {
+ // Where a group of booleans or strings equal the state
+ // provided, request a decrease of the configured delta
+ if (_state == value)
+ {
+ if (netDelta == 0)
+ {
+ netDelta = _delta;
+ }
+ else
+ {
+ netDelta = std::min(netDelta, _delta);
+ }
+ }
+ }
+ else
+ {
+ // Unsupported group member type for this action
+ log<level::ERR>(
+ fmt::format("Action {}: Unsupported group member type "
+ "given. [object = {} : {} : {}]",
+ ActionBase::getName(), member,
+ group.getInterface(), group.getProperty())
+ .c_str());
+ }
+ }
+ catch (const std::out_of_range& oore)
+ {
+ // Property value not found, netDelta unchanged
+ }
+ }
+ // Update group's decrease allowed state
+ zone.setDecreaseAllow(group.getName(), !(netDelta == 0));
+ // Request target decrease to occur on decrease interval
+ zone.requestDecrease(netDelta);
+}
+
+void NetTargetDecrease::setState(const json& jsonObj)
+{
+ if (!jsonObj.contains("state"))
+ {
+ throw ActionParseError{ActionBase::getName(),
+ "Missing required state value"};
+ }
+ _state = getJsonValue(jsonObj["state"]);
+}
+
+void NetTargetDecrease::setDelta(const json& jsonObj)
+{
+ if (!jsonObj.contains("delta"))
+ {
+ throw ActionParseError{ActionBase::getName(),
+ "Missing required delta value"};
+ }
+ _delta = jsonObj["delta"].get<uint64_t>();
+}
+
+} // namespace phosphor::fan::control::json
diff --git a/control/json/actions/net_target_decrease.hpp b/control/json/actions/net_target_decrease.hpp
new file mode 100644
index 0000000..cc09705
--- /dev/null
+++ b/control/json/actions/net_target_decrease.hpp
@@ -0,0 +1,108 @@
+/**
+ * Copyright © 2021 IBM 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.
+ */
+#pragma once
+
+#include "../zone.hpp"
+#include "action.hpp"
+#include "group.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <optional>
+
+namespace phosphor::fan::control::json
+{
+
+using json = nlohmann::json;
+
+/**
+ * @class NetTargetDecrease - Action to determine the net target decrease to
+ * request
+ *
+ * Calculates the net target decrease to be requested based on the value of each
+ * property given within a group. The net target decrease is the minimum delta
+ * determined from all of the properties of the group. This net target decrease
+ * is the decrease change that's requested to the current target of a zone.
+ */
+class NetTargetDecrease :
+ public ActionBase,
+ public ActionRegister<NetTargetDecrease>
+{
+ public:
+ /* Name of this action */
+ static constexpr auto name = "set_net_decrease_speed";
+
+ NetTargetDecrease() = delete;
+ NetTargetDecrease(const NetTargetDecrease&) = delete;
+ NetTargetDecrease(NetTargetDecrease&&) = delete;
+ NetTargetDecrease& operator=(const NetTargetDecrease&) = delete;
+ NetTargetDecrease& operator=(NetTargetDecrease&&) = delete;
+ ~NetTargetDecrease() = default;
+
+ /**
+ * @brief Determine/Set the net target decrease
+ *
+ * @param[in] jsonObj - JSON configuration of this action
+ */
+ explicit NetTargetDecrease(const json& jsonObj);
+
+ /**
+ * @brief Run the action
+ *
+ * Determines the net target decrease delta to be requested based on the
+ * property values of the group of dbus objects and requests this target
+ * decrease on the zone. The property values of the group is compared to
+ * the configured state value to determine if an decrease delta should be
+ * requested. For boolean & string values, the configured delta is
+ * requested when a property of the group equals the configured state. For
+ * integer & double values, the configured delta is multiplied by the
+ * difference in property value and the configured state resulting in a net
+ * target decrease for each group member. After all members of the group of
+ * dbus objects are processed, the minimum net target decrease calculated is
+ * requested on the zone.
+ *
+ * @param[in] zone - Zone to run the action on
+ * @param[in] group - Group of dbus objects the action runs against
+ */
+ void run(Zone& zone, const Group& group) override;
+
+ private:
+ /* State the members must be at to decrease the target */
+ PropertyVariantType _state;
+
+ /* Decrease delta for this action */
+ uint64_t _delta;
+
+ /**
+ * @brief Parse and set the state
+ *
+ * @param[in] jsonObj - JSON object for the action
+ *
+ * Sets the state to compare members to
+ */
+ void setState(const json& jsonObj);
+
+ /**
+ * @brief Parse and set the delta
+ *
+ * @param[in] jsonObj - JSON object for the action
+ *
+ * Sets the decrease delta to use when running the action
+ */
+ void setDelta(const json& jsonObj);
+};
+
+} // namespace phosphor::fan::control::json
diff --git a/control/json/zone.cpp b/control/json/zone.cpp
index 6dd4618..e11e6fc 100644
--- a/control/json/zone.cpp
+++ b/control/json/zone.cpp
@@ -51,8 +51,8 @@
Zone::Zone(sdbusplus::bus::bus& bus, const json& jsonObj) :
ConfigBase(jsonObj),
ThermalObject(bus, (fs::path{CONTROL_OBJPATH} /= getName()).c_str(), true),
- _incDelay(0), _floor(0), _target(0), _incDelta(0), _requestTargetBase(0),
- _isActive(true)
+ _incDelay(0), _floor(0), _target(0), _incDelta(0), _decDelta(0),
+ _requestTargetBase(0), _isActive(true)
{
// Increase delay is optional, defaults to 0
if (jsonObj.contains("increase_delay"))
@@ -136,6 +136,15 @@
}
}
+void Zone::requestDecrease(uint64_t targetDelta)
+{
+ // Only decrease the lowest target delta requested
+ if (_decDelta == 0 || targetDelta < _decDelta)
+ {
+ _decDelta = targetDelta;
+ }
+}
+
void Zone::setPersisted(const std::string& intf, const std::string& prop)
{
if (std::find_if(_propsPersisted[intf].begin(), _propsPersisted[intf].end(),
diff --git a/control/json/zone.hpp b/control/json/zone.hpp
index 2f6e925..3ae8139 100644
--- a/control/json/zone.hpp
+++ b/control/json/zone.hpp
@@ -146,6 +146,16 @@
};
/**
+ * @brief Get the target decrease delta
+ *
+ * @return - The current target decrease delta
+ */
+ inline auto& getDecDelta() const
+ {
+ return _decDelta;
+ };
+
+ /**
* @brief Add a fan object to the zone
*
* @param[in] fan - Unique pointer to a fan object that will be moved into
@@ -191,6 +201,17 @@
}
/**
+ * @brief Sets the decrease allowed state of a group
+ *
+ * @param[in] ident - An identifier that affects speed decreases
+ * @param[in] isAllow - Allow state according to the identifier
+ */
+ inline void setDecreaseAllow(const std::string& ident, bool isAllow)
+ {
+ _decAllowed[ident] = isAllow;
+ }
+
+ /**
* @brief Calculate the requested target from the given delta and increases
* the fans, not going above the ceiling.
*
@@ -199,6 +220,14 @@
void requestIncrease(uint64_t targetDelta);
/**
+ * @brief Calculate the lowest requested decrease target from the given
+ * delta within a decrease interval.
+ *
+ * @param[in] targetDelta - The delta to decrease the target by
+ */
+ void requestDecrease(uint64_t targetDelta);
+
+ /**
* @brief Set the requested target base to be used as the target to base a
* new requested target from
*
@@ -300,6 +329,9 @@
/* Zone increase delta */
uint64_t _incDelta;
+ /* Zone decrease delta */
+ uint64_t _decDelta;
+
/* The ceiling target to not go above */
uint64_t _ceiling;
@@ -309,6 +341,9 @@
/* Map of whether floor changes are allowed by a string identifier */
std::map<std::string, bool> _floorChange;
+ /* Map of controlling decreases allowed by a string identifer */
+ std::map<std::string, bool> _decAllowed;
+
/* Map of interfaces to persisted properties the zone hosts*/
std::map<std::string, std::vector<std::string>> _propsPersisted;