diff --git a/common/include/villas/hist.hpp b/common/include/villas/hist.hpp index ca3ea0be6..662c49a63 100644 --- a/common/include/villas/hist.hpp +++ b/common/include/villas/hist.hpp @@ -23,8 +23,7 @@ #pragma once -#include -#include +#include #include @@ -38,13 +37,11 @@ class Hist { public: using cnt_t = uintmax_t; + using idx_t = std::vector::difference_type; /** Initialize struct hist with supplied values and allocate memory for buckets. */ Hist(int buckets = 0, cnt_t warmup = 0); - /** Free the dynamically allocated memory. */ - ~Hist(); - /** Reset all counters and values back to zero. */ void reset(); @@ -121,8 +118,6 @@ protected: double lowest; /**< The lowest value observed (may be lower than #low). */ double last; /**< The last value which has been put into the buckets */ - int length; /**< The number of buckets in #data. */ - cnt_t total; /**< Total number of counted values. */ cnt_t warmup; /**< Number of values which are used during warmup phase. */ @@ -130,7 +125,7 @@ protected: cnt_t lower; /**< The number of values which are lower than #low. */ - cnt_t *data; /**< Pointer to dynamically allocated array of size length. */ + std::vector data; /**< Bucket counters. */ double _m[2], _s[2]; /**< Private variables for online variance calculation */ }; diff --git a/common/lib/hist.cpp b/common/lib/hist.cpp index ef1544cac..f7e53dd26 100644 --- a/common/lib/hist.cpp +++ b/common/lib/hist.cpp @@ -20,12 +20,8 @@ * along with this program. If not, see . *********************************************************************************/ -#include -#include -#include -#include #include -#include +#include #include #include @@ -36,21 +32,10 @@ using namespace villas::utils; namespace villas { -Hist::Hist(int buckets, Hist::cnt_t wu) -{ - length = buckets; - warmup = wu; - - data = (Hist::cnt_t *) (buckets ? alloc(length * sizeof(Hist::cnt_t)) : nullptr); - - Hist::reset(); -} - -Hist::~Hist() -{ - if (data) - free(data); -} +Hist::Hist(int buckets, Hist::cnt_t wu) : + warmup(wu), + data(buckets) +{ } void Hist::put(double value) { @@ -62,24 +47,26 @@ void Hist::put(double value) if (value < lowest) lowest = value; - if (total < warmup) { + if (data.size()) { + if (total < warmup) { + /* We are still in warmup phase... Waiting for more samples... */ + } + else if (data.size() && total == warmup) { + low = getMean() - 3 * getStddev(); + high = getMean() + 3 * getStddev(); + resolution = (high - low) / data.size(); + } + else { + idx_t idx = std::round((value - low) / resolution); - } - else if (total == warmup) { - low = getMean() - 3 * getStddev(); - high = getMean() + 3 * getStddev(); - resolution = (high - low) / length; - } - else { - int idx = round((value - low) / resolution); - - /* Check bounds and increment */ - if (idx >= length) - higher++; - else if (idx < 0) - lower++; - else if (data != nullptr) - data[idx]++; + /* Check bounds and increment */ + if (idx >= (idx_t) data.size()) + higher++; + else if (idx < 0) + lower++; + else + data[idx]++; + } } total++; @@ -107,21 +94,21 @@ void Hist::reset() higher = 0; lower = 0; - highest = -DBL_MAX; - lowest = DBL_MAX; + highest = std::numeric_limits::min(); + lowest = std::numeric_limits::max(); - if (data) - memset(data, 0, length * sizeof(unsigned)); + for (auto &elm : data) + elm = 0; } double Hist::getMean() const { - return (total > 0) ? _m[0] : NAN; + return total > 0 ? _m[0] : std::numeric_limits::quiet_NaN(); } double Hist::getVar() const { - return (total > 1) ? _s[0] / (total - 1) : NAN; + return total > 1 ? _s[0] / (total - 1) : std::numeric_limits::quiet_NaN(); } double Hist::getStddev() const @@ -156,13 +143,8 @@ void Hist::print(bool details) const void Hist::plot() const { - Hist::cnt_t max = 1; - /* Get highest bar */ - for (int i = 0; i < length; i++) { - if (data[i] > max) - max = data[i]; - } + Hist::cnt_t max = *std::max_element(data.begin(), data.end()); std::vector cols = { { -9, TableColumn::Alignment::RIGHT, "Value", "%+9.3g" }, @@ -175,7 +157,7 @@ void Hist::plot() const /* Print plot */ table.header(); - for (int i = 0; i < length; i++) { + for (size_t i = 0; i < data.size(); i++) { double value = low + (i) * resolution; Hist::cnt_t cnt = data[i]; int bar = cols[2].getWidth() * ((double) cnt / max); @@ -196,8 +178,8 @@ char * Hist::dump() const strcatf(&buf, "[ "); - for (int i = 0; i < length; i++) - strcatf(&buf, "%ju ", data[i]); + for (auto elm : data) + strcatf(&buf, "%ju ", elm); strcatf(&buf, "]"); @@ -229,8 +211,8 @@ json_t * Hist::toJson() const if (total - lower - higher > 0) { json_buckets = json_array(); - for (int i = 0; i < length; i++) - json_array_append(json_buckets, json_integer(data[i])); + for (auto elm : data) + json_array_append(json_buckets, json_integer(elm)); json_object_set(json_hist, "buckets", json_buckets); } @@ -269,7 +251,7 @@ int Hist::dumpMatlab(FILE *f) const free(buf); } else - fprintf(f, "'buckets', zeros(1, %d)", length); + fprintf(f, "'buckets', zeros(1, %zu)", data.size()); fprintf(f, ")"); diff --git a/common/tests/unit/hist.cpp b/common/tests/unit/hist.cpp index e011b6a8a..06c026e50 100644 --- a/common/tests/unit/hist.cpp +++ b/common/tests/unit/hist.cpp @@ -20,12 +20,14 @@ * along with this program. If not, see . *********************************************************************************/ +#include + #include #include #include -const double test_data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; +const std::array test_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; using namespace villas; @@ -35,10 +37,10 @@ Test(hist, simple) { Hist h; - for (unsigned i = 0; i < ARRAY_LEN(test_data); i++) - h.put(test_data[i]); + for (auto td : test_data) + h.put(td); - cr_assert_float_eq(h.getMean(), 5.5, 1e-6); + cr_assert_float_eq(h.getMean(), 5.5, 1e-6, "Mean is %lf", h.getMean()); cr_assert_float_eq(h.getVar(), 9.1666, 1e-3,); cr_assert_float_eq(h.getStddev(), 3.027650, 1e-6); }