openflow build environment setup
This commit is contained in:
240
openflow/include/click/gaprate.hh
Normal file
240
openflow/include/click/gaprate.hh
Normal file
@ -0,0 +1,240 @@
|
||||
// -*- c-basic-offset: 4; related-file-name: "../../lib/gaprate.cc" -*-
|
||||
#ifndef CLICK_GAPRATE_HH
|
||||
#define CLICK_GAPRATE_HH
|
||||
#include <click/timestamp.hh>
|
||||
CLICK_DECLS
|
||||
class ErrorHandler;
|
||||
|
||||
/** @file <click/gaprate.hh>
|
||||
* @brief A Click helper class for implementing a uniform rate.
|
||||
*/
|
||||
|
||||
/** @class GapRate include/click/gaprate.hh <click/gaprate.hh>
|
||||
* @brief A helper class for implementing a uniform rate.
|
||||
*
|
||||
* The GapRate class helps its user implement a process with a uniform rate:
|
||||
* a process in which one user event happens every T seconds. GapRate is
|
||||
* designed to efficiently model high rates. (Contrast this with Timer,
|
||||
* which can serve a similar function at low rates.)
|
||||
*
|
||||
* GapRate is not a great choice for limiting the rates of external
|
||||
* processes. See TokenBucketX, a token bucket rate limiter.
|
||||
*
|
||||
* GapRate models an underlying "true" rated process with the correct rate.
|
||||
* It also keeps a counter, maintained by its user via the update() method,
|
||||
* that measures the progress of the user's rated process. The
|
||||
* needs_update() method compares this counter with its expected value, which
|
||||
* is determined by the true rated process. If the user's rated process is
|
||||
* running behind, then needs_update() returns true; the user should trigger
|
||||
* an event and call the update() method. If the user's rated process is
|
||||
* just right or is running faster than the true process, then needs_update()
|
||||
* returns false; the user should <em>not</em> trigger an event.
|
||||
*
|
||||
* Creating a non-bursty rate can be expensive and difficult. GapRate
|
||||
* attempts to create a non-bursty rate using timestamps and some interesting
|
||||
* microsecond-based arithmetic. External factors can cause scheduling
|
||||
* hiccups where GapRate is not called as much as expected. GapRate
|
||||
* compensates for hiccups: the user's rated process may fall up to a full
|
||||
* second behind the true rated process, then catch up in a burst. More than
|
||||
* one second's worth of lag is ignored.
|
||||
*
|
||||
* The maximum rate GapRate can implement is MAX_RATE events per second.
|
||||
*
|
||||
* @sa TokenBucketX, Timer
|
||||
*/
|
||||
class GapRate { public:
|
||||
|
||||
/** @brief Construct a GapRate object with initial rate 0. */
|
||||
inline GapRate();
|
||||
|
||||
/** @brief Construct a GapRate object with initial rate @a r.
|
||||
* @param r initial rate (events per second) */
|
||||
inline GapRate(unsigned r);
|
||||
|
||||
/** @brief Return the current rate. */
|
||||
inline unsigned rate() const;
|
||||
|
||||
/** @brief Set the current rate to @a r.
|
||||
* @param r desired rate (events per second)
|
||||
*
|
||||
* Rates larger than MAX_RATE are reduced to MAX_RATE. Also performs the
|
||||
* equivalent of a reset() to flush old state. */
|
||||
inline void set_rate(unsigned r);
|
||||
|
||||
/** @brief Set the current rate to @a r.
|
||||
* @param r desired rate (events per second)
|
||||
* @param errh error handler
|
||||
*
|
||||
* Acts like set_rate(@a r), except that an warning is reported to @a errh
|
||||
* if @a r is larger than MAX_RATE. */
|
||||
void set_rate(unsigned r, ErrorHandler *errh);
|
||||
|
||||
|
||||
/** @brief Returns whether the user's rate is behind the true rate.
|
||||
* @param ts current timestamp
|
||||
*
|
||||
* Returns true iff the user's rate is currently behind the true rate,
|
||||
* meaning the user should cause an event and call update(). */
|
||||
inline bool need_update(const Timestamp &ts);
|
||||
|
||||
/** @brief Returns a time when the user's rate will be behind the true rate.
|
||||
* @pre need_update() has been called at least once.
|
||||
* @return If the rate is 0, or need_update() has not been called,
|
||||
* returns Timestamp(). If the user's rate is already behind the true
|
||||
* rate, returns a time no greater than the argument passed to the last
|
||||
* need_update(). Otherwise, returns a time in the future when
|
||||
* need_update() will return true.
|
||||
*/
|
||||
inline Timestamp expiry() const;
|
||||
|
||||
/** @brief Increment the user event counter.
|
||||
*
|
||||
* Call this function when causing a user event. */
|
||||
inline void update();
|
||||
|
||||
/** @brief Increment the user event counter by @a delta.
|
||||
* @param delta number of user events
|
||||
*
|
||||
* @note This may be faster than calling update() @a delta times.
|
||||
* Furthermore, @a delta can be negative. */
|
||||
inline void update_with(int delta);
|
||||
|
||||
/** @brief Resets the true rate counter.
|
||||
*
|
||||
* This function flushes any old information about the true rate counter
|
||||
* and its relationship to the user's rate counter. */
|
||||
inline void reset();
|
||||
|
||||
|
||||
enum { UGAP_SHIFT = 12 };
|
||||
enum { MAX_RATE = 1000000U << UGAP_SHIFT };
|
||||
|
||||
private:
|
||||
|
||||
unsigned _ugap; // (1000000 << UGAP_SHIFT) / _rate
|
||||
int _sec_count; // number of updates this second so far
|
||||
Timestamp::seconds_type _tv_sec; // current second
|
||||
unsigned _rate; // desired rate
|
||||
#if DEBUG_GAPRATE
|
||||
Timestamp _last;
|
||||
#endif
|
||||
|
||||
inline void initialize_rate(unsigned rate);
|
||||
|
||||
};
|
||||
|
||||
/** @brief Reset the underlying rated process. */
|
||||
inline void
|
||||
GapRate::reset()
|
||||
{
|
||||
_tv_sec = -1;
|
||||
#if DEBUG_GAPRATE
|
||||
_last.set_sec(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void
|
||||
GapRate::initialize_rate(unsigned r)
|
||||
{
|
||||
_rate = r;
|
||||
_ugap = (r == 0 ? MAX_RATE + 1 : MAX_RATE / r);
|
||||
#if DEBUG_GAPRATE
|
||||
click_chatter("ugap: %u", _ugap);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void
|
||||
GapRate::set_rate(unsigned r)
|
||||
{
|
||||
if (r > MAX_RATE)
|
||||
r = MAX_RATE;
|
||||
if (_rate != r) {
|
||||
initialize_rate(r);
|
||||
if (_tv_sec >= 0 && r != 0) {
|
||||
Timestamp now = Timestamp::now();
|
||||
_sec_count = (now.usec() << UGAP_SHIFT) / _ugap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
GapRate::GapRate()
|
||||
{
|
||||
initialize_rate(0);
|
||||
reset();
|
||||
}
|
||||
|
||||
inline
|
||||
GapRate::GapRate(unsigned r)
|
||||
: _rate(0)
|
||||
{
|
||||
initialize_rate(r);
|
||||
reset();
|
||||
}
|
||||
|
||||
inline unsigned
|
||||
GapRate::rate() const
|
||||
{
|
||||
return _rate;
|
||||
}
|
||||
|
||||
inline bool
|
||||
GapRate::need_update(const Timestamp &now)
|
||||
{
|
||||
// this is an approximation of:
|
||||
// unsigned need = (unsigned) ((now.usec() / 1000000.0) * _rate)
|
||||
unsigned need = (now.usec() << UGAP_SHIFT) / _ugap;
|
||||
|
||||
if (_tv_sec < 0) {
|
||||
// 27.Feb.2005: often OK to send a packet after reset unless rate is
|
||||
// 0 -- requested by Bart Braem
|
||||
// check include/click/gaprate.hh (1.2)
|
||||
_tv_sec = now.sec();
|
||||
_sec_count = need + ((now.usec() << UGAP_SHIFT) - (need * _ugap) > _ugap / 2);
|
||||
} else if (now.sec() > _tv_sec) {
|
||||
_tv_sec = now.sec();
|
||||
if (_sec_count > 0)
|
||||
_sec_count -= _rate;
|
||||
}
|
||||
|
||||
#if DEBUG_GAPRATE
|
||||
click_chatter("%p{timestamp} -> %u @ %u [%d]", &now, need, _sec_count, (int)need >= _sec_count);
|
||||
#endif
|
||||
return ((int)need >= _sec_count);
|
||||
}
|
||||
|
||||
inline void
|
||||
GapRate::update()
|
||||
{
|
||||
_sec_count++;
|
||||
}
|
||||
|
||||
inline void
|
||||
GapRate::update_with(int delta)
|
||||
{
|
||||
_sec_count += delta;
|
||||
}
|
||||
|
||||
inline Timestamp
|
||||
GapRate::expiry() const
|
||||
{
|
||||
if (_tv_sec < 0 || _rate == 0)
|
||||
return Timestamp();
|
||||
else if (_sec_count < 0)
|
||||
return Timestamp(_tv_sec, 0);
|
||||
else {
|
||||
Timestamp::seconds_type sec = _tv_sec;
|
||||
int count = _sec_count;
|
||||
if ((unsigned) count >= _rate) {
|
||||
sec += count / _rate;
|
||||
count = count % _rate;
|
||||
}
|
||||
|
||||
// uint32_t usec = (int) (count * 1000000.0 / _rate)
|
||||
uint32_t usec = (count * _ugap) >> UGAP_SHIFT;
|
||||
return Timestamp::make_usec(sec, usec);
|
||||
}
|
||||
}
|
||||
|
||||
CLICK_ENDDECLS
|
||||
#endif
|
||||
Reference in New Issue
Block a user