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), 18 left.second) < 19 std::make_tuple(!std::isfinite(right.second), 20 right.second); 21 }) 22 ->second; 23 } 24 25 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: 37 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 51 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: 63 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 86 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: 104 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 126 double 127 calculateForStartupInterval(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: 147 static constexpr Multiplier calculateMultiplier(Milliseconds duration) 148 { 149 constexpr auto m = Multiplier{Seconds{1}}; 150 return Multiplier{duration / m}; 151 } 152 }; 153 154 std::shared_ptr<CollectionFunction> 155 makeCollectionFunction(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("op: "s + 171 utils::enumToString(operationType) + 172 " is not supported"s); 173 } 174 } 175 176 } // namespace metrics 177