xref: /openbmc/telemetry/src/metric.cpp (revision 9e8da5468b8ce2f1235bb2c50ce2b163d0704555)
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,
14b8cc78ddSKrzysztof Grobelny                std::string idIn, CollectionTimeScope timeScopeIn,
158069771cSKrzysztof Grobelny                CollectionDuration collectionDurationIn,
168069771cSKrzysztof Grobelny                std::unique_ptr<interfaces::Clock> clockIn) :
17b8cc78ddSKrzysztof Grobelny     id(std::move(idIn)),
18dcc4e193SKrzysztof Grobelny     sensors(std::move(sensorsIn)), operationType(operationTypeIn),
198069771cSKrzysztof Grobelny     collectionTimeScope(timeScopeIn), collectionDuration(collectionDurationIn),
20f7ea2997SKrzysztof Grobelny     collectionAlgorithms(
21f7ea2997SKrzysztof Grobelny         metrics::makeCollectionData(sensors.size(), operationType,
22f7ea2997SKrzysztof Grobelny                                     collectionTimeScope, collectionDuration)),
238069771cSKrzysztof Grobelny     clock(std::move(clockIn))
24*9e8da546SKrzysztof 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 {
33f7ea2997SKrzysztof Grobelny     listeners.erase(
34f7ea2997SKrzysztof Grobelny         std::remove_if(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 
57*9e8da546SKrzysztof Grobelny const std::vector<MetricValue>& Metric::getUpdatedReadings()
58e8fc5751SKrzysztof Grobelny {
5951f0fd50SKrzysztof Grobelny     const auto steadyTimestamp = clock->steadyTimestamp();
60*9e8da546SKrzysztof Grobelny     const auto systemTimestamp =
61*9e8da546SKrzysztof Grobelny         std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
62*9e8da546SKrzysztof Grobelny             .count();
6351f0fd50SKrzysztof Grobelny 
64*9e8da546SKrzysztof Grobelny     for (size_t i = 0; i < collectionAlgorithms.size(); ++i)
658069771cSKrzysztof Grobelny     {
6651f0fd50SKrzysztof Grobelny         if (const auto value = collectionAlgorithms[i]->update(steadyTimestamp))
6751f0fd50SKrzysztof Grobelny         {
68*9e8da546SKrzysztof Grobelny             if (i < readings.size())
69*9e8da546SKrzysztof Grobelny             {
70*9e8da546SKrzysztof Grobelny                 readings[i].timestamp = systemTimestamp;
71*9e8da546SKrzysztof Grobelny                 readings[i].value = *value;
72*9e8da546SKrzysztof Grobelny             }
73*9e8da546SKrzysztof Grobelny             else
74*9e8da546SKrzysztof Grobelny             {
75*9e8da546SKrzysztof Grobelny                 if (i > readings.size())
76*9e8da546SKrzysztof Grobelny                 {
77*9e8da546SKrzysztof Grobelny                     const auto idx = readings.size();
78*9e8da546SKrzysztof Grobelny                     std::swap(collectionAlgorithms[i],
79*9e8da546SKrzysztof Grobelny                               collectionAlgorithms[idx]);
80*9e8da546SKrzysztof Grobelny                     std::swap(sensors[i], sensors[idx]);
81*9e8da546SKrzysztof Grobelny                     i = idx;
82*9e8da546SKrzysztof Grobelny                 }
83*9e8da546SKrzysztof Grobelny 
84*9e8da546SKrzysztof Grobelny                 readings.emplace_back(id, sensors[i]->metadata(), *value,
85*9e8da546SKrzysztof Grobelny                                       systemTimestamp);
86*9e8da546SKrzysztof Grobelny             }
8751f0fd50SKrzysztof Grobelny         }
888069771cSKrzysztof Grobelny     }
898069771cSKrzysztof Grobelny 
90*9e8da546SKrzysztof 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 {
111dcc4e193SKrzysztof Grobelny     auto it = std::find_if(
112dcc4e193SKrzysztof Grobelny         sensors.begin(), sensors.end(),
113dcc4e193SKrzysztof Grobelny         [&notifier](const auto& sensor) { return sensor.get() == &notifier; });
114dcc4e193SKrzysztof Grobelny     auto index = std::distance(sensors.begin(), it);
1158069771cSKrzysztof Grobelny     return *collectionAlgorithms.at(index);
1166ccfcbf5SKrzysztof Grobelny }
1176ccfcbf5SKrzysztof Grobelny 
118d2238194SKrzysztof Grobelny LabeledMetricParameters Metric::dumpConfiguration() const
1196ccfcbf5SKrzysztof Grobelny {
120dcc4e193SKrzysztof Grobelny     auto sensorPath = utils::transform(sensors, [this](const auto& sensor) {
12194f71c51SSzymon Dompke         return LabeledSensorInfo(sensor->id().service, sensor->id().path,
122b8cc78ddSKrzysztof Grobelny                                  sensor->metadata());
123dcc4e193SKrzysztof Grobelny     });
124dcc4e193SKrzysztof Grobelny 
125dcc4e193SKrzysztof Grobelny     return LabeledMetricParameters(std::move(sensorPath), operationType, id,
126b8cc78ddSKrzysztof Grobelny                                    collectionTimeScope, collectionDuration);
127dcc4e193SKrzysztof Grobelny }
128dcc4e193SKrzysztof Grobelny 
1293eb56865SSzymon Dompke uint64_t Metric::sensorCount() const
1303eb56865SSzymon Dompke {
1313eb56865SSzymon Dompke     return sensors.size();
1323eb56865SSzymon Dompke }
133f7ea2997SKrzysztof Grobelny 
134f7ea2997SKrzysztof Grobelny void Metric::updateReadings(Milliseconds timestamp)
135f7ea2997SKrzysztof Grobelny {
136f7ea2997SKrzysztof Grobelny     for (auto& data : collectionAlgorithms)
137f7ea2997SKrzysztof Grobelny     {
138f7ea2997SKrzysztof Grobelny         if (std::optional<double> newValue = data->update(timestamp))
139f7ea2997SKrzysztof Grobelny         {
140f7ea2997SKrzysztof Grobelny             if (data->updateLastValue(*newValue))
141f7ea2997SKrzysztof Grobelny             {
142f7ea2997SKrzysztof Grobelny                 for (interfaces::MetricListener& listener : listeners)
143f7ea2997SKrzysztof Grobelny                 {
144f7ea2997SKrzysztof Grobelny                     listener.metricUpdated();
145f7ea2997SKrzysztof Grobelny                 }
146f7ea2997SKrzysztof Grobelny                 return;
147f7ea2997SKrzysztof Grobelny             }
148f7ea2997SKrzysztof Grobelny         }
149f7ea2997SKrzysztof Grobelny     }
150f7ea2997SKrzysztof Grobelny }
151f7ea2997SKrzysztof Grobelny 
152f7ea2997SKrzysztof Grobelny bool Metric::isTimerRequired() const
153f7ea2997SKrzysztof Grobelny {
154f7ea2997SKrzysztof Grobelny     if (collectionTimeScope == CollectionTimeScope::point)
155f7ea2997SKrzysztof Grobelny     {
156f7ea2997SKrzysztof Grobelny         return false;
157f7ea2997SKrzysztof Grobelny     }
158f7ea2997SKrzysztof Grobelny 
159f7ea2997SKrzysztof Grobelny     if (collectionTimeScope == CollectionTimeScope::startup &&
160f7ea2997SKrzysztof Grobelny         (operationType == OperationType::min ||
161f7ea2997SKrzysztof Grobelny          operationType == OperationType::max))
162f7ea2997SKrzysztof Grobelny     {
163f7ea2997SKrzysztof Grobelny         return false;
164f7ea2997SKrzysztof Grobelny     }
165f7ea2997SKrzysztof Grobelny 
166f7ea2997SKrzysztof Grobelny     return true;
167f7ea2997SKrzysztof Grobelny }
168