diff options
author | Nan Zhou <nanzhoumails@gmail.com> | 2022-03-28 18:45:00 +0300 |
---|---|---|
committer | Nan Zhou <nanzhoumails@gmail.com> | 2022-04-11 18:42:31 +0300 |
commit | 928fefb9a542b816d7c0418077def2b3874d1b0f (patch) | |
tree | fbbf2c8924b3ffbab4159ce54b9a7c3f1b7e71c6 /redfish-core/lib/sensors.hpp | |
parent | a6b9125ff91500afed34dc923e9bafb90da75ec4 (diff) | |
download | bmcweb-928fefb9a542b816d7c0418077def2b3874d1b0f.tar.xz |
sensor collection: implement efficient expand handler
This change adds an efficient expand handler for $levels=1 expand at the
sensors collection.
Instead of Query one sensor at time, it reuses existing codes for
Thermal and Power (which has AutoExpand), and queries the whole sensor at
one query. It's more efficient than the default expand handler as well
since the default handler stills query all the sensors and filter other
sensors when querying a single sensor.
Performance improves dramatically on a real hardware with 220+ sensors:
Before this change,
time wget -qO-
'http://localhost/redfish/v1/Chassis/xxx/Sensors?$expand=.($levels=1)'
> /tmp/log_slow.json
real 0m33.786s
user 0m0.000s
sys 0m0.000s
After this change
time wget -qO-
'http://localhost/redfish/v1/Chassis/xxx/Sensors?$expand=.($levels=1)'
> /tmp/log_fast.json
real 0m0.769s
user 0m0.010s
sys 0m0.010s
TESTED::
1. QEMU Redfish/IPMI passed
2. Validator passed (though it doesn't support query paramters)
3. Tested on real hardware.
{
"@odata.id": "/redfish/v1/Chassis/xxx/Sensors",
"@odata.type": "#SensorCollection.SensorCollection",
"Description": "Collection of Sensors for this Chassis",
"Members": [
{
"@odata.id": "/redfish/v1/Chassis/xxx/Sensors/abc",
"@odata.type": "#Sensor.v1_0_0.Sensor",
"Id": "abc",
"Name": "abc",
"Reading": 3.133,
"ReadingRangeMax": 5.8500060148599005,
"ReadingRangeMin": 0.0,
"ReadingType": "Voltage",
"ReadingUnits": "V",
"Status": {
"Health": "OK",
"State": "Enabled"
},
"Thresholds": {
"LowerCritical": {
"Reading": 2.205
},
"UpperCritical": {
"Reading": 3.507
}
}
},
],
"Members@odata.count": 225,
"Name": "Sensors"
}
Signed-off-by: Nan Zhou <nanzhoumails@gmail.com>
Change-Id: I745a31d6fe8d0aac08d532ea976bfc1a4a40b19c
Diffstat (limited to 'redfish-core/lib/sensors.hpp')
-rw-r--r-- | redfish-core/lib/sensors.hpp | 124 |
1 files changed, 94 insertions, 30 deletions
diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp index 2e314aca98..ec63945d7c 100644 --- a/redfish-core/lib/sensors.hpp +++ b/redfish-core/lib/sensors.hpp @@ -26,6 +26,7 @@ #include <registries/privilege_registry.hpp> #include <sdbusplus/asio/property.hpp> #include <utils/json_utils.hpp> +#include <utils/query_param.hpp> #include <cmath> #include <utility> @@ -177,7 +178,8 @@ class SensorsAsyncResp const std::vector<const char*>& typesIn, const std::string_view& subNode) : asyncResp(asyncResp), - chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode) + chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode), + efficientExpand(false) {} // Store extra data about sensor mapping and return it in callback @@ -187,11 +189,21 @@ class SensorsAsyncResp const std::string_view& subNode, DataCompleteCb&& creationComplete) : asyncResp(asyncResp), - chassisId(chassisIdIn), types(typesIn), - chassisSubNode(subNode), metadata{std::vector<SensorData>()}, + chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode), + efficientExpand(false), metadata{std::vector<SensorData>()}, dataComplete{std::move(creationComplete)} {} + // sensor collections expand + SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& chassisIdIn, + const std::vector<const char*>& typesIn, + const std::string_view& subNode, bool efficientExpand) : + asyncResp(asyncResp), + chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode), + efficientExpand(efficientExpand) + {} + ~SensorsAsyncResp() { if (asyncResp->res.result() == @@ -252,6 +264,7 @@ class SensorsAsyncResp const std::string chassisId; const std::vector<const char*> types; const std::string chassisSubNode; + const bool efficientExpand; private: std::optional<std::vector<SensorData>> metadata; @@ -2524,7 +2537,8 @@ inline void getSensorData( nlohmann::json* sensorJson = nullptr; - if (sensorSchema == sensors::node::sensors) + if (sensorSchema == sensors::node::sensors && + !sensorsAsyncResp->efficientExpand) { sensorsAsyncResp->asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + @@ -2535,7 +2549,11 @@ inline void getSensorData( else { std::string fieldName; - if (sensorType == "temperature") + if (sensorsAsyncResp->efficientExpand) + { + fieldName = "Members"; + } + else if (sensorType == "temperature") { fieldName = "Temperatures"; } @@ -2599,6 +2617,16 @@ inline void getSensorData( sensorsAsyncResp->chassisId)); } } + else if (fieldName == "Members") + { + tempArray.push_back( + {{"@odata.id", + "/redfish/v1/Chassis/" + + sensorsAsyncResp->chassisId + "/" + + sensorsAsyncResp->chassisSubNode + "/" + + sensorName}}); + sensorJson = &(tempArray.back()); + } else { tempArray.push_back( @@ -2621,7 +2649,17 @@ inline void getSensorData( if (sensorsAsyncResp.use_count() == 1) { sortJSONResponse(sensorsAsyncResp); - if (sensorsAsyncResp->chassisSubNode == sensors::node::thermal) + if (sensorsAsyncResp->chassisSubNode == + sensors::node::sensors && + sensorsAsyncResp->efficientExpand) + { + sensorsAsyncResp->asyncResp->res + .jsonValue["Members@odata.count"] = + sensorsAsyncResp->asyncResp->res.jsonValue["Members"] + .size(); + } + else if (sensorsAsyncResp->chassisSubNode == + sensors::node::thermal) { populateFanRedundancy(sensorsAsyncResp); } @@ -2706,9 +2744,12 @@ inline void processSensorList(sensorsAsyncResp, sensorNames); BMCWEB_LOG_DEBUG << "getChassisCb exit"; }; - sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] = - nlohmann::json::array(); - + // SensorCollection doesn't contain the Redundancy property + if (sensorsAsyncResp->chassisSubNode != sensors::node::sensors) + { + sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] = + nlohmann::json::array(); + } // Get set of sensors in chassis getChassis(sensorsAsyncResp, std::move(getChassisCb)); BMCWEB_LOG_DEBUG << "getChassisData exit"; @@ -2923,6 +2964,7 @@ inline void retrieveUriToDbusMap(const std::string& chassis, namespace sensors { + inline void getChassisCallback( const std::shared_ptr<SensorsAsyncResp>& asyncResp, const std::shared_ptr<boost::container::flat_set<std::string>>& sensorNames) @@ -2958,28 +3000,50 @@ inline void requestRoutesSensorCollection(App& app) { BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/") .privileges(redfish::privileges::getSensorCollection) - .methods(boost::beast::http::verb::get)( - [&app](const crow::Request& req, - const std::shared_ptr<bmcweb::AsyncResp>& aResp, - const std::string& chassisId) { - if (!redfish::setUpRedfishRoute(app, req, aResp->res)) - { - return; - } + .methods( + boost::beast::http::verb::get)([&app]( + const crow::Request& req, + const std::shared_ptr< + bmcweb::AsyncResp>& aResp, + const std::string& chassisId) { + query_param::QueryCapabilities capabilities = { + .canDelegateExpandLevel = 1, + }; + query_param::Query delegatedQuery; + if (!redfish::setUpRedfishRouteWithDelegation( + app, req, aResp->res, delegatedQuery, capabilities)) + { + return; + } - BMCWEB_LOG_DEBUG << "SensorCollection doGet enter"; - - std::shared_ptr<SensorsAsyncResp> asyncResp = - std::make_shared<SensorsAsyncResp>( - aResp, chassisId, - sensors::dbus::paths.at(sensors::node::sensors), - sensors::node::sensors); - // Get set of sensors in chassis - getChassis( - asyncResp, - std::bind_front(sensors::getChassisCallback, asyncResp)); - BMCWEB_LOG_DEBUG << "SensorCollection doGet exit"; - }); + if (delegatedQuery.expandType != query_param::ExpandType::None) + { + // we perform efficient expand. + auto asyncResp = std::make_shared<SensorsAsyncResp>( + aResp, chassisId, + sensors::dbus::paths.at(sensors::node::sensors), + sensors::node::sensors, + /*efficientExpand=*/true); + getChassisData(asyncResp); + + BMCWEB_LOG_DEBUG + << "SensorCollection doGet exit via efficient expand handler"; + return; + }; + + // if there's no efficient expand available, we use the default + // Query Parameters route + auto asyncResp = std::make_shared<SensorsAsyncResp>( + aResp, chassisId, + sensors::dbus::paths.at(sensors::node::sensors), + sensors::node::sensors); + + // We get all sensors as hyperlinkes in the chassis (this + // implies we reply on the default query parameters handler) + getChassis(asyncResp, + std::bind_front(sensors::getChassisCallback, asyncResp)); + BMCWEB_LOG_DEBUG << "SensorCollection doGet exit"; + }); } inline void requestRoutesSensor(App& app) |