blob: ee12c741c5f353dbb71dabf70c8169d23c13a489 [file] [log] [blame]
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +02001#include "metric.hpp"
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +01002
Krzysztof Grobelny80697712021-03-04 09:49:27 +00003#include "details/collection_function.hpp"
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +00004#include "types/report_types.hpp"
Szymon Dompke3a617022021-07-19 18:23:02 +02005#include "utils/labeled_tuple.hpp"
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +01006#include "utils/transform.hpp"
7
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +01008#include <sdbusplus/exception.hpp>
9
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010010#include <algorithm>
11
Krzysztof Grobelny80697712021-03-04 09:49:27 +000012class Metric::CollectionData
13{
14 public:
15 using ReadingItem = details::ReadingItem;
16
17 virtual ~CollectionData() = default;
18
19 virtual ReadingItem update(uint64_t timestamp) = 0;
20 virtual ReadingItem update(uint64_t timestamp, double value) = 0;
21};
22
23class Metric::DataPoint : public Metric::CollectionData
24{
25 public:
26 ReadingItem update(uint64_t timestamp) override
27 {
28 return ReadingItem{lastTimestamp, lastReading};
29 }
30
31 ReadingItem update(uint64_t timestamp, double reading) override
32 {
33 lastTimestamp = timestamp;
34 lastReading = reading;
35 return update(timestamp);
36 }
37
38 private:
39 uint64_t lastTimestamp = 0u;
40 double lastReading = 0.0;
41};
42
43class Metric::DataInterval : public Metric::CollectionData
44{
45 public:
46 DataInterval(std::shared_ptr<details::CollectionFunction> function,
47 CollectionDuration duration) :
48 function(std::move(function)),
49 duration(duration)
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010050 {
51 if (duration.t.count() == 0)
52 {
53 throw sdbusplus::exception::SdBusError(
54 static_cast<int>(std::errc::invalid_argument),
55 "Invalid CollectionDuration");
56 }
57 }
Krzysztof Grobelny80697712021-03-04 09:49:27 +000058
59 ReadingItem update(uint64_t timestamp) override
60 {
61 if (readings.size() > 0)
62 {
63 auto it = readings.begin();
64 for (auto kt = std::next(readings.rbegin()); kt != readings.rend();
65 ++kt)
66 {
67 const auto& [nextItemTimestamp, nextItemReading] =
68 *std::prev(kt);
69 if (timestamp >= nextItemTimestamp &&
70 static_cast<uint64_t>(timestamp - nextItemTimestamp) >
71 duration.t.count())
72 {
73 it = kt.base();
74 break;
75 }
76 }
77 readings.erase(readings.begin(), it);
78
79 if (timestamp > duration.t.count())
80 {
81 readings.front().first = std::max(
82 readings.front().first, timestamp - duration.t.count());
83 }
84 }
85
86 return function->calculate(readings, timestamp);
87 }
88
89 ReadingItem update(uint64_t timestamp, double reading) override
90 {
91 readings.emplace_back(timestamp, reading);
92 return update(timestamp);
93 }
94
95 private:
96 std::shared_ptr<details::CollectionFunction> function;
97 std::vector<ReadingItem> readings;
98 CollectionDuration duration;
99};
100
101class Metric::DataStartup : public Metric::CollectionData
102{
103 public:
104 DataStartup(std::shared_ptr<details::CollectionFunction> function) :
105 function(std::move(function))
106 {}
107
108 ReadingItem update(uint64_t timestamp) override
109 {
110 return function->calculateForStartupInterval(readings, timestamp);
111 }
112
113 ReadingItem update(uint64_t timestamp, double reading) override
114 {
115 readings.emplace_back(timestamp, reading);
116 return function->calculateForStartupInterval(readings, timestamp);
117 }
118
119 private:
120 std::shared_ptr<details::CollectionFunction> function;
121 std::vector<ReadingItem> readings;
122};
123
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000124Metric::Metric(Sensors sensorsIn, OperationType operationTypeIn,
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100125 std::string idIn, CollectionTimeScope timeScopeIn,
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000126 CollectionDuration collectionDurationIn,
127 std::unique_ptr<interfaces::Clock> clockIn) :
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100128 id(std::move(idIn)),
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000129 sensors(std::move(sensorsIn)), operationType(operationTypeIn),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000130 collectionTimeScope(timeScopeIn), collectionDuration(collectionDurationIn),
131 collectionAlgorithms(makeCollectionData(sensors.size(), operationType,
132 collectionTimeScope,
133 collectionDuration)),
134 clock(std::move(clockIn))
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000135{
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100136 readings = utils::transform(sensors, [this](const auto& sensor) {
137 return MetricValue{id, sensor->metadata(), 0.0, 0u};
138 });
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000139}
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100140
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000141Metric::~Metric() = default;
142
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100143void Metric::initialize()
144{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000145 for (const auto& sensor : sensors)
146 {
147 sensor->registerForUpdates(weak_from_this());
148 }
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100149}
150
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200151void Metric::deinitialize()
152{
153 for (const auto& sensor : sensors)
154 {
155 sensor->unregisterFromUpdates(weak_from_this());
156 }
157}
158
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000159std::vector<MetricValue> Metric::getReadings() const
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100160{
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000161 const auto timestamp = clock->timestamp();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000162 auto resultReadings = readings;
163
164 for (size_t i = 0; i < resultReadings.size(); ++i)
165 {
166 std::tie(resultReadings[i].timestamp, resultReadings[i].value) =
167 collectionAlgorithms[i]->update(timestamp);
168 }
169
170 return resultReadings;
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100171}
172
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000173void Metric::sensorUpdated(interfaces::Sensor& notifier, uint64_t timestamp)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100174{
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000175 findAssociatedData(notifier).update(timestamp);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100176}
177
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000178void Metric::sensorUpdated(interfaces::Sensor& notifier, uint64_t timestamp,
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100179 double value)
180{
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000181 findAssociatedData(notifier).update(timestamp, value);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100182}
183
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000184Metric::CollectionData&
185 Metric::findAssociatedData(const interfaces::Sensor& notifier)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100186{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000187 auto it = std::find_if(
188 sensors.begin(), sensors.end(),
189 [&notifier](const auto& sensor) { return sensor.get() == &notifier; });
190 auto index = std::distance(sensors.begin(), it);
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000191 return *collectionAlgorithms.at(index);
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100192}
193
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000194LabeledMetricParameters Metric::dumpConfiguration() const
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100195{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000196 auto sensorPath = utils::transform(sensors, [this](const auto& sensor) {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100197 return LabeledSensorParameters(sensor->id().service, sensor->id().path,
198 sensor->metadata());
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000199 });
200
201 return LabeledMetricParameters(std::move(sensorPath), operationType, id,
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100202 collectionTimeScope, collectionDuration);
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000203}
204
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000205std::vector<std::unique_ptr<Metric::CollectionData>>
206 Metric::makeCollectionData(size_t size, OperationType op,
207 CollectionTimeScope timeScope,
208 CollectionDuration duration)
209{
210 using namespace std::string_literals;
211
212 std::vector<std::unique_ptr<Metric::CollectionData>> result;
213
214 result.reserve(size);
215
216 switch (timeScope)
217 {
218 case CollectionTimeScope::interval:
219 std::generate_n(
220 std::back_inserter(result), size,
221 [cf = details::makeCollectionFunction(op), duration] {
222 return std::make_unique<DataInterval>(cf, duration);
223 });
224 break;
225 case CollectionTimeScope::point:
226 std::generate_n(std::back_inserter(result), size,
227 [] { return std::make_unique<DataPoint>(); });
228 break;
229 case CollectionTimeScope::startup:
230 std::generate_n(std::back_inserter(result), size,
231 [cf = details::makeCollectionFunction(op)] {
232 return std::make_unique<DataStartup>(cf);
233 });
234 break;
235 default:
236 throw std::runtime_error("timeScope: "s +
237 utils::enumToString(timeScope) +
238 " is not supported"s);
239 }
240
241 return result;
242}
243
Szymon Dompke3eb56862021-09-20 15:32:04 +0200244uint64_t Metric::sensorCount() const
245{
246 return sensors.size();
247}