1 #include "metrics/collection_function.hpp"
2
3 #include <cmath>
4
5 namespace metrics
6 {
7
8 class FunctionMinimum : public CollectionFunction
9 {
10 public:
calculate(const std::vector<ReadingItem> & readings,Milliseconds) const11 double calculate(const std::vector<ReadingItem>& readings,
12 Milliseconds) const override
13 {
14 return std::min_element(
15 readings.begin(), readings.end(),
16 [](const auto& left, const auto& right) {
17 return std::make_tuple(!std::isfinite(left.second),
18 left.second) <
19 std::make_tuple(!std::isfinite(right.second),
20 right.second);
21 })
22 ->second;
23 }
24
calculateForStartupInterval(std::vector<ReadingItem> & readings,Milliseconds timestamp) const25 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
26 Milliseconds timestamp) const override
27 {
28 readings.assign(
29 {ReadingItem(timestamp, calculate(readings, timestamp))});
30 return readings.back().second;
31 }
32 };
33
34 class FunctionMaximum : public CollectionFunction
35 {
36 public:
calculate(const std::vector<ReadingItem> & readings,Milliseconds) const37 double calculate(const std::vector<ReadingItem>& readings,
38 Milliseconds) const override
39 {
40 return std::max_element(
41 readings.begin(), readings.end(),
42 [](const auto& left, const auto& right) {
43 return std::make_tuple(std::isfinite(left.second),
44 left.second) <
45 std::make_tuple(std::isfinite(right.second),
46 right.second);
47 })
48 ->second;
49 }
50
calculateForStartupInterval(std::vector<ReadingItem> & readings,Milliseconds timestamp) const51 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
52 Milliseconds timestamp) const override
53 {
54 readings.assign(
55 {ReadingItem(timestamp, calculate(readings, timestamp))});
56 return readings.back().second;
57 }
58 };
59
60 class FunctionAverage : public CollectionFunction
61 {
62 public:
calculate(const std::vector<ReadingItem> & readings,Milliseconds timestamp) const63 double calculate(const std::vector<ReadingItem>& readings,
64 Milliseconds timestamp) const override
65 {
66 auto valueSum = 0.0;
67 auto timeSum = Milliseconds{0};
68 for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
69 {
70 if (std::isfinite(it->second))
71 {
72 const auto kt = std::next(it);
73 const auto duration = kt->first - it->first;
74 valueSum += it->second * duration.count();
75 timeSum += duration;
76 }
77 }
78
79 const auto duration = timestamp - readings.back().first;
80 valueSum += readings.back().second * duration.count();
81 timeSum += duration;
82
83 return valueSum / std::max(timeSum.count(), uint64_t{1u});
84 }
85
calculateForStartupInterval(std::vector<ReadingItem> & readings,Milliseconds timestamp) const86 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
87 Milliseconds timestamp) const override
88 {
89 auto result = calculate(readings, timestamp);
90 if (std::isfinite(result))
91 {
92 readings.assign({ReadingItem(readings.front().first, result),
93 ReadingItem(timestamp, readings.back().second)});
94 }
95 return result;
96 }
97 };
98
99 class FunctionSummation : public CollectionFunction
100 {
101 using Multiplier = std::chrono::duration<double>;
102
103 public:
calculate(const std::vector<ReadingItem> & readings,const Milliseconds timestamp) const104 double calculate(const std::vector<ReadingItem>& readings,
105 const Milliseconds timestamp) const override
106 {
107 auto valueSum = 0.0;
108 for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
109 {
110 if (std::isfinite(it->second))
111 {
112 const auto kt = std::next(it);
113 const auto multiplier =
114 calculateMultiplier(kt->first - it->first);
115 valueSum += it->second * multiplier.count();
116 }
117 }
118
119 const auto multiplier =
120 calculateMultiplier(timestamp - readings.back().first);
121 valueSum += readings.back().second * multiplier.count();
122
123 return valueSum;
124 }
125
calculateForStartupInterval(std::vector<ReadingItem> & readings,const Milliseconds timestamp) const126 double calculateForStartupInterval(
127 std::vector<ReadingItem>& readings,
128 const Milliseconds timestamp) const override
129 {
130 const auto result = calculate(readings, timestamp);
131 if (readings.size() > 2 && std::isfinite(result))
132 {
133 const auto multiplier =
134 calculateMultiplier(timestamp - readings.front().first).count();
135 if (multiplier > 0.)
136 {
137 const auto prevValue = result / multiplier;
138 readings.assign(
139 {ReadingItem(readings.front().first, prevValue),
140 ReadingItem(timestamp, readings.back().second)});
141 }
142 }
143 return result;
144 }
145
146 private:
calculateMultiplier(Milliseconds duration)147 static constexpr Multiplier calculateMultiplier(Milliseconds duration)
148 {
149 constexpr auto m = Multiplier{Seconds{1}};
150 return Multiplier{duration / m};
151 }
152 };
153
makeCollectionFunction(OperationType operationType)154 std::shared_ptr<CollectionFunction> makeCollectionFunction(
155 OperationType operationType)
156 {
157 using namespace std::string_literals;
158
159 switch (operationType)
160 {
161 case OperationType::min:
162 return std::make_shared<FunctionMinimum>();
163 case OperationType::max:
164 return std::make_shared<FunctionMaximum>();
165 case OperationType::avg:
166 return std::make_shared<FunctionAverage>();
167 case OperationType::sum:
168 return std::make_shared<FunctionSummation>();
169 default:
170 throw std::runtime_error(
171 "op: "s + utils::enumToString(operationType) +
172 " is not supported"s);
173 }
174 }
175
176 } // namespace metrics
177