| #include "metrics/collection_function.hpp" |
| |
| #include <cmath> |
| |
| namespace metrics |
| { |
| |
| class FunctionMinimum : public CollectionFunction |
| { |
| public: |
| double calculate(const std::vector<ReadingItem>& readings, |
| Milliseconds) const override |
| { |
| return std::min_element( |
| readings.begin(), readings.end(), |
| [](const auto& left, const auto& right) { |
| return std::make_tuple(!std::isfinite(left.second), |
| left.second) < |
| std::make_tuple(!std::isfinite(right.second), |
| right.second); |
| }) |
| ->second; |
| } |
| |
| double calculateForStartupInterval(std::vector<ReadingItem>& readings, |
| Milliseconds timestamp) const override |
| { |
| readings.assign( |
| {ReadingItem(timestamp, calculate(readings, timestamp))}); |
| return readings.back().second; |
| } |
| }; |
| |
| class FunctionMaximum : public CollectionFunction |
| { |
| public: |
| double calculate(const std::vector<ReadingItem>& readings, |
| Milliseconds) const override |
| { |
| return std::max_element( |
| readings.begin(), readings.end(), |
| [](const auto& left, const auto& right) { |
| return std::make_tuple(std::isfinite(left.second), |
| left.second) < |
| std::make_tuple(std::isfinite(right.second), |
| right.second); |
| }) |
| ->second; |
| } |
| |
| double calculateForStartupInterval(std::vector<ReadingItem>& readings, |
| Milliseconds timestamp) const override |
| { |
| readings.assign( |
| {ReadingItem(timestamp, calculate(readings, timestamp))}); |
| return readings.back().second; |
| } |
| }; |
| |
| class FunctionAverage : public CollectionFunction |
| { |
| public: |
| double calculate(const std::vector<ReadingItem>& readings, |
| Milliseconds timestamp) const override |
| { |
| auto valueSum = 0.0; |
| auto timeSum = Milliseconds{0}; |
| for (auto it = readings.begin(); it != std::prev(readings.end()); ++it) |
| { |
| if (std::isfinite(it->second)) |
| { |
| const auto kt = std::next(it); |
| const auto duration = kt->first - it->first; |
| valueSum += it->second * duration.count(); |
| timeSum += duration; |
| } |
| } |
| |
| const auto duration = timestamp - readings.back().first; |
| valueSum += readings.back().second * duration.count(); |
| timeSum += duration; |
| |
| return valueSum / std::max(timeSum.count(), uint64_t{1u}); |
| } |
| |
| double calculateForStartupInterval(std::vector<ReadingItem>& readings, |
| Milliseconds timestamp) const override |
| { |
| auto result = calculate(readings, timestamp); |
| if (std::isfinite(result)) |
| { |
| readings.assign({ReadingItem(readings.front().first, result), |
| ReadingItem(timestamp, readings.back().second)}); |
| } |
| return result; |
| } |
| }; |
| |
| class FunctionSummation : public CollectionFunction |
| { |
| using Multiplier = std::chrono::duration<double>; |
| |
| public: |
| double calculate(const std::vector<ReadingItem>& readings, |
| const Milliseconds timestamp) const override |
| { |
| auto valueSum = 0.0; |
| for (auto it = readings.begin(); it != std::prev(readings.end()); ++it) |
| { |
| if (std::isfinite(it->second)) |
| { |
| const auto kt = std::next(it); |
| const auto multiplier = |
| calculateMultiplier(kt->first - it->first); |
| valueSum += it->second * multiplier.count(); |
| } |
| } |
| |
| const auto multiplier = |
| calculateMultiplier(timestamp - readings.back().first); |
| valueSum += readings.back().second * multiplier.count(); |
| |
| return valueSum; |
| } |
| |
| double |
| calculateForStartupInterval(std::vector<ReadingItem>& readings, |
| const Milliseconds timestamp) const override |
| { |
| const auto result = calculate(readings, timestamp); |
| if (readings.size() > 2 && std::isfinite(result)) |
| { |
| const auto multiplier = |
| calculateMultiplier(timestamp - readings.front().first).count(); |
| if (multiplier > 0.) |
| { |
| const auto prevValue = result / multiplier; |
| readings.assign( |
| {ReadingItem(readings.front().first, prevValue), |
| ReadingItem(timestamp, readings.back().second)}); |
| } |
| } |
| return result; |
| } |
| |
| private: |
| static constexpr Multiplier calculateMultiplier(Milliseconds duration) |
| { |
| constexpr auto m = Multiplier{Seconds{1}}; |
| return Multiplier{duration / m}; |
| } |
| }; |
| |
| std::shared_ptr<CollectionFunction> |
| makeCollectionFunction(OperationType operationType) |
| { |
| using namespace std::string_literals; |
| |
| switch (operationType) |
| { |
| case OperationType::min: |
| return std::make_shared<FunctionMinimum>(); |
| case OperationType::max: |
| return std::make_shared<FunctionMaximum>(); |
| case OperationType::avg: |
| return std::make_shared<FunctionAverage>(); |
| case OperationType::sum: |
| return std::make_shared<FunctionSummation>(); |
| default: |
| throw std::runtime_error("op: "s + |
| utils::enumToString(operationType) + |
| " is not supported"s); |
| } |
| } |
| |
| } // namespace metrics |