]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
start working on performance imporvements for statistics
authorRazvan Becheriu <razvan@isc.org>
Mon, 15 Jul 2019 12:11:38 +0000 (15:11 +0300)
committerRazvan Becheriu <razvan@isc.org>
Mon, 15 Jul 2019 12:51:49 +0000 (15:51 +0300)
src/lib/stats/observation.cc
src/lib/stats/observation.h

index badd1f86b59a92dbe23e82efab427150934babdd..b2cbc72352b1c7f81e03a8410d1b127845492d79 100644 (file)
@@ -230,38 +230,40 @@ SampleType Observation::getValueInternal(Storage& storage, Type exp_type) const
     return (*storage.begin());
 }
 
-std::list<IntegerSample> Observation::getIntegers() const {
+std::vector<IntegerSample> Observation::getIntegers() const {
     return (getValuesInternal<IntegerSample>(integer_samples_, STAT_INTEGER));
 }
 
-std::list<FloatSample> Observation::getFloats() const {
+std::vector<FloatSample> Observation::getFloats() const {
     return (getValuesInternal<FloatSample>(float_samples_, STAT_FLOAT));
 }
 
-std::list<DurationSample> Observation::getDurations() const {
+std::vector<DurationSample> Observation::getDurations() const {
     return (getValuesInternal<DurationSample>(duration_samples_, STAT_DURATION));
 }
 
-std::list<StringSample> Observation::getStrings() const {
+std::vector<StringSample> Observation::getStrings() const {
     return (getValuesInternal<StringSample>(string_samples_, STAT_STRING));
 }
 
 template<typename SampleType, typename Storage>
-std::list<SampleType> Observation::getValuesInternal(Storage& storage,
-                                                     Type exp_type) const {
+std::vector<SampleType> Observation::getValuesInternal(Storage& storage,
+                                                       Type exp_type) const {
     if (type_ != exp_type) {
         isc_throw(InvalidStatType, "Invalid statistic type requested: "
                   << typeToText(exp_type) << ", but the actual type is "
                   << typeToText(type_));
     }
 
-    if (storage.empty()) {
+    if (storage->empty()) {
         // That should never happen. The first element is always initialized in
         // the constructor. reset() sets its value to zero, but the element should
         // still be there.
         isc_throw(Unexpected, "Observation storage container empty");
     }
-    return (storage);
+    std::vector<SampleType> result(storage->size());
+    std::copy(result.begin(), storage->begin(), storage->end());
+    return (result);
 }
 
 template<typename StorageType>
@@ -280,12 +282,12 @@ void Observation::setMaxSampleAgeInternal(StorageType& storage,
     max_sample_count_.first = false;
 
     StatsDuration range_of_storage =
-        storage.front().second - storage.back().second;
+        storage->front().second - storage->back().second;
 
     while (range_of_storage > duration) {
         // deleting elements which are exceeding the duration limit
-        storage.pop_back();
-        range_of_storage = storage.front().second - storage.back().second;
+        storage->pop_back();
+        range_of_storage = storage->front().second - storage->back().second;
     }
 }
 
@@ -343,11 +345,11 @@ Observation::getJSON() const {
     // retrieving all samples of indicated observation
     switch (type_) {
     case STAT_INTEGER: {
-        std::list<IntegerSample> s = getIntegers(); // List of all integer samples
+        std::vector<IntegerSample> s = getIntegers(); // List of all integer samples
 
         // Iteration over all elements in the list
         // and adding alternately value and timestamp to the entry
-        for (std::list<IntegerSample>::iterator it = s.begin(); it != s.end(); ++it) {
+        for (std::vector<IntegerSample>::iterator it = s.begin(); it != s.end(); ++it) {
             value = isc::data::Element::create(static_cast<int64_t>((*it).first));
             timestamp = isc::data::Element::create(isc::util::ptimeToText((*it).second));
 
@@ -357,11 +359,11 @@ Observation::getJSON() const {
         break;
     }
     case STAT_FLOAT: {
-        std::list<FloatSample> s = getFloats();
+        std::vector<FloatSample> s = getFloats();
 
         // Iteration over all elements in the list
         // and adding alternately value and timestamp to the entry
-        for (std::list<FloatSample>::iterator it = s.begin(); it != s.end(); ++it) {
+        for (std::vector<FloatSample>::iterator it = s.begin(); it != s.end(); ++it) {
             value = isc::data::Element::create((*it).first);
             timestamp = isc::data::Element::create(isc::util::ptimeToText((*it).second));
 
@@ -371,11 +373,11 @@ Observation::getJSON() const {
         break;
     }
     case STAT_DURATION: {
-        std::list<DurationSample> s = getDurations();
+        std::vector<DurationSample> s = getDurations();
 
         // Iteration over all elements in the list
         // and adding alternately value and timestamp to the entry
-        for (std::list<DurationSample>::iterator it = s.begin(); it != s.end(); ++it) {
+        for (std::vector<DurationSample>::iterator it = s.begin(); it != s.end(); ++it) {
             value = isc::data::Element::create(isc::util::durationToText((*it).first));
             timestamp = isc::data::Element::create(isc::util::ptimeToText((*it).second));
 
@@ -385,11 +387,11 @@ Observation::getJSON() const {
         break;
     }
     case STAT_STRING: {
-        std::list<StringSample> s = getStrings();
+        std::vector<StringSample> s = getStrings();
 
         // Iteration over all elements in the list
         // and adding alternately value and timestamp to the entry
-        for (std::list<StringSample>::iterator it = s.begin(); it != s.end(); ++it) {
+        for (std::vector<StringSample>::iterator it = s.begin(); it != s.end(); ++it) {
             value = isc::data::Element::create((*it).first);
             timestamp = isc::data::Element::create(isc::util::ptimeToText((*it).second));
 
@@ -412,22 +414,22 @@ Observation::getJSON() const {
 void Observation::reset() {
     switch(type_) {
     case STAT_INTEGER: {
-        integer_samples_.clear();
+        integer_samples_->clear();
         setValue(static_cast<int64_t>(0));
         return;
     }
     case STAT_FLOAT: {
-        float_samples_.clear();
+        float_samples_->clear();
         setValue(0.0);
         return;
     }
     case STAT_DURATION: {
-        duration_samples_.clear();
+        duration_samples_->clear();
         setValue(time_duration(0, 0, 0, 0));
         return;
     }
     case STAT_STRING: {
-        string_samples_.clear();
+        string_samples_->clear();
         setValue(string(""));
         return;
     }
index 0fa2b7f43956c44af138aa8aa95f85a5a599d27e..a6851d8b62c46d2d68d8c6f8ae30325d4f154925 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <cc/data.h>
 #include <exceptions/exceptions.h>
+#include <boost/circular_buffer.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/date_time/time_duration.hpp>
 #include <boost/date_time/posix_time/posix_time_types.hpp>
@@ -68,6 +69,87 @@ typedef std::pair<std::string, boost::posix_time::ptime> StringSample;
 ///
 /// @todo: Eventually it will be possible to retain multiple samples for the same
 /// observation, but that is outside of scope for 0.9.2.
+
+template<typename SampleType>
+class DataContainerBase {
+public:
+    DataContainerBase() {}
+    virtual ~DataContainerBase() {}
+    virtual void push_front(SampleType&) = 0;
+    virtual SampleType pop_back() = 0;
+    virtual std::vector<SampleType> getValues() = 0;
+    virtual SampleType& front() = 0;
+    virtual SampleType& back() = 0;
+    virtual size_t size() = 0;
+    virtual void clear() = 0;
+};
+
+template<typename SampleType, typename StorageType>
+class DataContainer : public DataContainerBase<SampleType> {
+public:
+    void push_front(SampleType& value) {
+        storage_.push_front(value);
+    }
+    SampleType pop_back() {
+        return storage_.pop_back();
+    }
+    std::vector<SampleType> getValues() {
+        std::vector<SampleType> result(storage_.size());
+        std::copy(storage_.begin(), storage_.end(), result.begin());
+        return (result);
+    }
+    SampleType& front() {
+        return storage_.front();
+    }
+    SampleType& back() {
+        return storage_.back();
+    }
+    size_t size() {
+        return storage_.size();
+    }
+    void clear() {
+        storage_.clear();
+    }
+private:
+    StorageType storage_;
+};
+
+typedef DataContainerBase<IntegerSample> IntegerDataContainerBase;
+typedef std::shared_ptr<IntegerDataContainerBase> IntegerDataContainerBasePtr;
+
+typedef DataContainer<IntegerSample, std::list<IntegerSample>> IntegerListDataContainer;
+typedef std::shared_ptr<IntegerListDataContainer> IntegerListDataContainerPtr;
+
+typedef DataContainer<IntegerSample, boost::circular_buffer<IntegerSample>> IntegerRingDataContainer;
+typedef std::shared_ptr<IntegerRingDataContainer> IntegerRingDataContainerPtr;
+
+typedef DataContainerBase<FloatSample> FloatDataContainerBase;
+typedef std::shared_ptr<FloatDataContainerBase> FloatDataContainerBasePtr;
+
+typedef DataContainer<FloatSample, std::list<FloatSample>> FloatListDataContainer;
+typedef std::shared_ptr<FloatListDataContainer> FloatListDataContainerPtr;
+
+typedef DataContainer<FloatSample, boost::circular_buffer<FloatSample>> FloatRingDataContainer;
+typedef std::shared_ptr<FloatRingDataContainer> FloatRingDataContainerPtr;
+
+typedef DataContainerBase<DurationSample> DurationDataContainerBase;
+typedef std::shared_ptr<DurationDataContainerBase> DurationDataContainerBasePtr;
+
+typedef DataContainer<DurationSample, std::list<DurationSample>> DurationListDataContainer;
+typedef std::shared_ptr<DurationListDataContainer> DurationListDataContainerPtr;
+
+typedef DataContainer<DurationSample, boost::circular_buffer<DurationSample>> DurationRingDataContainer;
+typedef std::shared_ptr<DurationRingDataContainer> DurationRingDataContainerPtr;
+
+typedef DataContainerBase<StringSample> StringDataContainerBase;
+typedef std::shared_ptr<StringDataContainerBase> StringDataContainerBasePtr;
+
+typedef DataContainer<StringSample, std::list<StringSample>> StringListDataContainer;
+typedef std::shared_ptr<StringListDataContainer> StringListDataContainerPtr;
+
+typedef DataContainer<StringSample, boost::circular_buffer<StringSample>> StringRingDataContainer;
+typedef std::shared_ptr<StringRingDataContainer> StringRingDataContainerPtr;
+
 class Observation {
  public:
 
@@ -229,22 +311,22 @@ class Observation {
     /// @brief Returns observed integer samples
     /// @return list of observed samples (value + timestamp)
     /// @throw InvalidStatType if statistic is not integer
-    std::list<IntegerSample> getIntegers() const;
+    std::vector<IntegerSample> getIntegers() const;
 
     /// @brief Returns observed float samples
     /// @return list of observed samples (value + timestamp)
     /// @throw InvalidStatType if statistic is not fp
-    std::list<FloatSample> getFloats() const;
+    std::vector<FloatSample> getFloats() const;
 
     /// @brief Returns observed duration samples
     /// @return list of observed samples (value + timestamp)
     /// @throw InvalidStatType if statistic is not time duration
-    std::list<DurationSample> getDurations() const;
+    std::vector<DurationSample> getDurations() const;
 
     /// @brief Returns observed string samples
     /// @return list of observed samples (value + timestamp)
     /// @throw InvalidStatType if statistic is not a string
-    std::list<StringSample> getStrings() const;
+    std::vector<StringSample> getStrings() const;
 
     /// @brief Returns as a JSON structure
     /// @return JSON structures representing all observations
@@ -309,7 +391,7 @@ private:
     /// @throw InvalidStatType if observation type mismatches
     /// @return list of observed samples
     template<typename SampleType, typename Storage>
-    std::list<SampleType> getValuesInternal(Storage& storage,
+    std::vector<SampleType> getValuesInternal(Storage& storage,
                                             Type exp_type) const;
 
     /// @brief Determines maximum age of samples.
@@ -332,6 +414,9 @@ private:
     void setMaxSampleCountInternal(StorageType& storage,
                                    uint32_t max_samples, Type exp_type);
 
+    template<typename StorageType>
+    void swapStorage();
+
     /// @brief Observation (statistic) name
     std::string name_;
 
@@ -369,16 +454,40 @@ private:
     /// @{
 
     /// @brief Storage for integer samples
-    std::list<IntegerSample> integer_samples_;
+    IntegerDataContainerBasePtr integer_samples_;
 
     /// @brief Storage for floating point samples
-    std::list<FloatSample> float_samples_;
+    FloatDataContainerBasePtr float_samples_;
 
     /// @brief Storage for time duration samples
-    std::list<DurationSample> duration_samples_;
+    DurationDataContainerBasePtr duration_samples_;
 
     /// @brief Storage for string samples
-    std::list<StringSample> string_samples_;
+    StringDataContainerBasePtr string_samples_;
+
+    /// @brief Ring Storage for integer samples
+    IntegerRingDataContainerPtr integer_ring_samples_;
+
+    /// @brief Ring Storage for floating point samples
+    FloatRingDataContainerPtr float_ring_samples_;
+
+    /// @brief Ring Storage for time duration samples
+    DurationRingDataContainerPtr duration_ring_samples_;
+
+    /// @brief Ring Storage for string samples
+    StringRingDataContainerPtr string_ring_samples_;
+
+    /// @brief List Storage for integer samples
+    IntegerListDataContainerPtr integer_list_samples_;
+
+    /// @brief List Storage for floating point samples
+    FloatListDataContainerPtr float_list_samples_;
+
+    /// @brief List Storage for time duration samples
+    DurationListDataContainerPtr duration_list_samples_;
+
+    /// @brief List Storage for string samples
+    StringListDataContainerPtr string_list_samples_;
     /// @}
 };