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(readings.begin(), readings.end(), 15 [](const auto& left, const auto& right) { 16 return std::make_tuple(!std::isfinite(left.second), left.second) < 17 std::make_tuple(!std::isfinite(right.second), right.second); 18 })->second; 19 } 20 21 double calculateForStartupInterval(std::vector<ReadingItem>& readings, 22 Milliseconds timestamp) const override 23 { 24 readings.assign( 25 {ReadingItem(timestamp, calculate(readings, timestamp))}); 26 return readings.back().second; 27 } 28 }; 29 30 class FunctionMaximum : public CollectionFunction 31 { 32 public: 33 double calculate(const std::vector<ReadingItem>& readings, 34 Milliseconds) const override 35 { 36 return std::max_element(readings.begin(), readings.end(), 37 [](const auto& left, const auto& right) { 38 return std::make_tuple(std::isfinite(left.second), left.second) < 39 std::make_tuple(std::isfinite(right.second), right.second); 40 })->second; 41 } 42 43 double calculateForStartupInterval(std::vector<ReadingItem>& readings, 44 Milliseconds timestamp) const override 45 { 46 readings.assign( 47 {ReadingItem(timestamp, calculate(readings, timestamp))}); 48 return readings.back().second; 49 } 50 }; 51 52 class FunctionAverage : public CollectionFunction 53 { 54 public: 55 double calculate(const std::vector<ReadingItem>& readings, 56 Milliseconds timestamp) const override 57 { 58 auto valueSum = 0.0; 59 auto timeSum = Milliseconds{0}; 60 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; 66 valueSum += it->second * duration.count(); 67 timeSum += duration; 68 } 69 } 70 71 const auto duration = timestamp - readings.back().first; 72 valueSum += readings.back().second * duration.count(); 73 timeSum += duration; 74 75 return valueSum / std::max(timeSum.count(), uint64_t{1u}); 76 } 77 78 double calculateForStartupInterval(std::vector<ReadingItem>& readings, 79 Milliseconds timestamp) const override 80 { 81 auto result = calculate(readings, timestamp); 82 if (std::isfinite(result)) 83 { 84 readings.assign({ReadingItem(readings.front().first, result), 85 ReadingItem(timestamp, readings.back().second)}); 86 } 87 return result; 88 } 89 }; 90 91 class FunctionSummation : public CollectionFunction 92 { 93 using Multiplier = std::chrono::duration<double>; 94 95 public: 96 double calculate(const std::vector<ReadingItem>& readings, 97 const Milliseconds timestamp) const override 98 { 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); 105 const auto multiplier = 106 calculateMultiplier(kt->first - it->first); 107 valueSum += it->second * multiplier.count(); 108 } 109 } 110 111 const auto multiplier = 112 calculateMultiplier(timestamp - readings.back().first); 113 valueSum += readings.back().second * multiplier.count(); 114 115 return valueSum; 116 } 117 118 double 119 calculateForStartupInterval(std::vector<ReadingItem>& readings, 120 const Milliseconds timestamp) const override 121 { 122 const auto result = calculate(readings, timestamp); 123 if (readings.size() > 2 && std::isfinite(result)) 124 { 125 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 } 134 } 135 return result; 136 } 137 138 private: 139 static constexpr Multiplier calculateMultiplier(Milliseconds duration) 140 { 141 constexpr auto m = Multiplier{Seconds{1}}; 142 return Multiplier{duration / m}; 143 } 144 }; 145 146 std::shared_ptr<CollectionFunction> 147 makeCollectionFunction(OperationType operationType) 148 { 149 using namespace std::string_literals; 150 151 switch (operationType) 152 { 153 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 168 } // namespace metrics 169