Move Average into average.hh

Moved the class to a more appropriate place.
This commit is contained in:
Markus Mäkelä
2018-09-19 14:20:29 +03:00
parent 5ed3667f4a
commit a94081067f
3 changed files with 250 additions and 252 deletions

View File

@ -13,6 +13,8 @@
#pragma once #pragma once
#include <maxbase/ccdefs.hh> #include <maxbase/ccdefs.hh>
#include <maxbase/atomic.hh>
#include <maxbase/assert.h>
#include <vector> #include <vector>
@ -32,28 +34,28 @@ public:
* @param ave The average value * @param ave The average value
* @param num_samples How many samples were taken to construct it * @param num_samples How many samples were taken to construct it
*/ */
void add(double ave, int num_samples = 1); void add(double ave, int num_samples = 1);
/** /**
* Get the average value * Get the average value
* *
* @return The average value * @return The average value
*/ */
double average() const; double average() const;
/** /**
* Get number of samples * Get number of samples
* *
* @return Number of collected samples * @return Number of collected samples
*/ */
int num_samples() const; int num_samples() const;
/** /**
* Reset the average value * Reset the average value
* *
* Sets the average to 0.0 and number of samples to 0. * Sets the average to 0.0 and number of samples to 0.
*/ */
void reset(); void reset();
CumulativeAverage& operator+=(const CumulativeAverage& rhs); CumulativeAverage& operator+=(const CumulativeAverage& rhs);
private: private:
@ -99,7 +101,7 @@ public:
* @param ave Value to add * @param ave Value to add
* @param num_samples Number of samples the value consists of * @param num_samples Number of samples the value consists of
*/ */
void add(double ave, int num_samples = 1); void add(double ave, int num_samples = 1);
/** /**
* Add a CumulativeAverage * Add a CumulativeAverage
@ -108,7 +110,7 @@ public:
* *
* @param ca CumulativeAverage to add * @param ca CumulativeAverage to add
*/ */
void add(const CumulativeAverage& ca); void add(const CumulativeAverage& ca);
/** /**
* Get the current average value * Get the current average value
@ -122,28 +124,28 @@ public:
* *
* @return The number of samples * @return The number of samples
*/ */
int num_samples() const; int num_samples() const;
/** /**
* Set maximum sample size * Set maximum sample size
* *
* @param sample_max The new sample max size * @param sample_max The new sample max size
*/ */
void set_sample_max(int sample_max); void set_sample_max(int sample_max);
/** /**
* Get maximum sample size * Get maximum sample size
* *
* @return The maximum sample size * @return The maximum sample size
*/ */
int sample_max() const; int sample_max() const;
/** /**
* Reset the average * Reset the average
* *
* Sets average value to 0.0 and number of samples to 0. * Sets average value to 0.0 and number of samples to 0.
*/ */
void reset(); void reset();
private: private:
const double m_min_alpha; const double m_min_alpha;
@ -152,4 +154,241 @@ private:
int m_num_samples = 0; int m_num_samples = 0;
double m_ave = 0; double m_ave = 0;
}; };
/**
* Average is a base class for classes intended to be used for calculating
* averages. An Average may have a dependant Average whose value depends
* upon the value of the first. At certain moments, an Average may trigger
* its dependant Average to update itself.
*/
class Average
{
Average(const Average&) = delete;
Average& operator=(const Average&) = delete;
public:
/**
* Constructor
*
* @param pDependant An optional dependant average.
*/
Average(Average* pDependant = NULL)
: m_pDependant(pDependant)
, m_value(0)
{
}
/**
* Add a value to the Average. The exact meaning depends upon the
* concrete Average class.
*
* If the addition of the value in some sense represents a full cycle
* in the average calculation, then the instance will call add_value()
* on its dependant, otherwise it will call update_value(). In both cases
* with its own value as argument.
*
* @param value The value to be added.
*
* @return True if the addition of the value caused a full cycle
* in the average calculation, false otherwise.
*/
virtual bool add_value(uint8_t value) = 0;
/**
* Update the value of the Average. The exact meaning depends upon the
* concrete Average class. Will also call update_value() of its dependant
* with its own value as argument.
*
* @param value The value to be updated.
*/
virtual void update_value(uint8_t value) = 0;
/**
* Return the average value.
*
* @return The value represented by the Average.
*/
uint8_t value() const
{
return mxb::atomic::load(&m_value);
}
protected:
Average* m_pDependant; /*< The optional dependant Average. */
uint32_t m_value; /*< The current average value. */
protected:
void set_value(uint32_t value)
{
mxb::atomic::store(&m_value, value);
}
};
/**
* An Average consisting of a single value.
*/
class Average1 : public Average
{
public:
Average1(Average* pDependant = NULL)
: Average(pDependant)
{
}
bool add_value(uint8_t value)
{
set_value(value);
// Every addition of a value represents a full cycle.
if (m_pDependant)
{
m_pDependant->add_value(value);
}
return true;
}
void update_value(uint8_t value)
{
set_value(value);
if (m_pDependant)
{
m_pDependant->update_value(value);
}
}
};
/**
* An Average calculated from N values.
*/
template<size_t N>
class AverageN : public Average
{
public:
AverageN(Average* pDependant = NULL)
: Average(pDependant)
, m_end(m_begin + N)
, m_i(m_begin)
, m_sum(0)
, m_nValues(0)
{
}
bool add_value(uint8_t value)
{
if (m_nValues == N)
{
// If as many values that fit has been added, then remove the
// least recent value from the sum.
m_sum -= *m_i;
}
else
{
// Otherwise make a note that a new value is added.
++m_nValues;
}
*m_i = value;
m_sum += *m_i; // Update the sum of all values.
m_i = next(m_i);
uint32_t average = m_sum / m_nValues;
set_value(average);
if (m_pDependant)
{
if (m_i == m_begin)
{
// If we have looped around we have performed a full cycle and will
// add a new value to the dependant average.
m_pDependant->add_value(average);
}
else
{
// Otherwise we just update the most recent value.
m_pDependant->update_value(average);
}
}
return m_i == m_begin;
}
void update_value(uint8_t value)
{
if (m_nValues == 0)
{
// If no values have been added yet, there's nothing to update but we
// need to add the value.
add_value(value);
}
else
{
// Otherwise we update the most recent value.
uint8_t* p = prev(m_i);
m_sum -= *p;
*p = value;
m_sum += *p;
uint32_t average = m_sum / m_nValues;
set_value(average);
if (m_pDependant)
{
m_pDependant->update_value(average);
}
}
}
private:
uint8_t* prev(uint8_t* p)
{
mxb_assert(p >= m_begin);
mxb_assert(p < m_end);
if (p > m_begin)
{
--p;
}
else
{
mxb_assert(p == m_begin);
p = m_end - 1;
}
mxb_assert(p >= m_begin);
mxb_assert(p < m_end);
return p;
}
uint8_t* next(uint8_t* p)
{
mxb_assert(p >= m_begin);
mxb_assert(p < m_end);
++p;
if (p == m_end)
{
p = m_begin;
}
mxb_assert(p >= m_begin);
mxb_assert(p < m_end);
return p;
}
private:
uint8_t m_begin[N]; /*< Buffer containing values from which the average is calculated. */
uint8_t* m_end; /*< Points to one past the end of the buffer. */
uint8_t* m_i; /*< Current position in the buffer. */
uint32_t m_sum; /*< Sum of all values in the buffer. */
uint32_t m_nValues; /*< How many values the buffer contains. */
};
} }

View File

@ -24,6 +24,7 @@
#include <maxbase/assert.h> #include <maxbase/assert.h>
#include <maxbase/atomic.h> #include <maxbase/atomic.h>
#include <maxbase/average.hh>
#include <maxbase/messagequeue.hh> #include <maxbase/messagequeue.hh>
#include <maxbase/semaphore.hh> #include <maxbase/semaphore.hh>
#include <maxbase/worker.h> #include <maxbase/worker.h>
@ -175,244 +176,6 @@ public:
static uint64_t get_time(); static uint64_t get_time();
private: private:
/**
* Average is a base class for classes intended to be used for calculating
* averages. An Average may have a dependant Average whose value depends
* upon the value of the first. At certain moments, an Average may trigger
* its dependant Average to update itself.
*/
class Average
{
Average(const Average&) = delete;
Average& operator=(const Average&) = delete;
public:
/**
* Constructor
*
* @param pDependant An optional dependant average.
*/
Average(Average* pDependant = NULL)
: m_pDependant(pDependant)
, m_value(0)
{
}
virtual ~Average();
/**
* Add a value to the Average. The exact meaning depends upon the
* concrete Average class.
*
* If the addition of the value in some sense represents a full cycle
* in the average calculation, then the instance will call add_value()
* on its dependant, otherwise it will call update_value(). In both cases
* with its own value as argument.
*
* @param value The value to be added.
*
* @return True if the addition of the value caused a full cycle
* in the average calculation, false otherwise.
*/
virtual bool add_value(uint8_t value) = 0;
/**
* Update the value of the Average. The exact meaning depends upon the
* concrete Average class. Will also call update_value() of its dependant
* with its own value as argument.
*
* @param value The value to be updated.
*/
virtual void update_value(uint8_t value) = 0;
/**
* Return the average value.
*
* @return The value represented by the Average.
*/
uint8_t value() const
{
return atomic_load_uint32(&m_value);
}
protected:
Average* m_pDependant; /*< The optional dependant Average. */
uint32_t m_value; /*< The current average value. */
protected:
void set_value(uint32_t value)
{
atomic_store_uint32(&m_value, value);
}
};
/**
* An Average consisting of a single value.
*/
class Average1 : public Average
{
public:
Average1(Average* pDependant = NULL)
: Average(pDependant)
{
}
bool add_value(uint8_t value)
{
set_value(value);
// Every addition of a value represents a full cycle.
if (m_pDependant)
{
m_pDependant->add_value(value);
}
return true;
}
void update_value(uint8_t value)
{
set_value(value);
if (m_pDependant)
{
m_pDependant->update_value(value);
}
}
};
/**
* An Average calculated from N values.
*/
template<size_t N>
class AverageN : public Average
{
public:
AverageN(Average* pDependant = NULL)
: Average(pDependant)
, m_end(m_begin + N)
, m_i(m_begin)
, m_sum(0)
, m_nValues(0)
{
}
bool add_value(uint8_t value)
{
if (m_nValues == N)
{
// If as many values that fit has been added, then remove the
// least recent value from the sum.
m_sum -= *m_i;
}
else
{
// Otherwise make a note that a new value is added.
++m_nValues;
}
*m_i = value;
m_sum += *m_i; // Update the sum of all values.
m_i = next(m_i);
uint32_t average = m_sum / m_nValues;
set_value(average);
if (m_pDependant)
{
if (m_i == m_begin)
{
// If we have looped around we have performed a full cycle and will
// add a new value to the dependant average.
m_pDependant->add_value(average);
}
else
{
// Otherwise we just update the most recent value.
m_pDependant->update_value(average);
}
}
return m_i == m_begin;
}
void update_value(uint8_t value)
{
if (m_nValues == 0)
{
// If no values have been added yet, there's nothing to update but we
// need to add the value.
add_value(value);
}
else
{
// Otherwise we update the most recent value.
uint8_t* p = prev(m_i);
m_sum -= *p;
*p = value;
m_sum += *p;
uint32_t average = m_sum / m_nValues;
set_value(average);
if (m_pDependant)
{
m_pDependant->update_value(average);
}
}
}
private:
uint8_t* prev(uint8_t* p)
{
mxb_assert(p >= m_begin);
mxb_assert(p < m_end);
if (p > m_begin)
{
--p;
}
else
{
mxb_assert(p == m_begin);
p = m_end - 1;
}
mxb_assert(p >= m_begin);
mxb_assert(p < m_end);
return p;
}
uint8_t* next(uint8_t* p)
{
mxb_assert(p >= m_begin);
mxb_assert(p < m_end);
++p;
if (p == m_end)
{
p = m_begin;
}
mxb_assert(p >= m_begin);
mxb_assert(p < m_end);
return p;
}
private:
uint8_t m_begin[N]; /*< Buffer containing values from which the average is calculated. */
uint8_t* m_end; /*< Points to one past the end of the buffer. */
uint8_t* m_i; /*< Current position in the buffer. */
uint32_t m_sum; /*< Sum of all values in the buffer. */
uint32_t m_nValues; /*< How many values the buffer contains. */
};
uint64_t m_start_time; /*< When was the current 1-second period started. */ uint64_t m_start_time; /*< When was the current 1-second period started. */
uint64_t m_wait_start; /*< The time when the worker entered epoll_wait(). */ uint64_t m_wait_start; /*< The time when the worker entered epoll_wait(). */

View File

@ -103,10 +103,6 @@ void WorkerLoad::about_to_work(uint64_t now)
} }
} }
WorkerLoad::Average::~Average()
{
}
// static // static
uint64_t WorkerLoad::get_time() uint64_t WorkerLoad::get_time()
{ {