📄 gaprate.hh
字号:
// -*- c-basic-offset: 4; related-file-name: "../../lib/gaprate.cc" -*-#ifndef CLICK_GAPRATE_HH#define CLICK_GAPRATE_HH#include <click/timestamp.hh>CLICK_DECLSclass 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 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 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};/** @brief Reset the underlying rated process. */inline voidGapRate::reset(){ _tv_sec = -1;#if DEBUG_GAPRATE _last.set_sec(0);#endif}inline voidGapRate::set_rate(unsigned r){ if (r > MAX_RATE) r = MAX_RATE; _rate = r; _ugap = (r == 0 ? MAX_RATE + 1 : MAX_RATE / r);#if DEBUG_GAPRATE click_chatter("ugap: %u", _ugap);#endif reset();}inlineGapRate::GapRate(){ set_rate(0);}inlineGapRate::GapRate(unsigned r){ set_rate(r);}inline unsignedGapRate::rate() const{ return _rate;}inline boolGapRate::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("%{timestamp} -> %u @ %u [%d]", &now, need, _sec_count, (int)need >= _sec_count);#endif return ((int)need >= _sec_count);}inline voidGapRate::update(){ _sec_count++;}inline voidGapRate::update_with(int delta){ _sec_count += delta;}inline TimestampGapRate::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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -