blob: 717bb68dd47a35cc04310ed2ed391db47caf617a [file] [log] [blame]
#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