1 #include "metrics/collection_data.hpp" 2 3 #include "metrics/collection_function.hpp" 4 5 namespace metrics 6 { 7 8 bool CollectionData::updateLastValue(double value) 9 { 10 const bool changed = lastValue != value; 11 lastValue = value; 12 return changed; 13 } 14 15 class DataPoint : public CollectionData 16 { 17 public: 18 std::optional<double> update(Milliseconds) override 19 { 20 return lastReading; 21 } 22 23 double update(Milliseconds, double reading) override 24 { 25 lastReading = reading; 26 return reading; 27 } 28 29 private: 30 std::optional<double> lastReading; 31 }; 32 33 class DataInterval : public CollectionData 34 { 35 public: 36 DataInterval(std::shared_ptr<CollectionFunction> function, 37 CollectionDuration duration) : 38 function(std::move(function)), 39 duration(duration) 40 { 41 if (duration.t.count() == 0) 42 { 43 throw sdbusplus::exception::SdBusError( 44 static_cast<int>(std::errc::invalid_argument), 45 "Invalid CollectionDuration"); 46 } 47 } 48 49 std::optional<double> update(Milliseconds timestamp) override 50 { 51 if (readings.empty()) 52 { 53 return std::nullopt; 54 } 55 56 cleanup(timestamp); 57 58 return function->calculate(readings, timestamp); 59 } 60 61 double update(Milliseconds timestamp, double reading) override 62 { 63 readings.emplace_back(timestamp, reading); 64 65 cleanup(timestamp); 66 67 return function->calculate(readings, timestamp); 68 } 69 70 private: 71 void cleanup(Milliseconds timestamp) 72 { 73 auto it = readings.begin(); 74 for (auto kt = std::next(readings.rbegin()); kt != readings.rend(); 75 ++kt) 76 { 77 const auto& [nextItemTimestamp, nextItemReading] = *std::prev(kt); 78 if (timestamp >= nextItemTimestamp && 79 timestamp - nextItemTimestamp > duration.t) 80 { 81 it = kt.base(); 82 break; 83 } 84 } 85 readings.erase(readings.begin(), it); 86 87 if (timestamp > duration.t) 88 { 89 readings.front().first = 90 std::max(readings.front().first, timestamp - duration.t); 91 } 92 } 93 94 std::shared_ptr<CollectionFunction> function; 95 std::vector<ReadingItem> readings; 96 CollectionDuration duration; 97 }; 98 99 class DataStartup : public CollectionData 100 { 101 public: 102 explicit DataStartup(std::shared_ptr<CollectionFunction> function) : 103 function(std::move(function)) 104 {} 105 106 std::optional<double> update(Milliseconds timestamp) override 107 { 108 if (readings.empty()) 109 { 110 return std::nullopt; 111 } 112 113 return function->calculateForStartupInterval(readings, timestamp); 114 } 115 116 double update(Milliseconds timestamp, double reading) override 117 { 118 readings.emplace_back(timestamp, reading); 119 return function->calculateForStartupInterval(readings, timestamp); 120 } 121 122 private: 123 std::shared_ptr<CollectionFunction> function; 124 std::vector<ReadingItem> readings; 125 }; 126 127 std::vector<std::unique_ptr<CollectionData>> 128 makeCollectionData(size_t size, OperationType op, 129 CollectionTimeScope timeScope, 130 CollectionDuration duration) 131 { 132 using namespace std::string_literals; 133 134 std::vector<std::unique_ptr<CollectionData>> result; 135 136 result.reserve(size); 137 138 switch (timeScope) 139 { 140 case CollectionTimeScope::interval: 141 std::generate_n(std::back_inserter(result), size, 142 [cf = makeCollectionFunction(op), duration] { 143 return std::make_unique<DataInterval>(cf, 144 duration); 145 }); 146 break; 147 case CollectionTimeScope::point: 148 std::generate_n(std::back_inserter(result), size, 149 [] { return std::make_unique<DataPoint>(); }); 150 break; 151 case CollectionTimeScope::startup: 152 std::generate_n(std::back_inserter(result), size, 153 [cf = makeCollectionFunction(op)] { 154 return std::make_unique<DataStartup>(cf); 155 }); 156 break; 157 } 158 159 return result; 160 } 161 162 } // namespace metrics 163