522 lines
18 KiB
C++
522 lines
18 KiB
C++
#ifndef CLICK_EWMA_HH
|
|
#define CLICK_EWMA_HH
|
|
#include <click/glue.hh>
|
|
#include <click/confparse.hh>
|
|
CLICK_DECLS
|
|
|
|
/** @file <click/ewma.hh>
|
|
* @brief Click's classes for supporting exponentially weighted moving
|
|
* averages.
|
|
*/
|
|
|
|
/** @class DirectEWMAX include/click/ewma.hh <click/ewma.hh>
|
|
* @brief An exponentially weighted moving average.
|
|
*
|
|
* The DirectEWMAX template class represents a simple exponentially weighted
|
|
* moving average. The average starts out with value 0. The update()
|
|
* function adds a new observation to the average.
|
|
*
|
|
* The template parameter P defines three EWMA parameters: value type,
|
|
* stability shift, and scale factor.
|
|
*
|
|
* The value type is simply the unsigned integral type used to store the
|
|
* average. It is also the type of each observation. <code>unsigned</code>
|
|
* and <code>uint64_t</code> are examples.
|
|
*
|
|
* The stability shift specifies alpha, the stability parameter. Concretely,
|
|
* alpha = 1. / (2 ** stability_shift). Thus, a stability shift of 4
|
|
* corresponds to an alpha of 1/16.
|
|
*
|
|
* The scaling factor specifies how many bits of fraction are kept per
|
|
* observation. Fraction bits are necessary to account for small differences
|
|
* between observations. For example, consider a EWMA with value 0, alpha
|
|
* 1/16, and 0 bits of fraction. Assume the EWMA begins to observe a stream
|
|
* of observations equal to 1. Despite these observations, the EWMA's value
|
|
* will never change from 0, since the 1/16 alpha factor rounds the new
|
|
* observations down to 0. At least 4 bits of fraction are required to
|
|
* account for this difference. There is a tradeoff: the more bits of
|
|
* fraction, the more precise the EWMA, but the less bits available to
|
|
* account for large values.
|
|
*
|
|
* These EWMA parameters are defined by five of P's members, two typedefs and
|
|
* three possibly static member functions.
|
|
*
|
|
* <dl>
|
|
* <dt><strong>P::value_type</strong></dt>
|
|
* <dd>The EWMA's value type. Example: <code>unsigned</code>.</dd>
|
|
*
|
|
* <dt><strong>P::signed_value_type</strong></dt>
|
|
* <dd>The signed version of <code>P::value_type</code>. Used internally.
|
|
* Example: <code>int</code>.</dd>
|
|
*
|
|
* <dt><strong>unsigned P::stability_shift()</strong></dt>
|
|
* <dd>This function should return this EWMA's stability shift
|
|
* (see above).</dd>
|
|
*
|
|
* <dt><strong>unsigned P::scale()</strong></dt>
|
|
* <dd>This function should return this EWMA's scaling factor
|
|
* (see above).</dd>
|
|
*
|
|
* <dt><strong>unsigned P::compensation()</strong></dt>
|
|
* <dd>This function should return this EWMA's stability compensation,
|
|
* which normally equals 1 @<@< (stability_shift - 1).</dd>
|
|
* </dl>
|
|
*
|
|
* Since DirectEWMAX inherits from an object of type P, these members are
|
|
* also directly available to callers.
|
|
*
|
|
* The FixedEWMAXParameters and StabilityEWMAXParameters types are good
|
|
* template arguments for DirectEWMAX.
|
|
*
|
|
* @sa RateEWMAX
|
|
*/
|
|
template <typename P>
|
|
class DirectEWMAX : public P { public:
|
|
|
|
typedef typename P::value_type value_type;
|
|
|
|
/** @brief Construct a EWMA with initial average 0. */
|
|
DirectEWMAX()
|
|
: _avg(0) {
|
|
}
|
|
|
|
/** @brief Construct a EWMA with initial scaled average @a scaled_value. */
|
|
DirectEWMAX(value_type scaled_value)
|
|
: _avg(scaled_value) {
|
|
}
|
|
|
|
/** @brief Return the current scaled moving average.
|
|
* @note The returned value has scale() bits of fraction. */
|
|
value_type scaled_average() const {
|
|
return _avg;
|
|
}
|
|
|
|
/** @brief Return the current moving average, rounded up.
|
|
* @note The returned value is unscaled (has zero bits of fraction). */
|
|
value_type unscaled_average() const {
|
|
return (_avg + (P::scaled_one() >> 1)) >> P::scale();
|
|
}
|
|
|
|
/** @brief Reset the EWMA to value 0. */
|
|
void clear() {
|
|
_avg = 0;
|
|
}
|
|
|
|
/** @brief Assign the EWMA to scaled average @a scaled_value. */
|
|
inline void assign(value_type scaled_value) {
|
|
_avg = scaled_value;
|
|
}
|
|
|
|
/** @brief Update the moving average with a new observation.
|
|
* @param x the observation (unscaled) */
|
|
inline void update(value_type x);
|
|
|
|
/** @brief Update the moving average with @a n identical observations.
|
|
* @param x the observation (unscaled)
|
|
* @param n number of observations
|
|
* @note This may be faster than calling update(@a x) @a n
|
|
* times. */
|
|
void update_n(value_type x, unsigned n);
|
|
|
|
/** @brief Unparse the current average into a String.
|
|
* @note The returned value is unscaled, but may contain a fractional
|
|
* part. */
|
|
String unparse() const;
|
|
|
|
/** @brief Update the moving average with a new observation (deprecated).
|
|
* @param x the observation (unscaled)
|
|
* @deprecated Use update() instead. */
|
|
inline void update_with(value_type x) CLICK_DEPRECATED;
|
|
|
|
private:
|
|
|
|
value_type _avg;
|
|
|
|
};
|
|
|
|
template <typename P>
|
|
inline void
|
|
DirectEWMAX<P>::update(value_type x)
|
|
{
|
|
value_type x_scaled = (x << P::scale()) + P::compensation();
|
|
unsigned stability = P::stability_shift();
|
|
#if HAVE_ARITHMETIC_RIGHT_SHIFT
|
|
_avg += static_cast<typename P::signed_value_type>(x_scaled - _avg) >> stability;
|
|
#else
|
|
if (x_scaled < _avg)
|
|
_avg -= (_avg - x_scaled) >> stability;
|
|
else
|
|
_avg += (x_scaled - _avg) >> stability;
|
|
#endif
|
|
}
|
|
|
|
template <typename P>
|
|
void
|
|
DirectEWMAX<P>::update_n(value_type x, unsigned n)
|
|
{
|
|
// XXX use table lookup
|
|
value_type x_scaled = x << P::scale();
|
|
if (n >= 100)
|
|
_avg = x_scaled;
|
|
else {
|
|
x_scaled += P::compensation();
|
|
unsigned stability = P::stability_shift();
|
|
#if HAVE_ARITHMETIC_RIGHT_SHIFT
|
|
for (; n > 0; n--)
|
|
_avg += static_cast<typename P::signed_value_type>(x_scaled - _avg) >> stability;
|
|
#else
|
|
if (x_scaled < _avg)
|
|
for (; n > 0; n--)
|
|
_avg -= (_avg - x_scaled) >> stability;
|
|
else
|
|
for (; n > 0; n--)
|
|
_avg += (x_scaled - _avg) >> stability;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
template <typename P>
|
|
inline String
|
|
DirectEWMAX<P>::unparse() const
|
|
{
|
|
return cp_unparse_real2(scaled_average(), P::scale());
|
|
}
|
|
|
|
template <typename P>
|
|
inline void
|
|
DirectEWMAX<P>::update_with(value_type x)
|
|
{
|
|
update(x);
|
|
}
|
|
|
|
/** @class FixedEWMAXParameters include/click/ewma.hh <click/ewma.hh>
|
|
* @brief Parameters for a EWMA with constant scaling factor and stability
|
|
* shift.
|
|
*
|
|
* The FixedEWMAXParameters template class is used as a template argument to
|
|
* DirectEWMAX. It defines a EWMA with fixed constant scaling factor and
|
|
* stability shift. FixedEWMAXParameters's first template argument is the
|
|
* EWMA's stability shift, its second template argument is the EWMA's scaling
|
|
* factor, its third template argument is the EWMA's value type, and the
|
|
* fourth template argument is the EWMA's signed value type.
|
|
*
|
|
* Example 1: <code>DirectEWMAX@<FixedEWMAXParameters@<4, 10, unsigned, int@>
|
|
* @></code> defines a EWMA with alpha 1/16 (stability shift 4), scaling
|
|
* factor 10, and value type unsigned. (These are the default parameters
|
|
* available in the DirectEWMA typedef.)
|
|
*
|
|
* Example 2: <code>DirectEWMAX@<FixedEWMAXParameters@<3, 10, uint64_t,
|
|
* int64_t@> @></code> defines a EWMA with alpha 1/8 (stability shift 3),
|
|
* scaling factor 10, and value type uint64_t.
|
|
*/
|
|
template <unsigned STABILITY, unsigned SCALE, typename T = unsigned, typename U = int>
|
|
class FixedEWMAXParameters { public:
|
|
|
|
typedef T value_type;
|
|
typedef U signed_value_type;
|
|
|
|
/** @brief Return this EWMA's stability shift.
|
|
* @return the 1st template parameter */
|
|
static unsigned stability_shift() {
|
|
return STABILITY;
|
|
}
|
|
|
|
/** @brief Return this EWMA's scaling factor (bits of fraction).
|
|
* @return the 2nd template parameter */
|
|
static unsigned scale() {
|
|
static_assert(SCALE < sizeof(T) * 8, "SCALE too big for EWMA type.");
|
|
return SCALE;
|
|
}
|
|
|
|
/** @brief Return this EWMA's scaled value for one. */
|
|
static value_type scaled_one() {
|
|
return (value_type) 1 << SCALE;
|
|
}
|
|
|
|
/** @brief Return this EWMA's compensation.
|
|
* @return 1 << (stability_shift() - 1) */
|
|
static unsigned compensation() {
|
|
return 1 << (STABILITY - 1);
|
|
}
|
|
|
|
};
|
|
|
|
/** @brief A DirectEWMAX with stability shift 4 (alpha 1/16), scaling factor
|
|
* 10 (10 bits of fraction), and underlying type <code>unsigned</code>. */
|
|
typedef DirectEWMAX<FixedEWMAXParameters<4, 10> > DirectEWMA;
|
|
|
|
/** @brief A DirectEWMAX with stability shift 3 (alpha 1/8), scaling factor
|
|
* 10 (10 bits of fraction), and underlying type <code>unsigned</code>. */
|
|
typedef DirectEWMAX<FixedEWMAXParameters<3, 10> > FastDirectEWMA;
|
|
|
|
|
|
/** @class StabilityEWMAXParameters include/click/ewma.hh <click/ewma.hh>
|
|
* @brief Parameters for a EWMA with constant scaling factor
|
|
* and user-settable alpha.
|
|
*
|
|
* The StabilityEWMAXParameters template class is used as a template argument
|
|
* to DirectEWMAX. It defines a EWMA with fixed constant scaling factor.
|
|
* StabilityEWMAXParameters's first template argument is the EWMA's scaling
|
|
* factor, its second template argument is the EWMA's value type, and the
|
|
* third template argument is the EWMA's signed value type.
|
|
*
|
|
* Example: <code>DirectEWMAX@<StabilityEWMAXParameters@<10, unsigned, int@>
|
|
* @></code> defines a EWMA with user-settable alpha (stability shift)
|
|
* initially equal to 1/16, scaling factor 10, and value type unsigned.
|
|
*
|
|
* A <code>DirectEWMAX@<StabilityEWMAXParameters@<...@> @></code> object has
|
|
* stability_shift() and set_stability_shift() methods.
|
|
*/
|
|
template <unsigned SCALE, typename T = unsigned, typename U = int>
|
|
class StabilityEWMAXParameters { public:
|
|
|
|
typedef T value_type;
|
|
typedef U signed_value_type;
|
|
|
|
/** @brief Construct a StabilityEWMAXParameters with initial alpha 1/16. */
|
|
StabilityEWMAXParameters()
|
|
: _stability(4) {
|
|
}
|
|
|
|
/** @brief Return the current stability shift.
|
|
*
|
|
* The current alpha equals 1. / (2 ** stability_shift()). */
|
|
unsigned stability_shift() const {
|
|
return _stability;
|
|
}
|
|
|
|
/** @brief Set the current stability shift.
|
|
* @param stability_shift new value */
|
|
void set_stability_shift(unsigned stability_shift) {
|
|
_stability = stability_shift;
|
|
}
|
|
|
|
/** @brief Return this EWMA's scaling factor (bits of fraction).
|
|
* @return the 1st template parameter */
|
|
static unsigned scale() {
|
|
return SCALE;
|
|
}
|
|
|
|
/** @brief Return this EWMA's scaled value for one. */
|
|
static value_type scaled_one() {
|
|
return (value_type) 1 << SCALE;
|
|
}
|
|
|
|
/** @brief Return this EWMA's compensation.
|
|
* @return 1 << (stability_shift() - 1) */
|
|
unsigned compensation() const {
|
|
return 1 << (stability_shift() - 1);
|
|
}
|
|
|
|
private:
|
|
|
|
unsigned _stability;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** @class RateEWMAX include/click/ewma.hh <click/ewma.hh>
|
|
* @brief An exponentially weighted moving average used to measure a rate.
|
|
*
|
|
* The RateEWMAX template class represents an exponentially weighted moving
|
|
* average that measures a <em>rate</em>: a count of events per unit time.
|
|
* The average starts out with value 0.
|
|
*
|
|
* RateEWMAX adds to DirectEWMAX a concept of epochs, which are periods of
|
|
* time. A RateEWMAX object collects samples over the current epoch. When
|
|
* the epoch closes, the collected sample count is used to update the moving
|
|
* average. Thus, the moving average is measured in samples per epoch. The
|
|
* rate() and unparse_rate() member functions return the rate in samples per
|
|
* <em>second</em>, rather than per epoch. These functions use the epoch
|
|
* frequency to translate between epochs and seconds.
|
|
*
|
|
* Note that it often makes sense to call update() before calling
|
|
* scaled_average(), rate(), or unparse_rate(), in case an epoch or two has
|
|
* passed and the average should take account of passing time.
|
|
*
|
|
* The template parameter P defines the EWMA parameters required by
|
|
* DirectEWMAX, and three others: a rate count, an epoch measurement, and an
|
|
* epoch frequency.
|
|
*
|
|
* The rate count is the number of rates measured per object. Usually it is
|
|
* 1.
|
|
*
|
|
* The epoch measurement is a function that returns the current epoch as an
|
|
* unsigned number. Epochs should increase monotonically.
|
|
*
|
|
* The epoch frequency is the number of epochs per second, and is only used
|
|
* by rate() and unparse_rate().
|
|
*
|
|
* These are defined by:
|
|
*
|
|
* <dl>
|
|
* <dt><strong>P::rate_count</strong></dt>
|
|
* <dd>The rate count, as a static constant (for example, defined by an
|
|
* enum).</dd>
|
|
*
|
|
* <dt><strong>unsigned P::epoch()</strong></dt>
|
|
* <dd>This function returns the current epoch number.</dd>
|
|
*
|
|
* <dt><strong>unsigned P::epoch_frequency()</strong></dt>
|
|
* <dd>This function returns the number of epochs per second.</dd>
|
|
* </dl>
|
|
*
|
|
* Since RateEWMAX inherits from an object of type P, these members are
|
|
* also directly available to callers.
|
|
*
|
|
* The RateEWMAXParameters type is a good template argument for RateEWMAX.
|
|
*
|
|
* @sa DirectEWMAX
|
|
*/
|
|
template <typename P>
|
|
class RateEWMAX : public P { public:
|
|
|
|
typedef typename P::value_type value_type;
|
|
typedef typename P::signed_value_type signed_value_type;
|
|
|
|
/** @brief Create a rate EWMA with initial value(s) 0. */
|
|
RateEWMAX() {
|
|
_current_epoch = P::epoch();
|
|
for (unsigned i = 0; i < P::rate_count; i++)
|
|
_current[i] = 0;
|
|
}
|
|
|
|
/** @brief Return the current scaled moving average.
|
|
* @param ratenum rate index (0 <= ratenum < rate_count)
|
|
* @note The returned value has scale() bits of fraction.
|
|
* @note scaled_average() does not check the current epoch.
|
|
* If an epoch might have passed since the last update(), you
|
|
* should call update(0, @a ratenum) before calling this
|
|
* function. */
|
|
signed_value_type scaled_average(unsigned ratenum = 0) const {
|
|
// note: return type must be signed!
|
|
return _avg[ratenum].scaled_average();
|
|
}
|
|
|
|
/** @brief Returns one of the average's scaling factors (bits of
|
|
* fraction). */
|
|
unsigned scale(unsigned ratenum = 0) const {
|
|
return _avg[ratenum].scale();
|
|
}
|
|
|
|
/** @brief Return the current rate in samples per second.
|
|
* @param ratenum rate index (0 <= ratenum < rate_count)
|
|
* @note The returned value is unscaled.
|
|
* @note rate() does not check the current epoch.
|
|
* If an epoch might have passed since the last update(), you
|
|
* should call update(0, @a ratenum) before calling this
|
|
* function. */
|
|
inline int rate(unsigned ratenum = 0) const;
|
|
|
|
/** @brief Update the sample count for the current epoch.
|
|
* @param delta increment for current epoch sample count
|
|
* @param ratenum rate index (0 <= ratenum < rate_count)
|
|
* @note If the epoch has changed since the last update(),
|
|
* this function applies the last epoch's sample count (if any)
|
|
* to the relevant moving average, accounts for any passage of
|
|
* time (in case one or more epochs have passed with no samples),
|
|
* and clears the sample count for the new epoch. */
|
|
inline void update(signed_value_type delta, unsigned ratenum = 0);
|
|
|
|
/** @brief Unparse the current average into a String.
|
|
* @param ratenum rate index (0 <= ratenum < rate_count)
|
|
* @note The returned value is unscaled, but may contain a fractional
|
|
* part.
|
|
* @note unparse_rate() does not check the current epoch.
|
|
* If an epoch might have passed since the last update(), you
|
|
* should call update(0, @a ratenum) before calling this
|
|
* function. */
|
|
String unparse_rate(unsigned ratenum = 0) const;
|
|
|
|
private:
|
|
|
|
unsigned _current_epoch;
|
|
value_type _current[P::rate_count];
|
|
DirectEWMAX<P> _avg[P::rate_count];
|
|
|
|
inline void update_time(unsigned now);
|
|
|
|
};
|
|
|
|
/** @class RateEWMAXParameters include/click/ewma.hh <click/ewma.hh>
|
|
* @brief Parameters for a RateEWMA with constant scaling factor
|
|
* and alpha, one rate count, and epochs of jiffies.
|
|
*
|
|
* The RateEWMAXParameters template class is used as a template argument
|
|
* to RateEWMAX. It defines a EWMA with fixed constant scaling factor and
|
|
* alpha and one rate count. The EWMA uses jiffies as epochs. Template
|
|
* parameters are as for DirectEWMAXParameters.
|
|
*
|
|
* Example: <code>RateEWMAX@<RateEWMAXParameters@<4, 10, unsigned, int@>
|
|
* @></code> defines a rate EWMA with user-settable alpha (stability shift)
|
|
* initially equal to 1/16, scaling factor 10, and value type unsigned.
|
|
*/
|
|
template <unsigned STABILITY, unsigned SCALE, typename T = unsigned, typename U = int>
|
|
class RateEWMAXParameters : public FixedEWMAXParameters<STABILITY, SCALE, T, U> { public:
|
|
enum {
|
|
rate_count = 1
|
|
};
|
|
|
|
/** @brief Return the current epoch number.
|
|
* @note RateEWMAXParameters measures epochs in jiffies. */
|
|
static unsigned epoch() {
|
|
return click_jiffies();
|
|
}
|
|
|
|
/** @brief Return the number of epochs (jiffies) per second. */
|
|
static unsigned epoch_frequency() {
|
|
return CLICK_HZ;
|
|
}
|
|
};
|
|
|
|
/** @brief A RateEWMAX with stability shift 4 (alpha 1/16), scaling factor 10
|
|
* (10 bits of fraction), one rate, and underlying type <code>unsigned</code>
|
|
* that measures epochs in jiffies. */
|
|
typedef RateEWMAX<RateEWMAXParameters<4, 10> > RateEWMA;
|
|
|
|
|
|
template <typename P>
|
|
inline void
|
|
RateEWMAX<P>::update_time(unsigned now)
|
|
{
|
|
unsigned jj = _current_epoch;
|
|
if (now != jj) {
|
|
for (unsigned i = 0; i < P::rate_count; i++) {
|
|
// adjust the average rate using the last measured packets
|
|
_avg[i].update(_current[i]);
|
|
|
|
// adjust for time w/ no packets
|
|
if (jj + 1 != now)
|
|
_avg[i].update_n(0, now - jj - 1);
|
|
_current[i] = 0;
|
|
}
|
|
_current_epoch = now;
|
|
}
|
|
}
|
|
|
|
template <typename P>
|
|
inline void
|
|
RateEWMAX<P>::update(signed_value_type delta, unsigned ratenum)
|
|
{
|
|
update_time(P::epoch());
|
|
_current[ratenum] += delta;
|
|
}
|
|
|
|
template <typename P>
|
|
inline int
|
|
RateEWMAX<P>::rate(unsigned ratenum) const
|
|
{
|
|
return (scaled_average(ratenum) * P::epoch_frequency()) >> _avg[ratenum].scale();
|
|
}
|
|
|
|
template <typename P>
|
|
inline String
|
|
RateEWMAX<P>::unparse_rate(unsigned ratenum) const
|
|
{
|
|
return cp_unparse_real2(scaled_average(ratenum) * P::epoch_frequency(), _avg[ratenum].scale());
|
|
}
|
|
|
|
CLICK_ENDDECLS
|
|
#endif
|