xref: /openbmc/telemetry/src/metric.cpp (revision b8cc78ddf9cc87c83176c7bda575ceef2678d00f)
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         [&notifier](const auto& sensor) { return sensor.get() == &notifier; });
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