xref: /openbmc/telemetry/src/metric.cpp (revision cff70c14ef8cadb7fffd0cd41e06b972fa240e56)
1c8e3a64aSKrzysztof Grobelny #include "metric.hpp"
26ccfcbf5SKrzysztof Grobelny 
3f7ea2997SKrzysztof Grobelny #include "metrics/collection_data.hpp"
4dcc4e193SKrzysztof Grobelny #include "types/report_types.hpp"
594f71c51SSzymon Dompke #include "types/sensor_types.hpp"
63a617023SSzymon Dompke #include "utils/labeled_tuple.hpp"
76ccfcbf5SKrzysztof Grobelny #include "utils/transform.hpp"
86ccfcbf5SKrzysztof Grobelny 
9b8cc78ddSKrzysztof Grobelny #include <sdbusplus/exception.hpp>
10b8cc78ddSKrzysztof Grobelny 
116ccfcbf5SKrzysztof Grobelny #include <algorithm>
126ccfcbf5SKrzysztof Grobelny 
13dcc4e193SKrzysztof Grobelny Metric::Metric(Sensors sensorsIn, OperationType operationTypeIn,
14*cff70c14SKrzysztof Grobelny                CollectionTimeScope timeScopeIn,
158069771cSKrzysztof Grobelny                CollectionDuration collectionDurationIn,
168069771cSKrzysztof Grobelny                std::unique_ptr<interfaces::Clock> clockIn) :
17*cff70c14SKrzysztof Grobelny     sensors(std::move(sensorsIn)),
18*cff70c14SKrzysztof Grobelny     operationType(operationTypeIn), collectionTimeScope(timeScopeIn),
19*cff70c14SKrzysztof Grobelny     collectionDuration(collectionDurationIn),
20f7ea2997SKrzysztof Grobelny     collectionAlgorithms(
21f7ea2997SKrzysztof Grobelny         metrics::makeCollectionData(sensors.size(), operationType,
22f7ea2997SKrzysztof Grobelny                                     collectionTimeScope, collectionDuration)),
238069771cSKrzysztof Grobelny     clock(std::move(clockIn))
249e8da546SKrzysztof Grobelny {}
256ccfcbf5SKrzysztof Grobelny 
26f7ea2997SKrzysztof Grobelny void Metric::registerForUpdates(interfaces::MetricListener& listener)
27f7ea2997SKrzysztof Grobelny {
28f7ea2997SKrzysztof Grobelny     listeners.emplace_back(listener);
29f7ea2997SKrzysztof Grobelny }
30f7ea2997SKrzysztof Grobelny 
31f7ea2997SKrzysztof Grobelny void Metric::unregisterFromUpdates(interfaces::MetricListener& listener)
32f7ea2997SKrzysztof Grobelny {
333a1c297aSPatrick Williams     listeners.erase(std::remove_if(
343a1c297aSPatrick Williams                         listeners.begin(), listeners.end(),
35f7ea2997SKrzysztof Grobelny                         [&listener](const interfaces::MetricListener& item) {
36f7ea2997SKrzysztof Grobelny         return &item == &listener;
37f7ea2997SKrzysztof Grobelny                         }),
38f7ea2997SKrzysztof Grobelny                     listeners.end());
39f7ea2997SKrzysztof Grobelny }
408069771cSKrzysztof Grobelny 
416ccfcbf5SKrzysztof Grobelny void Metric::initialize()
426ccfcbf5SKrzysztof Grobelny {
43dcc4e193SKrzysztof Grobelny     for (const auto& sensor : sensors)
44dcc4e193SKrzysztof Grobelny     {
456ccfcbf5SKrzysztof Grobelny         sensor->registerForUpdates(weak_from_this());
466ccfcbf5SKrzysztof Grobelny     }
47dcc4e193SKrzysztof Grobelny }
48e8fc5751SKrzysztof Grobelny 
497e098e93SLukasz Kazmierczak void Metric::deinitialize()
507e098e93SLukasz Kazmierczak {
517e098e93SLukasz Kazmierczak     for (const auto& sensor : sensors)
527e098e93SLukasz Kazmierczak     {
537e098e93SLukasz Kazmierczak         sensor->unregisterFromUpdates(weak_from_this());
547e098e93SLukasz Kazmierczak     }
557e098e93SLukasz Kazmierczak }
567e098e93SLukasz Kazmierczak 
579e8da546SKrzysztof Grobelny const std::vector<MetricValue>& Metric::getUpdatedReadings()
58e8fc5751SKrzysztof Grobelny {
5951f0fd50SKrzysztof Grobelny     const auto steadyTimestamp = clock->steadyTimestamp();
609e8da546SKrzysztof Grobelny     const auto systemTimestamp =
619e8da546SKrzysztof Grobelny         std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
629e8da546SKrzysztof Grobelny             .count();
6351f0fd50SKrzysztof Grobelny 
649e8da546SKrzysztof Grobelny     for (size_t i = 0; i < collectionAlgorithms.size(); ++i)
658069771cSKrzysztof Grobelny     {
6651f0fd50SKrzysztof Grobelny         if (const auto value = collectionAlgorithms[i]->update(steadyTimestamp))
6751f0fd50SKrzysztof Grobelny         {
689e8da546SKrzysztof Grobelny             if (i < readings.size())
699e8da546SKrzysztof Grobelny             {
709e8da546SKrzysztof Grobelny                 readings[i].timestamp = systemTimestamp;
719e8da546SKrzysztof Grobelny                 readings[i].value = *value;
729e8da546SKrzysztof Grobelny             }
739e8da546SKrzysztof Grobelny             else
749e8da546SKrzysztof Grobelny             {
759e8da546SKrzysztof Grobelny                 if (i > readings.size())
769e8da546SKrzysztof Grobelny                 {
779e8da546SKrzysztof Grobelny                     const auto idx = readings.size();
789e8da546SKrzysztof Grobelny                     std::swap(collectionAlgorithms[i],
799e8da546SKrzysztof Grobelny                               collectionAlgorithms[idx]);
809e8da546SKrzysztof Grobelny                     std::swap(sensors[i], sensors[idx]);
819e8da546SKrzysztof Grobelny                     i = idx;
829e8da546SKrzysztof Grobelny                 }
839e8da546SKrzysztof Grobelny 
84*cff70c14SKrzysztof Grobelny                 readings.emplace_back(sensors[i]->metadata(), *value,
859e8da546SKrzysztof Grobelny                                       systemTimestamp);
869e8da546SKrzysztof Grobelny             }
8751f0fd50SKrzysztof Grobelny         }
888069771cSKrzysztof Grobelny     }
898069771cSKrzysztof Grobelny 
909e8da546SKrzysztof Grobelny     return readings;
916ccfcbf5SKrzysztof Grobelny }
926ccfcbf5SKrzysztof Grobelny 
9351f0fd50SKrzysztof Grobelny void Metric::sensorUpdated(interfaces::Sensor& notifier, Milliseconds timestamp,
946ccfcbf5SKrzysztof Grobelny                            double value)
956ccfcbf5SKrzysztof Grobelny {
96f7ea2997SKrzysztof Grobelny     auto& data = findAssociatedData(notifier);
97f7ea2997SKrzysztof Grobelny     double newValue = data.update(timestamp, value);
98f7ea2997SKrzysztof Grobelny 
99f7ea2997SKrzysztof Grobelny     if (data.updateLastValue(newValue))
100f7ea2997SKrzysztof Grobelny     {
101f7ea2997SKrzysztof Grobelny         for (interfaces::MetricListener& listener : listeners)
102f7ea2997SKrzysztof Grobelny         {
103f7ea2997SKrzysztof Grobelny             listener.metricUpdated();
104f7ea2997SKrzysztof Grobelny         }
105f7ea2997SKrzysztof Grobelny     }
1066ccfcbf5SKrzysztof Grobelny }
1076ccfcbf5SKrzysztof Grobelny 
108f7ea2997SKrzysztof Grobelny metrics::CollectionData&
1098069771cSKrzysztof Grobelny     Metric::findAssociatedData(const interfaces::Sensor& notifier)
1106ccfcbf5SKrzysztof Grobelny {
1113a1c297aSPatrick Williams     auto it = std::find_if(sensors.begin(), sensors.end(),
1123a1c297aSPatrick Williams                            [&notifier](const auto& sensor) {
1133a1c297aSPatrick Williams         return sensor.get() == &notifier;
1143a1c297aSPatrick Williams     });
115dcc4e193SKrzysztof Grobelny     auto index = std::distance(sensors.begin(), it);
1168069771cSKrzysztof Grobelny     return *collectionAlgorithms.at(index);
1176ccfcbf5SKrzysztof Grobelny }
1186ccfcbf5SKrzysztof Grobelny 
119d2238194SKrzysztof Grobelny LabeledMetricParameters Metric::dumpConfiguration() const
1206ccfcbf5SKrzysztof Grobelny {
121dcc4e193SKrzysztof Grobelny     auto sensorPath = utils::transform(sensors, [this](const auto& sensor) {
12294f71c51SSzymon Dompke         return LabeledSensorInfo(sensor->id().service, sensor->id().path,
123b8cc78ddSKrzysztof Grobelny                                  sensor->metadata());
124dcc4e193SKrzysztof Grobelny     });
125dcc4e193SKrzysztof Grobelny 
126*cff70c14SKrzysztof Grobelny     return LabeledMetricParameters(std::move(sensorPath), operationType,
127b8cc78ddSKrzysztof Grobelny                                    collectionTimeScope, collectionDuration);
128dcc4e193SKrzysztof Grobelny }
129dcc4e193SKrzysztof Grobelny 
13018e7101cSKrzysztof Grobelny uint64_t Metric::metricCount() const
1313eb56865SSzymon Dompke {
1323eb56865SSzymon Dompke     return sensors.size();
1333eb56865SSzymon Dompke }
134f7ea2997SKrzysztof Grobelny 
135f7ea2997SKrzysztof Grobelny void Metric::updateReadings(Milliseconds timestamp)
136f7ea2997SKrzysztof Grobelny {
137f7ea2997SKrzysztof Grobelny     for (auto& data : collectionAlgorithms)
138f7ea2997SKrzysztof Grobelny     {
139f7ea2997SKrzysztof Grobelny         if (std::optional<double> newValue = data->update(timestamp))
140f7ea2997SKrzysztof Grobelny         {
141f7ea2997SKrzysztof Grobelny             if (data->updateLastValue(*newValue))
142f7ea2997SKrzysztof Grobelny             {
143f7ea2997SKrzysztof Grobelny                 for (interfaces::MetricListener& listener : listeners)
144f7ea2997SKrzysztof Grobelny                 {
145f7ea2997SKrzysztof Grobelny                     listener.metricUpdated();
146f7ea2997SKrzysztof Grobelny                 }
147f7ea2997SKrzysztof Grobelny                 return;
148f7ea2997SKrzysztof Grobelny             }
149f7ea2997SKrzysztof Grobelny         }
150f7ea2997SKrzysztof Grobelny     }
151f7ea2997SKrzysztof Grobelny }
152f7ea2997SKrzysztof Grobelny 
153f7ea2997SKrzysztof Grobelny bool Metric::isTimerRequired() const
154f7ea2997SKrzysztof Grobelny {
155f7ea2997SKrzysztof Grobelny     if (collectionTimeScope == CollectionTimeScope::point)
156f7ea2997SKrzysztof Grobelny     {
157f7ea2997SKrzysztof Grobelny         return false;
158f7ea2997SKrzysztof Grobelny     }
159f7ea2997SKrzysztof Grobelny 
160f7ea2997SKrzysztof Grobelny     if (collectionTimeScope == CollectionTimeScope::startup &&
161f7ea2997SKrzysztof Grobelny         (operationType == OperationType::min ||
162f7ea2997SKrzysztof Grobelny          operationType == OperationType::max))
163f7ea2997SKrzysztof Grobelny     {
164f7ea2997SKrzysztof Grobelny         return false;
165f7ea2997SKrzysztof Grobelny     }
166f7ea2997SKrzysztof Grobelny 
167f7ea2997SKrzysztof Grobelny     return true;
168f7ea2997SKrzysztof Grobelny }
169