📄 timestamp.hh
字号:
// -*- c-basic-offset: 4; related-file-name: "../../lib/timestamp.cc" -*-#ifndef CLICK_TIMESTAMP_HH#define CLICK_TIMESTAMP_HH#include <click/glue.hh>#if !CLICK_LINUXMODULE && !CLICK_BSDMODULE# include <math.h>#endifCLICK_DECLSclass String;// Timestamp has three possible internal representations, selected by #defines.// * TIMESTAMP_REP_FLAT64: a 64-bit integer number of nanoseconds// * TIMESTAMP_REP_BIG_ENDIAN: 32 bits of seconds plus 32 bits of subseconds// * TIMESTAMP_REP_LITTLE_ENDIAN: 32 bits of subseconds plus 32 bits of seconds//// Rationale: The linuxmodule driver must select the same representation as// Linux's sk_buff tstamp member, which may use any of these representations.// (Linuxmodule Packet objects are equivalent to sk_buffs, and// Packet::timestamp_anno() maps to sk_buff::tstamp. We want to avoid// conversion expense when accessing timestamp_anno(). More seriously, it is// very convenient to treat timestamp_anno() as a modifiable reference.)#if !TIMESTAMP_REP_FLAT64 && !TIMESTAMP_REP_BIG_ENDIAN && !TIMESTAMP_REP_LITTLE_ENDIAN# if CLICK_LINUXMODULE# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)# define TIMESTAMP_REP_BIG_ENDIAN 1# elif BITS_PER_LONG == 64 || defined(CONFIG_KTIME_SCALAR)# define TIMESTAMP_REP_FLAT64 1# elif defined(__BIG_ENDIAN)# define TIMESTAMP_REP_BIG_ENDIAN 1# else# define TIMESTAMP_REP_LITTLE_ENDIAN 1# endif# elif HAVE_INT64_TYPES && SIZEOF_LONG == 8# define TIMESTAMP_REP_FLAT64 1# elif HAVE_INT64_TYPES && CLICK_BYTE_ORDER == CLICK_LITTLE_ENDIAN# define TIMESTAMP_REP_LITTLE_ENDIAN 1# else# define TIMESTAMP_REP_BIG_ENDIAN 1# endif#endif// Timestamp can use microsecond or nanosecond precision. Nanosecond// precision is used if TIMESTAMP_NANOSEC == 1. In the Linux kernel, we// choose what Linux uses for sk_buff::tstamp. Elsewhere, we default to// microsecond precision (XXX); "./configure --enable-nanotimestamp" selects// nanosecond precision.#ifndef TIMESTAMP_NANOSEC# if CLICK_LINUXMODULE# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)# define TIMESTAMP_NANOSEC 1# endif# endif#endif// Define TIMESTAMP_MATH_FLAT64 if despite a seconds-and-subseconds// representation, 64-bit arithmetic should be used for timestamp addition,// subtraction, and comparisons. This can be faster than operating on two// separate 32-bit integers.#if HAVE_INT64_TYPES && !TIMESTAMP_REP_FLAT64# if (TIMESTAMP_REP_BIG_ENDIAN && CLICK_BYTE_ORDER == CLICK_BIG_ENDIAN) \ || (TIMESTAMP_REP_LITTLE_ENDIAN && CLICK_BYTE_ORDER == CLICK_LITTLE_ENDIAN)# define TIMESTAMP_MATH_FLAT64 1# endif#endif// If a Timestamp's internal representation is identical to struct timespec// or struct timeval, define TIMESTAMP_PUNS_TIMESPEC or TIMESTAMP_PUNS_TIMEVAL.#if TIMESTAMP_REP_BIG_ENDIAN# if !TIMESTAMP_NANOSEC && SIZEOF_STRUCT_TIMEVAL == 8# define TIMESTAMP_PUNS_TIMEVAL 1# elif TIMESTAMP_NANOSEC && HAVE_STRUCT_TIMESPEC && SIZEOF_STRUCT_TIMESPEC == 8# define TIMESTAMP_PUNS_TIMESPEC 1# endif#endif// Timestamp::value_type is the type of arguments to, for example,// Timestamp::make_msec(), and should be as large as possible. This is// int64_t at userlevel. In the linuxmodule driver, int64_t can only be used// if the relevant Linux provides 64-bit divide, which is do_div.// TIMESTAMP_VALUE_INT64 is defined to 1 if Timestamp::value_type is int64_t.#if !defined(TIMESTAMP_VALUE_INT64) && HAVE_INT64_TYPES# if CLICK_LINUXMODULE && defined(do_div)# define TIMESTAMP_VALUE_INT64 1# elif !CLICK_LINUXMODULE && !CLICK_BSDMODULE# define TIMESTAMP_VALUE_INT64 1# endif#endif// PRITIMESTAMP is a printf format string for Timestamps. The corresponding// printf argument list is Timestamp::sec() and Timestamp::subsec(), in that// order.#if TIMESTAMP_NANOSEC# define PRITIMESTAMP "%d.%09d"#else# define PRITIMESTAMP "%d.%06d"#endifclass Timestamp { public: /** @brief Type represents a number of seconds. */ typedef int32_t seconds_type; /** @brief Return type for msecval(), usecval(), and nsecval(). */#if TIMESTAMP_VALUE_INT64 typedef int64_t value_type;#else typedef int32_t value_type;#endif enum { max_seconds = (seconds_type) 2147483647U, min_seconds = (seconds_type) -2147483648U, nsec_per_sec = 1000000000, nsec_per_msec = 1000000, nsec_per_usec = 1000, usec_per_sec = 1000000, usec_per_msec = 1000, msec_per_sec = 1000,#if TIMESTAMP_NANOSEC subsec_per_sec = nsec_per_sec, /**< Number of subseconds in a second. Can be 1000000 or 1000000000, depending on how Click is compiled. */#else subsec_per_sec = usec_per_sec,#endif subsec_per_msec = subsec_per_sec / msec_per_sec, subsec_per_usec = subsec_per_sec / usec_per_sec }; enum { NSUBSEC = subsec_per_sec }; struct uninitialized_t { }; /** @brief Construct a zero-valued Timestamp. */ inline Timestamp() { assign(0, 0); } /** @brief Construct a Timestamp of @a sec seconds plus @a subsec * subseconds. * @param sec number of seconds * @param subsec number of subseconds (defaults to 0) * * The @a subsec parameter must be between 0 and subsec_per_sec - 1, and * the @a sec parameter must be between @link Timestamp::min_seconds * min_seconds @endlink and @link Timestamp::max_seconds max_seconds * @endlink. Errors are not necessarily checked. */ inline Timestamp(long sec, uint32_t subsec = 0) { assign(sec, subsec); } /** @overload */ inline Timestamp(int sec, uint32_t subsec = 0) { assign(sec, subsec); } /** @overload */ inline Timestamp(unsigned long sec, uint32_t subsec = 0) { assign(sec, subsec); } /** @overload */ inline Timestamp(unsigned sec, uint32_t subsec = 0) { assign(sec, subsec); }#if HAVE_FLOAT_TYPES inline Timestamp(double);#endif inline Timestamp(const struct timeval &tv);#if HAVE_STRUCT_TIMESPEC inline Timestamp(const struct timespec &ts);#endif /** @brief Construct an uninitialized timestamp. */ inline Timestamp(const uninitialized_t &unused) { (void) unused; } typedef seconds_type (Timestamp::*unspecified_bool_type)() const; inline operator unspecified_bool_type() const; inline seconds_type sec() const; inline uint32_t subsec() const; inline uint32_t msec() const; inline uint32_t usec() const; inline uint32_t nsec() const; inline void set_sec(seconds_type sec); inline void set_subsec(uint32_t subsec); inline seconds_type msec1() const CLICK_DEPRECATED; inline seconds_type usec1() const CLICK_DEPRECATED; inline seconds_type nsec1() const CLICK_DEPRECATED;#if TIMESTAMP_PUNS_TIMEVAL inline const struct timeval &timeval() const;#else inline struct timeval timeval() const;#endif#if HAVE_STRUCT_TIMESPEC# if TIMESTAMP_PUNS_TIMESPEC inline const struct timespec ×pec() const;# else inline struct timespec timespec() const;# endif#endif#if HAVE_FLOAT_TYPES inline double doubleval() const;#endif /** @brief Return this timestamp's interval length in milliseconds. */ inline value_type msecval() const {#if TIMESTAMP_REP_FLAT64 return value_div(_t.x, subsec_per_sec / msec_per_sec);#else return (value_type) _t.sec * msec_per_sec + subsec_to_msec(_t.subsec);#endif } /** @brief Return this timestamp's interval length in microseconds. */ inline value_type usecval() const {#if TIMESTAMP_REP_FLAT64 return value_div(_t.x, subsec_per_sec / usec_per_sec);#else return (value_type) _t.sec * usec_per_sec + subsec_to_usec(_t.subsec);#endif } /** @brief Return this timestamp's interval length in nanoseconds. */ inline value_type nsecval() const {#if TIMESTAMP_REP_FLAT64 return _t.x * (nsec_per_sec / subsec_per_sec);#else return (value_type) _t.sec * nsec_per_sec + subsec_to_nsec(_t.subsec);#endif }#if !CLICK_TOOL /** @brief Return a timestamp representing @a jiffies. */ static inline Timestamp make_jiffies(click_jiffies_t jiffies); /** @brief Return the number of jiffies represented by this timestamp. */ inline click_jiffies_t jiffies() const;#endif /** @brief Return a timestamp representing @a sec seconds. */ static inline Timestamp make_sec(seconds_type sec) { return Timestamp(sec, 0); } /** @brief Return a timestamp representing @a sec seconds plus @a msec * milliseconds. * @pre 0 <= @a msec < 1000 */ static inline Timestamp make_msec(seconds_type sec, uint32_t msec) { return Timestamp(sec, msec_to_subsec(msec)); } /** @brief Return a timestamp representing @a msec milliseconds. */ static inline Timestamp make_msec(value_type msec) { Timestamp t = Timestamp::uninitialized_t();#if TIMESTAMP_REP_FLAT64 t._t.x = msec * (subsec_per_sec / msec_per_sec);#else value_div_mod(t._t.sec, t._t.subsec, msec, msec_per_sec); t._t.subsec *= subsec_per_sec / msec_per_sec;#endif return t; } /** @brief Return a timestamp representing @a sec seconds plus @a usec * microseconds. * @pre 0 <= @a usec < 1000000 */ static inline Timestamp make_usec(seconds_type sec, uint32_t usec) { return Timestamp(sec, usec_to_subsec(usec)); } /** @brief Return a timestamp representing @a usec microseconds. */ static inline Timestamp make_usec(value_type usec) { Timestamp t = Timestamp::uninitialized_t();#if TIMESTAMP_REP_FLAT64 t._t.x = usec * (subsec_per_sec / usec_per_sec);#else value_div_mod(t._t.sec, t._t.subsec, usec, usec_per_sec); t._t.subsec *= subsec_per_sec / usec_per_sec;#endif return t; } /** @brief Return a timestamp representing @a sec seconds plus @a nsec * nanoseconds. * @pre 0 <= @a nsec < 1000000000 */ static inline Timestamp make_nsec(seconds_type sec, uint32_t nsec) { return Timestamp(sec, nsec_to_subsec(nsec)); } /** @brief Return a timestamp representing @a nsec nanoseconds. */ static inline Timestamp make_nsec(value_type nsec) { Timestamp t = Timestamp::uninitialized_t();#if TIMESTAMP_REP_FLAT64 t._t.x = value_div(nsec, nsec_per_sec / subsec_per_sec);#else value_div_mod(t._t.sec, t._t.subsec, nsec, nsec_per_sec); t._t.subsec /= nsec_per_sec / subsec_per_sec;#endif return t; } static inline Timestamp now(); /** @brief Return the smallest nonzero timestamp, Timestamp(0, 1). */ static inline Timestamp epsilon() { return Timestamp(0, 1); } /** Set this timestamp to a seconds-and-subseconds value. * * @sa Timestamp(int, int) */ inline void assign(seconds_type sec, uint32_t subsec = 0) {#if TIMESTAMP_REP_FLAT64 _t.x = (int64_t) sec * subsec_per_sec + subsec;#else _t.sec = sec; _t.subsec = subsec;#endif } /** Assign this timestamp to a seconds-and-microseconds value. */ inline void assign_usec(seconds_type sec, uint32_t usec) { assign(sec, usec_to_subsec(usec)); } /** Assign this timestamp to a seconds-and-nanoseconds value. */ inline void assign_nsec(seconds_type sec, uint32_t nsec) { assign(sec, nsec_to_subsec(nsec)); } /** Assign this timestamp to a seconds-and-subseconds value. * @deprecated Use assign() instead. */ inline void set(seconds_type sec, uint32_t subsec = 0) CLICK_DEPRECATED; /** Assign this timestamp to a seconds-and-microseconds value. * @deprecated Use assign_usec() instead. */ inline void set_usec(seconds_type sec, uint32_t usec) CLICK_DEPRECATED; /** Assign this timestamp to a seconds-and-nanoseconds value. * @deprecated Use assign_nsec() instead. */ inline void set_nsec(seconds_type sec, uint32_t nsec) CLICK_DEPRECATED; inline void set_now();#if !CLICK_LINUXMODULE && !CLICK_BSDMODULE int set_timeval_ioctl(int fd, int ioctl_selector);#endif String unparse() const; String unparse_interval() const; /** @brief Convert milliseconds to subseconds. * * Subseconds are either microseconds or nanoseconds, depending on * configuration options and driver choice. * @sa usec_to_subsec(), nsec_to_subsec(), subsec_to_msec(), * subsec_to_usec(), subsec_to_nsec() */ inline static uint32_t msec_to_subsec(uint32_t msec) { return msec * (subsec_per_sec / msec_per_sec); } /** @brief Convert microseconds to subseconds. */ inline static uint32_t usec_to_subsec(uint32_t usec) { return usec * (subsec_per_sec / usec_per_sec); } /** @brief Convert nanoseconds to subseconds. */ inline static uint32_t nsec_to_subsec(uint32_t nsec) { return nsec / (nsec_per_sec / subsec_per_sec); } /** @brief Convert subseconds to milliseconds. */ inline static uint32_t subsec_to_msec(uint32_t subsec) { return subsec / (subsec_per_sec / msec_per_sec); } /** @brief Convert subseconds to microseconds. */ inline static uint32_t subsec_to_usec(uint32_t subsec) { return subsec / (subsec_per_sec / usec_per_sec); } /** @brief Convert subseconds to nanoseconds. */ inline static uint32_t subsec_to_nsec(uint32_t subsec) { return subsec * (nsec_per_sec / subsec_per_sec); } private: union {#if TIMESTAMP_REP_FLAT64 || TIMESTAMP_MATH_FLAT64 int64_t x;#endif#if TIMESTAMP_REP_BIG_ENDIAN struct { int32_t sec; int32_t subsec; };#elif TIMESTAMP_REP_LITTLE_ENDIAN struct { int32_t subsec; int32_t sec; };#endif#if CLICK_LINUXMODULE# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ktime_t ktime;# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) skb_timeval skbtime;# else timeval tv;# endif#endif } _t; inline void add_fix() {#if TIMESTAMP_REP_FLAT64 /* no fix necessary */#elif TIMESTAMP_MATH_FLAT64 if (_t.subsec >= subsec_per_sec) _t.x += (uint32_t) -subsec_per_sec;#else if (_t.subsec >= subsec_per_sec) _t.sec++, _t.subsec -= subsec_per_sec;#endif } inline void sub_fix() {#if TIMESTAMP_REP_FLAT64 /* no fix necessary */#elif TIMESTAMP_MATH_FLAT64 if (_t.subsec < 0) _t.subsec += subsec_per_sec;#else if (_t.subsec < 0) _t.sec--, _t.subsec += subsec_per_sec;#endif } static inline value_type value_div(value_type a, uint32_t b) {#if CLICK_LINUXMODULE && TIMESTAMP_VALUE_INT64 && BITS_PER_LONG < 64 do_div(a, b); return a;#else return a / b;#endif } static inline void value_div_mod(int32_t &div, int32_t &rem, value_type a, uint32_t b) {#if CLICK_LINUXMODULE && TIMESTAMP_VALUE_INT64 && BITS_PER_LONG < 64 if (unlikely(a < 0)) { a = -a - 1; rem = do_div(a, b); div = -a - 1; if (rem) rem = b - rem; } else { rem = do_div(a, b); div = a; }#else // This arithmetic is about twice as fast on my laptop as the // alternative "div = a / b; // mod = a - (value_type) div * b; // if (mod < 0) div--, mod += b;", // and 3-4x faster than "div = a / b; // mod = a % b; // if (mod < 0) div--, mod += b;". if (unlikely(a < 0)) div = -((-a - 1) / b) - 1; else div = a / b; rem = a - (value_type) div * b;#endif } friend inline bool operator==(const Timestamp &a, const Timestamp &b); friend inline bool operator<(const Timestamp &a, const Timestamp &b); friend inline Timestamp operator-(const Timestamp &b); friend inline Timestamp &operator+=(Timestamp &a, const Timestamp &b); friend inline Timestamp &operator-=(Timestamp &a, const Timestamp &b);};/** @brief Create a Timestamp measuring @a tv. @param tv timeval structure */inlineTimestamp::Timestamp(const struct timeval& tv){ assign(tv.tv_sec, usec_to_subsec(tv.tv_usec));}#if HAVE_STRUCT_TIMESPEC/** @brief Create a Timestamp measuring @a ts. @param ts timespec structure */inlineTimestamp::Timestamp(const struct timespec& ts){ assign(ts.tv_sec, nsec_to_subsec(ts.tv_nsec));}#endif/** @brief Return true iff this timestamp is not zero-valued. */inlineTimestamp::operator unspecified_bool_type() const{#if TIMESTAMP_REP_FLAT64 || TIMESTAMP_MATH_FLAT64 return _t.x ? &Timestamp::sec : 0;#else return _t.sec || _t.subsec ? &Timestamp::sec : 0;#endif}/** @brief Set this timestamp to the current time.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -