blob: 7170936d637c45c4f2465a6f0df0d51f8df90a9c [file] [log] [blame]
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +01001#include "metrics/collection_function.hpp"
Krzysztof Grobelny80697712021-03-04 09:49:27 +00002
3#include <cmath>
4
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +01005namespace metrics
Krzysztof Grobelny80697712021-03-04 09:49:27 +00006{
7
Krzysztof Grobelny80697712021-03-04 09:49:27 +00008class FunctionMinimum : public CollectionFunction
9{
10 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010011 double calculate(const std::vector<ReadingItem>& readings,
12 Milliseconds) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000013 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010014 return std::min_element(
15 readings.begin(), readings.end(),
16 [](const auto& left, const auto& right) {
Patrick Williams3a1c2972023-05-10 07:51:04 -050017 return std::make_tuple(!std::isfinite(left.second), left.second) <
18 std::make_tuple(!std::isfinite(right.second), right.second);
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010019 })
20 ->second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000021 }
22
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010023 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
24 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000025 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010026 readings.assign(
27 {ReadingItem(timestamp, calculate(readings, timestamp))});
28 return readings.back().second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000029 }
30};
31
32class FunctionMaximum : public CollectionFunction
33{
34 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010035 double calculate(const std::vector<ReadingItem>& readings,
36 Milliseconds) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000037 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010038 return std::max_element(
39 readings.begin(), readings.end(),
40 [](const auto& left, const auto& right) {
Patrick Williams3a1c2972023-05-10 07:51:04 -050041 return std::make_tuple(std::isfinite(left.second), left.second) <
42 std::make_tuple(std::isfinite(right.second), right.second);
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010043 })
44 ->second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000045 }
46
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010047 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
48 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000049 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010050 readings.assign(
51 {ReadingItem(timestamp, calculate(readings, timestamp))});
52 return readings.back().second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000053 }
54};
55
56class FunctionAverage : public CollectionFunction
57{
58 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010059 double calculate(const std::vector<ReadingItem>& readings,
60 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000061 {
62 auto valueSum = 0.0;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010063 auto timeSum = Milliseconds{0};
Krzysztof Grobelny80697712021-03-04 09:49:27 +000064 for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
65 {
66 if (std::isfinite(it->second))
67 {
68 const auto kt = std::next(it);
69 const auto duration = kt->first - it->first;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010070 valueSum += it->second * duration.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +000071 timeSum += duration;
72 }
73 }
74
75 const auto duration = timestamp - readings.back().first;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010076 valueSum += readings.back().second * duration.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +000077 timeSum += duration;
78
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010079 return valueSum / std::max(timeSum.count(), uint64_t{1u});
Krzysztof Grobelny80697712021-03-04 09:49:27 +000080 }
81
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010082 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
83 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000084 {
85 auto result = calculate(readings, timestamp);
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010086 if (std::isfinite(result))
Krzysztof Grobelny80697712021-03-04 09:49:27 +000087 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010088 readings.assign({ReadingItem(readings.front().first, result),
Krzysztof Grobelny80697712021-03-04 09:49:27 +000089 ReadingItem(timestamp, readings.back().second)});
90 }
91 return result;
92 }
93};
94
95class FunctionSummation : public CollectionFunction
96{
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010097 using Multiplier = std::chrono::duration<double>;
98
Krzysztof Grobelny80697712021-03-04 09:49:27 +000099 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100100 double calculate(const std::vector<ReadingItem>& readings,
101 const Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000102 {
103 auto valueSum = 0.0;
104 for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
105 {
106 if (std::isfinite(it->second))
107 {
108 const auto kt = std::next(it);
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100109 const auto multiplier =
110 calculateMultiplier(kt->first - it->first);
111 valueSum += it->second * multiplier.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000112 }
113 }
114
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100115 const auto multiplier =
116 calculateMultiplier(timestamp - readings.back().first);
117 valueSum += readings.back().second * multiplier.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000118
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100119 return valueSum;
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000120 }
121
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100122 double
123 calculateForStartupInterval(std::vector<ReadingItem>& readings,
124 const Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000125 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100126 const auto result = calculate(readings, timestamp);
127 if (readings.size() > 2 && std::isfinite(result))
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000128 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100129 const auto multiplier =
130 calculateMultiplier(timestamp - readings.front().first).count();
131 if (multiplier > 0.)
132 {
133 const auto prevValue = result / multiplier;
134 readings.assign(
135 {ReadingItem(readings.front().first, prevValue),
136 ReadingItem(timestamp, readings.back().second)});
137 }
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000138 }
139 return result;
140 }
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100141
142 private:
143 static constexpr Multiplier calculateMultiplier(Milliseconds duration)
144 {
145 constexpr auto m = Multiplier{Seconds{1}};
146 return Multiplier{duration / m};
147 }
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000148};
149
150std::shared_ptr<CollectionFunction>
151 makeCollectionFunction(OperationType operationType)
152{
153 using namespace std::string_literals;
154
155 switch (operationType)
156 {
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000157 case OperationType::min:
158 return std::make_shared<FunctionMinimum>();
159 case OperationType::max:
160 return std::make_shared<FunctionMaximum>();
161 case OperationType::avg:
162 return std::make_shared<FunctionAverage>();
163 case OperationType::sum:
164 return std::make_shared<FunctionSummation>();
165 default:
166 throw std::runtime_error("op: "s +
167 utils::enumToString(operationType) +
168 " is not supported"s);
169 }
170}
171
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100172} // namespace metrics