diff --git a/maxutils/maxbase/include/maxbase/average.hh b/maxutils/maxbase/include/maxbase/average.hh new file mode 100644 index 000000000..3f275645e --- /dev/null +++ b/maxutils/maxbase/include/maxbase/average.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2022-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ +#pragma once + +#include + +#include + +namespace maxbase +{ +/** Regular average, but calculated cumulatively. */ +class CumulativeAverage +{ +public: + // add an average made of num_samples + void add(double ave, int num_samples = 1); + double average() const; + int num_samples() const; + void reset(); + CumulativeAverage& operator+=(const CumulativeAverage& rhs); + CumulativeAverage operator+(const CumulativeAverage& rhs) const; +private: + double m_ave = 0; + int m_num_samples = 0; + int m_num_last_added = 0; +}; + +/** Exponential Moving Average. */ +class EMAverage +{ +public: + EMAverage(double min_alpha, double max_alpha, int sample_max); + + /* add an average made of num_samples + * alpha = m_min_alpha + m_max_alpha * std::min(double(num_samples) / sample_max, 1.0); + * ave = alpha * ave + (1 - alpha) * sample; */ + void add(double ave, int num_samples = 1); + void add(const CumulativeAverage& ca); + double average() const; + int num_samples() const; + void set_sample_max(int sample_max); + int sample_max() const; + void reset(); +private: + const double m_min_alpha; + const double m_max_alpha; + int m_sample_max; + int m_num_samples = 0; + double m_ave = 0; +}; + +} // maxbase diff --git a/maxutils/maxbase/include/maxbase/stopwatch.hh b/maxutils/maxbase/include/maxbase/stopwatch.hh index 5dbce6197..297a831b3 100644 --- a/maxutils/maxbase/include/maxbase/stopwatch.hh +++ b/maxutils/maxbase/include/maxbase/stopwatch.hh @@ -20,18 +20,22 @@ namespace maxbase { -#if __cplusplus >= 201103 -typedef std::chrono::steady_clock Clock; -#else -typedef std::chrono::system_clock Clock; -#endif +using Clock = std::chrono::steady_clock; struct Duration : public Clock::duration // for ADL { - // gcc 4.4 does not inherit constructors, so this is a bit limited. + using Clock::duration::duration; Duration() = default; - Duration(long long l) : Clock::duration(l) {} Duration(Clock::duration d) : Clock::duration(d) {} + Duration(long long l) : Clock::duration(l) {} // FIXME. Get rid of this. + + explicit Duration(double secs) : Duration{rep(secs * period::den / period::num)} + {} + + double secs() + { + return std::chrono::duration(*this).count(); + } }; typedef std::chrono::time_point TimePoint; diff --git a/maxutils/maxbase/src/CMakeLists.txt b/maxutils/maxbase/src/CMakeLists.txt index 527352bea..8cc720f60 100644 --- a/maxutils/maxbase/src/CMakeLists.txt +++ b/maxutils/maxbase/src/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(maxbase STATIC stacktrace.cc worker.cc workertask.cc + average.cc ) set_target_properties(maxbase PROPERTIES VERSION "1.0.0" LINK_FLAGS -Wl,-z,defs) diff --git a/maxutils/maxbase/src/average.cc b/maxutils/maxbase/src/average.cc new file mode 100644 index 000000000..242d1821f --- /dev/null +++ b/maxutils/maxbase/src/average.cc @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2022-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +#include +#include + +namespace maxbase +{ + +void CumulativeAverage::add(double ave, int num_samples) +{ + m_num_samples += num_samples; + + if (m_num_samples == num_samples) + { + m_ave = ave; + } + else + { + m_ave = (m_ave * (m_num_samples - m_num_last_added) + + ave * num_samples) / m_num_samples; + } + m_num_last_added = num_samples; +} + +double CumulativeAverage::average() const +{ + return m_ave; +} + +int CumulativeAverage::num_samples() const +{ + return m_num_samples; +} + +CumulativeAverage &CumulativeAverage::operator+=(const CumulativeAverage &rhs) +{ + this->add(rhs.m_ave, rhs.m_num_samples); + return *this; +} + +CumulativeAverage CumulativeAverage::operator+(const CumulativeAverage &rhs) const +{ + return CumulativeAverage(*this) += rhs; +} + +void CumulativeAverage::reset() +{ + m_ave = 0; + m_num_samples = 0; + m_num_last_added = 0; +} + +EMAverage::EMAverage(double min_alpha, double max_alpha, int sample_max) : + m_min_alpha{min_alpha}, m_max_alpha{max_alpha}, m_sample_max{sample_max} +{ +} + +void EMAverage::add(double ave, int num_samples) +{ + double alpha = m_min_alpha + m_max_alpha * + std::min(double(num_samples) / m_sample_max, 1.0); + + m_num_samples += num_samples; + if (m_num_samples == num_samples) + { + m_ave = ave; + } + else + { + m_ave = alpha * ave + (1 - alpha) * m_ave; + } +} + +void EMAverage::add(const CumulativeAverage &ca) +{ + add(ca.average(), ca.num_samples()); +} + +double EMAverage::average() const +{ + return m_ave; +} + +int EMAverage::num_samples() const +{ + return m_num_samples; +} + +void EMAverage::set_sample_max(int sample_max) +{ + m_sample_max = sample_max; +} + +int EMAverage::sample_max() const +{ + return m_sample_max; +} + +void EMAverage::reset() +{ + m_ave = 0; + m_num_samples = 0; +} + + +} // maxbase