xref: /openbmc/telemetry/src/metric.cpp (revision f535cad6)
1 #include "metric.hpp"
2 
3 #include "metrics/collection_data.hpp"
4 #include "types/report_types.hpp"
5 #include "types/sensor_types.hpp"
6 #include "utils/labeled_tuple.hpp"
7 #include "utils/transform.hpp"
8 
9 #include <sdbusplus/exception.hpp>
10 
11 #include <algorithm>
12 
Metric(Sensors sensorsIn,OperationType operationTypeIn,CollectionTimeScope timeScopeIn,CollectionDuration collectionDurationIn,std::unique_ptr<interfaces::Clock> clockIn)13 Metric::Metric(Sensors sensorsIn, OperationType operationTypeIn,
14                CollectionTimeScope timeScopeIn,
15                CollectionDuration collectionDurationIn,
16                std::unique_ptr<interfaces::Clock> clockIn) :
17     sensors(std::move(sensorsIn)), operationType(operationTypeIn),
18     collectionTimeScope(timeScopeIn), collectionDuration(collectionDurationIn),
19     collectionAlgorithms(
20         metrics::makeCollectionData(sensors.size(), operationType,
21                                     collectionTimeScope, collectionDuration)),
22     clock(std::move(clockIn))
23 {}
24 
registerForUpdates(interfaces::MetricListener & listener)25 void Metric::registerForUpdates(interfaces::MetricListener& listener)
26 {
27     listeners.emplace_back(listener);
28 }
29 
unregisterFromUpdates(interfaces::MetricListener & listener)30 void Metric::unregisterFromUpdates(interfaces::MetricListener& listener)
31 {
32     listeners.erase(
33         std::remove_if(listeners.begin(), listeners.end(),
34                        [&listener](const interfaces::MetricListener& item) {
35         return &item == &listener;
36     }),
37         listeners.end());
38 }
39 
initialize()40 void Metric::initialize()
41 {
42     for (const auto& sensor : sensors)
43     {
44         sensor->registerForUpdates(weak_from_this());
45     }
46 }
47 
deinitialize()48 void Metric::deinitialize()
49 {
50     for (const auto& sensor : sensors)
51     {
52         sensor->unregisterFromUpdates(weak_from_this());
53     }
54 }
55 
getUpdatedReadings()56 const std::vector<MetricValue>& Metric::getUpdatedReadings()
57 {
58     const auto steadyTimestamp = clock->steadyTimestamp();
59     const auto systemTimestamp =
60         std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
61             .count();
62 
63     for (size_t i = 0; i < collectionAlgorithms.size(); ++i)
64     {
65         if (const auto value = collectionAlgorithms[i]->update(steadyTimestamp))
66         {
67             if (i < readings.size())
68             {
69                 readings[i].timestamp = systemTimestamp;
70                 readings[i].value = *value;
71             }
72             else
73             {
74                 if (i > readings.size())
75                 {
76                     const auto idx = readings.size();
77                     std::swap(collectionAlgorithms[i],
78                               collectionAlgorithms[idx]);
79                     std::swap(sensors[i], sensors[idx]);
80                     i = idx;
81                 }
82 
83                 readings.emplace_back(sensors[i]->metadata(), *value,
84                                       systemTimestamp);
85             }
86         }
87     }
88 
89     return readings;
90 }
91 
sensorUpdated(interfaces::Sensor & notifier,Milliseconds timestamp,double value)92 void Metric::sensorUpdated(interfaces::Sensor& notifier, Milliseconds timestamp,
93                            double value)
94 {
95     auto& data = findAssociatedData(notifier);
96     double newValue = data.update(timestamp, value);
97 
98     if (data.updateLastValue(newValue))
99     {
100         for (interfaces::MetricListener& listener : listeners)
101         {
102             listener.metricUpdated();
103         }
104     }
105 }
106 
107 metrics::CollectionData&
findAssociatedData(const interfaces::Sensor & notifier)108     Metric::findAssociatedData(const interfaces::Sensor& notifier)
109 {
110     auto it = std::find_if(
111         sensors.begin(), sensors.end(),
112         [&notifier](const auto& sensor) { return sensor.get() == &notifier; });
113     auto index = std::distance(sensors.begin(), it);
114     return *collectionAlgorithms.at(index);
115 }
116 
dumpConfiguration() const117 LabeledMetricParameters Metric::dumpConfiguration() const
118 {
119     auto sensorPath = utils::transform(sensors, [this](const auto& sensor) {
120         return LabeledSensorInfo(sensor->id().service, sensor->id().path,
121                                  sensor->metadata());
122     });
123 
124     return LabeledMetricParameters(std::move(sensorPath), operationType,
125                                    collectionTimeScope, collectionDuration);
126 }
127 
metricCount() const128 uint64_t Metric::metricCount() const
129 {
130     return sensors.size();
131 }
132 
updateReadings(Milliseconds timestamp)133 void Metric::updateReadings(Milliseconds timestamp)
134 {
135     for (auto& data : collectionAlgorithms)
136     {
137         if (std::optional<double> newValue = data->update(timestamp))
138         {
139             if (data->updateLastValue(*newValue))
140             {
141                 for (interfaces::MetricListener& listener : listeners)
142                 {
143                     listener.metricUpdated();
144                 }
145                 return;
146             }
147         }
148     }
149 }
150 
isTimerRequired() const151 bool Metric::isTimerRequired() const
152 {
153     if (collectionTimeScope == CollectionTimeScope::point)
154     {
155         return false;
156     }
157 
158     if (collectionTimeScope == CollectionTimeScope::startup &&
159         (operationType == OperationType::min ||
160          operationType == OperationType::max))
161     {
162         return false;
163     }
164 
165     return true;
166 }
167