1c8e3a64aSKrzysztof Grobelny #include "metric.hpp" 26ccfcbf5SKrzysztof Grobelny 38069771cSKrzysztof Grobelny #include "details/collection_function.hpp" 4dcc4e193SKrzysztof Grobelny #include "types/report_types.hpp" 53a617023SSzymon Dompke #include "utils/labeled_tuple.hpp" 66ccfcbf5SKrzysztof Grobelny #include "utils/transform.hpp" 76ccfcbf5SKrzysztof Grobelny 8*b8cc78ddSKrzysztof Grobelny #include <sdbusplus/exception.hpp> 9*b8cc78ddSKrzysztof Grobelny 106ccfcbf5SKrzysztof Grobelny #include <algorithm> 116ccfcbf5SKrzysztof Grobelny 128069771cSKrzysztof Grobelny class Metric::CollectionData 138069771cSKrzysztof Grobelny { 148069771cSKrzysztof Grobelny public: 158069771cSKrzysztof Grobelny using ReadingItem = details::ReadingItem; 168069771cSKrzysztof Grobelny 178069771cSKrzysztof Grobelny virtual ~CollectionData() = default; 188069771cSKrzysztof Grobelny 198069771cSKrzysztof Grobelny virtual ReadingItem update(uint64_t timestamp) = 0; 208069771cSKrzysztof Grobelny virtual ReadingItem update(uint64_t timestamp, double value) = 0; 218069771cSKrzysztof Grobelny }; 228069771cSKrzysztof Grobelny 238069771cSKrzysztof Grobelny class Metric::DataPoint : public Metric::CollectionData 248069771cSKrzysztof Grobelny { 258069771cSKrzysztof Grobelny public: 268069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp) override 278069771cSKrzysztof Grobelny { 288069771cSKrzysztof Grobelny return ReadingItem{lastTimestamp, lastReading}; 298069771cSKrzysztof Grobelny } 308069771cSKrzysztof Grobelny 318069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp, double reading) override 328069771cSKrzysztof Grobelny { 338069771cSKrzysztof Grobelny lastTimestamp = timestamp; 348069771cSKrzysztof Grobelny lastReading = reading; 358069771cSKrzysztof Grobelny return update(timestamp); 368069771cSKrzysztof Grobelny } 378069771cSKrzysztof Grobelny 388069771cSKrzysztof Grobelny private: 398069771cSKrzysztof Grobelny uint64_t lastTimestamp = 0u; 408069771cSKrzysztof Grobelny double lastReading = 0.0; 418069771cSKrzysztof Grobelny }; 428069771cSKrzysztof Grobelny 438069771cSKrzysztof Grobelny class Metric::DataInterval : public Metric::CollectionData 448069771cSKrzysztof Grobelny { 458069771cSKrzysztof Grobelny public: 468069771cSKrzysztof Grobelny DataInterval(std::shared_ptr<details::CollectionFunction> function, 478069771cSKrzysztof Grobelny CollectionDuration duration) : 488069771cSKrzysztof Grobelny function(std::move(function)), 498069771cSKrzysztof Grobelny duration(duration) 50*b8cc78ddSKrzysztof Grobelny { 51*b8cc78ddSKrzysztof Grobelny if (duration.t.count() == 0) 52*b8cc78ddSKrzysztof Grobelny { 53*b8cc78ddSKrzysztof Grobelny throw sdbusplus::exception::SdBusError( 54*b8cc78ddSKrzysztof Grobelny static_cast<int>(std::errc::invalid_argument), 55*b8cc78ddSKrzysztof Grobelny "Invalid CollectionDuration"); 56*b8cc78ddSKrzysztof Grobelny } 57*b8cc78ddSKrzysztof Grobelny } 588069771cSKrzysztof Grobelny 598069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp) override 608069771cSKrzysztof Grobelny { 618069771cSKrzysztof Grobelny if (readings.size() > 0) 628069771cSKrzysztof Grobelny { 638069771cSKrzysztof Grobelny auto it = readings.begin(); 648069771cSKrzysztof Grobelny for (auto kt = std::next(readings.rbegin()); kt != readings.rend(); 658069771cSKrzysztof Grobelny ++kt) 668069771cSKrzysztof Grobelny { 678069771cSKrzysztof Grobelny const auto& [nextItemTimestamp, nextItemReading] = 688069771cSKrzysztof Grobelny *std::prev(kt); 698069771cSKrzysztof Grobelny if (timestamp >= nextItemTimestamp && 708069771cSKrzysztof Grobelny static_cast<uint64_t>(timestamp - nextItemTimestamp) > 718069771cSKrzysztof Grobelny duration.t.count()) 728069771cSKrzysztof Grobelny { 738069771cSKrzysztof Grobelny it = kt.base(); 748069771cSKrzysztof Grobelny break; 758069771cSKrzysztof Grobelny } 768069771cSKrzysztof Grobelny } 778069771cSKrzysztof Grobelny readings.erase(readings.begin(), it); 788069771cSKrzysztof Grobelny 798069771cSKrzysztof Grobelny if (timestamp > duration.t.count()) 808069771cSKrzysztof Grobelny { 818069771cSKrzysztof Grobelny readings.front().first = std::max( 828069771cSKrzysztof Grobelny readings.front().first, timestamp - duration.t.count()); 838069771cSKrzysztof Grobelny } 848069771cSKrzysztof Grobelny } 858069771cSKrzysztof Grobelny 868069771cSKrzysztof Grobelny return function->calculate(readings, timestamp); 878069771cSKrzysztof Grobelny } 888069771cSKrzysztof Grobelny 898069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp, double reading) override 908069771cSKrzysztof Grobelny { 918069771cSKrzysztof Grobelny readings.emplace_back(timestamp, reading); 928069771cSKrzysztof Grobelny return update(timestamp); 938069771cSKrzysztof Grobelny } 948069771cSKrzysztof Grobelny 958069771cSKrzysztof Grobelny private: 968069771cSKrzysztof Grobelny std::shared_ptr<details::CollectionFunction> function; 978069771cSKrzysztof Grobelny std::vector<ReadingItem> readings; 988069771cSKrzysztof Grobelny CollectionDuration duration; 998069771cSKrzysztof Grobelny }; 1008069771cSKrzysztof Grobelny 1018069771cSKrzysztof Grobelny class Metric::DataStartup : public Metric::CollectionData 1028069771cSKrzysztof Grobelny { 1038069771cSKrzysztof Grobelny public: 1048069771cSKrzysztof Grobelny DataStartup(std::shared_ptr<details::CollectionFunction> function) : 1058069771cSKrzysztof Grobelny function(std::move(function)) 1068069771cSKrzysztof Grobelny {} 1078069771cSKrzysztof Grobelny 1088069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp) override 1098069771cSKrzysztof Grobelny { 1108069771cSKrzysztof Grobelny return function->calculateForStartupInterval(readings, timestamp); 1118069771cSKrzysztof Grobelny } 1128069771cSKrzysztof Grobelny 1138069771cSKrzysztof Grobelny ReadingItem update(uint64_t timestamp, double reading) override 1148069771cSKrzysztof Grobelny { 1158069771cSKrzysztof Grobelny readings.emplace_back(timestamp, reading); 1168069771cSKrzysztof Grobelny return function->calculateForStartupInterval(readings, timestamp); 1178069771cSKrzysztof Grobelny } 1188069771cSKrzysztof Grobelny 1198069771cSKrzysztof Grobelny private: 1208069771cSKrzysztof Grobelny std::shared_ptr<details::CollectionFunction> function; 1218069771cSKrzysztof Grobelny std::vector<ReadingItem> readings; 1228069771cSKrzysztof Grobelny }; 1238069771cSKrzysztof Grobelny 124dcc4e193SKrzysztof Grobelny Metric::Metric(Sensors sensorsIn, OperationType operationTypeIn, 125*b8cc78ddSKrzysztof Grobelny std::string idIn, CollectionTimeScope timeScopeIn, 1268069771cSKrzysztof Grobelny CollectionDuration collectionDurationIn, 1278069771cSKrzysztof Grobelny std::unique_ptr<interfaces::Clock> clockIn) : 128*b8cc78ddSKrzysztof Grobelny id(std::move(idIn)), 129dcc4e193SKrzysztof Grobelny sensors(std::move(sensorsIn)), operationType(operationTypeIn), 1308069771cSKrzysztof Grobelny collectionTimeScope(timeScopeIn), collectionDuration(collectionDurationIn), 1318069771cSKrzysztof Grobelny collectionAlgorithms(makeCollectionData(sensors.size(), operationType, 1328069771cSKrzysztof Grobelny collectionTimeScope, 1338069771cSKrzysztof Grobelny collectionDuration)), 1348069771cSKrzysztof Grobelny clock(std::move(clockIn)) 135dcc4e193SKrzysztof Grobelny { 136*b8cc78ddSKrzysztof Grobelny readings = utils::transform(sensors, [this](const auto& sensor) { 137*b8cc78ddSKrzysztof Grobelny return MetricValue{id, sensor->metadata(), 0.0, 0u}; 138*b8cc78ddSKrzysztof Grobelny }); 139dcc4e193SKrzysztof Grobelny } 1406ccfcbf5SKrzysztof Grobelny 1418069771cSKrzysztof Grobelny Metric::~Metric() = default; 1428069771cSKrzysztof Grobelny 1436ccfcbf5SKrzysztof Grobelny void Metric::initialize() 1446ccfcbf5SKrzysztof Grobelny { 145dcc4e193SKrzysztof Grobelny for (const auto& sensor : sensors) 146dcc4e193SKrzysztof Grobelny { 1476ccfcbf5SKrzysztof Grobelny sensor->registerForUpdates(weak_from_this()); 1486ccfcbf5SKrzysztof Grobelny } 149dcc4e193SKrzysztof Grobelny } 150e8fc5751SKrzysztof Grobelny 1517e098e93SLukasz Kazmierczak void Metric::deinitialize() 1527e098e93SLukasz Kazmierczak { 1537e098e93SLukasz Kazmierczak for (const auto& sensor : sensors) 1547e098e93SLukasz Kazmierczak { 1557e098e93SLukasz Kazmierczak sensor->unregisterFromUpdates(weak_from_this()); 1567e098e93SLukasz Kazmierczak } 1577e098e93SLukasz Kazmierczak } 1587e098e93SLukasz Kazmierczak 1598069771cSKrzysztof Grobelny std::vector<MetricValue> Metric::getReadings() const 160e8fc5751SKrzysztof Grobelny { 1618069771cSKrzysztof Grobelny const auto timestamp = clock->timestamp(); 1628069771cSKrzysztof Grobelny auto resultReadings = readings; 1638069771cSKrzysztof Grobelny 1648069771cSKrzysztof Grobelny for (size_t i = 0; i < resultReadings.size(); ++i) 1658069771cSKrzysztof Grobelny { 1668069771cSKrzysztof Grobelny std::tie(resultReadings[i].timestamp, resultReadings[i].value) = 1678069771cSKrzysztof Grobelny collectionAlgorithms[i]->update(timestamp); 1688069771cSKrzysztof Grobelny } 1698069771cSKrzysztof Grobelny 1708069771cSKrzysztof Grobelny return resultReadings; 1716ccfcbf5SKrzysztof Grobelny } 1726ccfcbf5SKrzysztof Grobelny 173e8fc5751SKrzysztof Grobelny void Metric::sensorUpdated(interfaces::Sensor& notifier, uint64_t timestamp) 1746ccfcbf5SKrzysztof Grobelny { 1758069771cSKrzysztof Grobelny findAssociatedData(notifier).update(timestamp); 1766ccfcbf5SKrzysztof Grobelny } 1776ccfcbf5SKrzysztof Grobelny 178e8fc5751SKrzysztof Grobelny void Metric::sensorUpdated(interfaces::Sensor& notifier, uint64_t timestamp, 1796ccfcbf5SKrzysztof Grobelny double value) 1806ccfcbf5SKrzysztof Grobelny { 1818069771cSKrzysztof Grobelny findAssociatedData(notifier).update(timestamp, value); 1826ccfcbf5SKrzysztof Grobelny } 1836ccfcbf5SKrzysztof Grobelny 1848069771cSKrzysztof Grobelny Metric::CollectionData& 1858069771cSKrzysztof Grobelny Metric::findAssociatedData(const interfaces::Sensor& notifier) 1866ccfcbf5SKrzysztof Grobelny { 187dcc4e193SKrzysztof Grobelny auto it = std::find_if( 188dcc4e193SKrzysztof Grobelny sensors.begin(), sensors.end(), 189dcc4e193SKrzysztof Grobelny [¬ifier](const auto& sensor) { return sensor.get() == ¬ifier; }); 190dcc4e193SKrzysztof Grobelny auto index = std::distance(sensors.begin(), it); 1918069771cSKrzysztof Grobelny return *collectionAlgorithms.at(index); 1926ccfcbf5SKrzysztof Grobelny } 1936ccfcbf5SKrzysztof Grobelny 194d2238194SKrzysztof Grobelny LabeledMetricParameters Metric::dumpConfiguration() const 1956ccfcbf5SKrzysztof Grobelny { 196dcc4e193SKrzysztof Grobelny auto sensorPath = utils::transform(sensors, [this](const auto& sensor) { 197*b8cc78ddSKrzysztof Grobelny return LabeledSensorParameters(sensor->id().service, sensor->id().path, 198*b8cc78ddSKrzysztof Grobelny sensor->metadata()); 199dcc4e193SKrzysztof Grobelny }); 200dcc4e193SKrzysztof Grobelny 201dcc4e193SKrzysztof Grobelny return LabeledMetricParameters(std::move(sensorPath), operationType, id, 202*b8cc78ddSKrzysztof Grobelny collectionTimeScope, collectionDuration); 203dcc4e193SKrzysztof Grobelny } 204dcc4e193SKrzysztof Grobelny 2058069771cSKrzysztof Grobelny std::vector<std::unique_ptr<Metric::CollectionData>> 2068069771cSKrzysztof Grobelny Metric::makeCollectionData(size_t size, OperationType op, 2078069771cSKrzysztof Grobelny CollectionTimeScope timeScope, 2088069771cSKrzysztof Grobelny CollectionDuration duration) 2098069771cSKrzysztof Grobelny { 2108069771cSKrzysztof Grobelny using namespace std::string_literals; 2118069771cSKrzysztof Grobelny 2128069771cSKrzysztof Grobelny std::vector<std::unique_ptr<Metric::CollectionData>> result; 2138069771cSKrzysztof Grobelny 2148069771cSKrzysztof Grobelny result.reserve(size); 2158069771cSKrzysztof Grobelny 2168069771cSKrzysztof Grobelny switch (timeScope) 2178069771cSKrzysztof Grobelny { 2188069771cSKrzysztof Grobelny case CollectionTimeScope::interval: 2198069771cSKrzysztof Grobelny std::generate_n( 2208069771cSKrzysztof Grobelny std::back_inserter(result), size, 2218069771cSKrzysztof Grobelny [cf = details::makeCollectionFunction(op), duration] { 2228069771cSKrzysztof Grobelny return std::make_unique<DataInterval>(cf, duration); 2238069771cSKrzysztof Grobelny }); 2248069771cSKrzysztof Grobelny break; 2258069771cSKrzysztof Grobelny case CollectionTimeScope::point: 2268069771cSKrzysztof Grobelny std::generate_n(std::back_inserter(result), size, 2278069771cSKrzysztof Grobelny [] { return std::make_unique<DataPoint>(); }); 2288069771cSKrzysztof Grobelny break; 2298069771cSKrzysztof Grobelny case CollectionTimeScope::startup: 2308069771cSKrzysztof Grobelny std::generate_n(std::back_inserter(result), size, 2318069771cSKrzysztof Grobelny [cf = details::makeCollectionFunction(op)] { 2328069771cSKrzysztof Grobelny return std::make_unique<DataStartup>(cf); 2338069771cSKrzysztof Grobelny }); 2348069771cSKrzysztof Grobelny break; 2358069771cSKrzysztof Grobelny default: 2368069771cSKrzysztof Grobelny throw std::runtime_error("timeScope: "s + 2378069771cSKrzysztof Grobelny utils::enumToString(timeScope) + 2388069771cSKrzysztof Grobelny " is not supported"s); 2398069771cSKrzysztof Grobelny } 2408069771cSKrzysztof Grobelny 2418069771cSKrzysztof Grobelny return result; 2428069771cSKrzysztof Grobelny } 2438069771cSKrzysztof Grobelny 2443eb56865SSzymon Dompke uint64_t Metric::sensorCount() const 2453eb56865SSzymon Dompke { 2463eb56865SSzymon Dompke return sensors.size(); 2473eb56865SSzymon Dompke } 248