1 #include "metrics/collection_function.hpp" 2 3 #include <cmath> 4 5 namespace metrics 6 { 7 8 class FunctionMinimum : public CollectionFunction 9 { 10 public: 11 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), left.second) < 18 std::make_tuple(!std::isfinite(right.second), right.second); 19 }) 20 ->second; 21 } 22 23 double calculateForStartupInterval(std::vector<ReadingItem>& readings, 24 Milliseconds timestamp) const override 25 { 26 readings.assign( 27 {ReadingItem(timestamp, calculate(readings, timestamp))}); 28 return readings.back().second; 29 } 30 }; 31 32 class FunctionMaximum : public CollectionFunction 33 { 34 public: 35 double calculate(const std::vector<ReadingItem>& readings, 36 Milliseconds) const override 37 { 38 return std::max_element( 39 readings.begin(), readings.end(), 40 [](const auto& left, const auto& right) { 41 return std::make_tuple(std::isfinite(left.second), left.second) < 42 std::make_tuple(std::isfinite(right.second), right.second); 43 }) 44 ->second; 45 } 46 47 double calculateForStartupInterval(std::vector<ReadingItem>& readings, 48 Milliseconds timestamp) const override 49 { 50 readings.assign( 51 {ReadingItem(timestamp, calculate(readings, timestamp))}); 52 return readings.back().second; 53 } 54 }; 55 56 class FunctionAverage : public CollectionFunction 57 { 58 public: 59 double calculate(const std::vector<ReadingItem>& readings, 60 Milliseconds timestamp) const override 61 { 62 auto valueSum = 0.0; 63 auto timeSum = Milliseconds{0}; 64 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; 70 valueSum += it->second * duration.count(); 71 timeSum += duration; 72 } 73 } 74 75 const auto duration = timestamp - readings.back().first; 76 valueSum += readings.back().second * duration.count(); 77 timeSum += duration; 78 79 return valueSum / std::max(timeSum.count(), uint64_t{1u}); 80 } 81 82 double calculateForStartupInterval(std::vector<ReadingItem>& readings, 83 Milliseconds timestamp) const override 84 { 85 auto result = calculate(readings, timestamp); 86 if (std::isfinite(result)) 87 { 88 readings.assign({ReadingItem(readings.front().first, result), 89 ReadingItem(timestamp, readings.back().second)}); 90 } 91 return result; 92 } 93 }; 94 95 class FunctionSummation : public CollectionFunction 96 { 97 using Multiplier = std::chrono::duration<double>; 98 99 public: 100 double calculate(const std::vector<ReadingItem>& readings, 101 const Milliseconds timestamp) const override 102 { 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); 109 const auto multiplier = 110 calculateMultiplier(kt->first - it->first); 111 valueSum += it->second * multiplier.count(); 112 } 113 } 114 115 const auto multiplier = 116 calculateMultiplier(timestamp - readings.back().first); 117 valueSum += readings.back().second * multiplier.count(); 118 119 return valueSum; 120 } 121 122 double 123 calculateForStartupInterval(std::vector<ReadingItem>& readings, 124 const Milliseconds timestamp) const override 125 { 126 const auto result = calculate(readings, timestamp); 127 if (readings.size() > 2 && std::isfinite(result)) 128 { 129 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 } 138 } 139 return result; 140 } 141 142 private: 143 static constexpr Multiplier calculateMultiplier(Milliseconds duration) 144 { 145 constexpr auto m = Multiplier{Seconds{1}}; 146 return Multiplier{duration / m}; 147 } 148 }; 149 150 std::shared_ptr<CollectionFunction> 151 makeCollectionFunction(OperationType operationType) 152 { 153 using namespace std::string_literals; 154 155 switch (operationType) 156 { 157 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 172 } // namespace metrics 173