#include "metrics/collection_data.hpp" #include "metrics/collection_function.hpp" namespace metrics { bool CollectionData::updateLastValue(double value) { const bool changed = lastValue != value; lastValue = value; return changed; } class DataPoint : public CollectionData { public: std::optional update(Milliseconds) override { return lastReading; } double update(Milliseconds, double reading) override { lastReading = reading; return reading; } private: std::optional lastReading; }; class DataInterval : public CollectionData { public: DataInterval(std::shared_ptr function, CollectionDuration duration) : function(std::move(function)), duration(duration) { if (duration.t.count() == 0) { throw sdbusplus::exception::SdBusError( static_cast(std::errc::invalid_argument), "Invalid CollectionDuration"); } } std::optional update(Milliseconds timestamp) override { if (readings.empty()) { return std::nullopt; } cleanup(timestamp); return function->calculate(readings, timestamp); } double update(Milliseconds timestamp, double reading) override { readings.emplace_back(timestamp, reading); cleanup(timestamp); return function->calculate(readings, timestamp); } private: void cleanup(Milliseconds timestamp) { auto it = readings.begin(); for (auto kt = std::next(readings.rbegin()); kt != readings.rend(); ++kt) { const auto& [nextItemTimestamp, nextItemReading] = *std::prev(kt); if (timestamp >= nextItemTimestamp && timestamp - nextItemTimestamp > duration.t) { it = kt.base(); break; } } readings.erase(readings.begin(), it); if (timestamp > duration.t) { readings.front().first = std::max(readings.front().first, timestamp - duration.t); } } std::shared_ptr function; std::vector readings; CollectionDuration duration; }; class DataStartup : public CollectionData { public: explicit DataStartup(std::shared_ptr function) : function(std::move(function)) {} std::optional update(Milliseconds timestamp) override { if (readings.empty()) { return std::nullopt; } return function->calculateForStartupInterval(readings, timestamp); } double update(Milliseconds timestamp, double reading) override { readings.emplace_back(timestamp, reading); return function->calculateForStartupInterval(readings, timestamp); } private: std::shared_ptr function; std::vector readings; }; std::vector> makeCollectionData(size_t size, OperationType op, CollectionTimeScope timeScope, CollectionDuration duration) { using namespace std::string_literals; std::vector> result; result.reserve(size); switch (timeScope) { case CollectionTimeScope::interval: std::generate_n(std::back_inserter(result), size, [cf = makeCollectionFunction(op), duration] { return std::make_unique(cf, duration); }); break; case CollectionTimeScope::point: std::generate_n(std::back_inserter(result), size, [] { return std::make_unique(); }); break; case CollectionTimeScope::startup: std::generate_n(std::back_inserter(result), size, [cf = makeCollectionFunction(op)] { return std::make_unique(cf); }); break; } return result; } } // namespace metrics