blob: 21c811156e1708164c5343d1fced094c74c8ab06 [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 {
Patrick Williamsc7935fa2023-10-20 11:19:30 -050014 return std::min_element(readings.begin(), readings.end(),
15 [](const auto& left, const auto& right) {
Patrick Williams3a1c2972023-05-10 07:51:04 -050016 return std::make_tuple(!std::isfinite(left.second), left.second) <
17 std::make_tuple(!std::isfinite(right.second), right.second);
Patrick Williamsc7935fa2023-10-20 11:19:30 -050018 })->second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000019 }
20
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010021 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
22 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000023 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010024 readings.assign(
25 {ReadingItem(timestamp, calculate(readings, timestamp))});
26 return readings.back().second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000027 }
28};
29
30class FunctionMaximum : public CollectionFunction
31{
32 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010033 double calculate(const std::vector<ReadingItem>& readings,
34 Milliseconds) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000035 {
Patrick Williamsc7935fa2023-10-20 11:19:30 -050036 return std::max_element(readings.begin(), readings.end(),
37 [](const auto& left, const auto& right) {
Patrick Williams3a1c2972023-05-10 07:51:04 -050038 return std::make_tuple(std::isfinite(left.second), left.second) <
39 std::make_tuple(std::isfinite(right.second), right.second);
Patrick Williamsc7935fa2023-10-20 11:19:30 -050040 })->second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000041 }
42
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010043 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
44 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000045 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010046 readings.assign(
47 {ReadingItem(timestamp, calculate(readings, timestamp))});
48 return readings.back().second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000049 }
50};
51
52class FunctionAverage : public CollectionFunction
53{
54 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010055 double calculate(const std::vector<ReadingItem>& readings,
56 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000057 {
58 auto valueSum = 0.0;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010059 auto timeSum = Milliseconds{0};
Krzysztof Grobelny80697712021-03-04 09:49:27 +000060 for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
61 {
62 if (std::isfinite(it->second))
63 {
64 const auto kt = std::next(it);
65 const auto duration = kt->first - it->first;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010066 valueSum += it->second * duration.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +000067 timeSum += duration;
68 }
69 }
70
71 const auto duration = timestamp - readings.back().first;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010072 valueSum += readings.back().second * duration.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +000073 timeSum += duration;
74
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010075 return valueSum / std::max(timeSum.count(), uint64_t{1u});
Krzysztof Grobelny80697712021-03-04 09:49:27 +000076 }
77
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010078 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
79 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000080 {
81 auto result = calculate(readings, timestamp);
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010082 if (std::isfinite(result))
Krzysztof Grobelny80697712021-03-04 09:49:27 +000083 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010084 readings.assign({ReadingItem(readings.front().first, result),
Krzysztof Grobelny80697712021-03-04 09:49:27 +000085 ReadingItem(timestamp, readings.back().second)});
86 }
87 return result;
88 }
89};
90
91class FunctionSummation : public CollectionFunction
92{
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010093 using Multiplier = std::chrono::duration<double>;
94
Krzysztof Grobelny80697712021-03-04 09:49:27 +000095 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010096 double calculate(const std::vector<ReadingItem>& readings,
97 const Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000098 {
99 auto valueSum = 0.0;
100 for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
101 {
102 if (std::isfinite(it->second))
103 {
104 const auto kt = std::next(it);
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100105 const auto multiplier =
106 calculateMultiplier(kt->first - it->first);
107 valueSum += it->second * multiplier.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000108 }
109 }
110
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100111 const auto multiplier =
112 calculateMultiplier(timestamp - readings.back().first);
113 valueSum += readings.back().second * multiplier.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000114
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100115 return valueSum;
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000116 }
117
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100118 double
119 calculateForStartupInterval(std::vector<ReadingItem>& readings,
120 const Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000121 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100122 const auto result = calculate(readings, timestamp);
123 if (readings.size() > 2 && std::isfinite(result))
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000124 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100125 const auto multiplier =
126 calculateMultiplier(timestamp - readings.front().first).count();
127 if (multiplier > 0.)
128 {
129 const auto prevValue = result / multiplier;
130 readings.assign(
131 {ReadingItem(readings.front().first, prevValue),
132 ReadingItem(timestamp, readings.back().second)});
133 }
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000134 }
135 return result;
136 }
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100137
138 private:
139 static constexpr Multiplier calculateMultiplier(Milliseconds duration)
140 {
141 constexpr auto m = Multiplier{Seconds{1}};
142 return Multiplier{duration / m};
143 }
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000144};
145
146std::shared_ptr<CollectionFunction>
147 makeCollectionFunction(OperationType operationType)
148{
149 using namespace std::string_literals;
150
151 switch (operationType)
152 {
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000153 case OperationType::min:
154 return std::make_shared<FunctionMinimum>();
155 case OperationType::max:
156 return std::make_shared<FunctionMaximum>();
157 case OperationType::avg:
158 return std::make_shared<FunctionAverage>();
159 case OperationType::sum:
160 return std::make_shared<FunctionSummation>();
161 default:
162 throw std::runtime_error("op: "s +
163 utils::enumToString(operationType) +
164 " is not supported"s);
165 }
166}
167
Krzysztof Grobelnyf7ea2992022-01-27 11:04:58 +0100168} // namespace metrics