Files
NE_YuR/openflow/include/click/timestamp.hh

1541 lines
43 KiB
C++

// -*- c-basic-offset: 4; related-file-name: "../../lib/timestamp.cc" -*-
#ifndef CLICK_TIMESTAMP_HH
#define CLICK_TIMESTAMP_HH
#include <click/glue.hh>
#include <click/type_traits.hh>
#include <click/integers.hh>
#if !CLICK_LINUXMODULE && !CLICK_BSDMODULE
# include <math.h>
#endif
CLICK_DECLS
class String;
class Timestamp;
Timestamp operator+(Timestamp, const Timestamp &);
// 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"
#endif
// TIMESTAMP_WARPABLE is defined if this Timestamp implementation supports
// timewarping.
#if !CLICK_LINUXMODULE && !CLICK_BSDMODULE && !CLICK_NS
# define TIMESTAMP_WARPABLE 1
#endif
class 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,
/**< Maximum number of seconds representable in a
Timestamp. */
min_seconds = (seconds_type) -2147483648U
/**< Minimum number of seconds representable in a
Timestamp. */
};
enum {
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
#if CLICK_NS
, schedule_granularity = usec_per_sec
#endif
};
enum {
NSUBSEC = subsec_per_sec
};
typedef uninitialized_type uninitialized_t;
union rep_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. */
explicit inline Timestamp(long sec, uint32_t subsec = 0) {
assign(sec, subsec);
}
/** @overload */
explicit inline Timestamp(int sec, uint32_t subsec = 0) {
assign(sec, subsec);
}
/** @overload */
explicit inline Timestamp(unsigned long sec, uint32_t subsec = 0) {
assign(sec, subsec);
}
/** @overload */
explicit inline Timestamp(unsigned sec, uint32_t subsec = 0) {
assign(sec, subsec);
}
#if HAVE_FLOAT_TYPES
explicit inline Timestamp(double);
#endif
inline Timestamp(const struct timeval &tv);
#if HAVE_STRUCT_TIMESPEC
inline Timestamp(const struct timespec &ts);
#endif
/** @brief Construct a Timestamp from its internal representation. */
inline Timestamp(const rep_t &rep)
: _t(rep) {
}
/** @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;
/** @brief Test if this Timestamp is negative (< Timestamp(0, 0)). */
inline bool is_negative() const {
#if TIMESTAMP_REP_FLAT64 || TIMESTAMP_MATH_FLAT64
return _t.x < 0;
#else
return sec() < 0;
#endif
}
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;
inline const struct timeval &timeval_ceil() const;
#else
inline struct timeval timeval() const;
inline struct timeval timeval_ceil() const;
#endif
#if HAVE_STRUCT_TIMESPEC
# if TIMESTAMP_PUNS_TIMESPEC
inline const struct timespec &timespec() 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
}
/** @brief Return the next millisecond-valued timestamp no smaller than *this. */
inline Timestamp msec_ceil() const {
uint32_t x = subsec() % subsec_per_msec;
return (x ? *this + Timestamp(0, subsec_per_msec - x) : *this);
}
/** @brief Return the next microsecond-valued timestamp no smaller than *this. */
inline Timestamp usec_ceil() const {
#if TIMESTAMP_NANOSEC
uint32_t x = subsec() % subsec_per_usec;
return (x ? *this + Timestamp(0, subsec_per_usec - x) : *this);
#else
return *this;
#endif
}
/** @brief Return the next nanosecond-valued timestamp no smaller than *this. */
inline Timestamp nsec_ceil() const {
return *this;
}
#if !CLICK_TOOL
/** @brief Return a timestamp representing an interval of @a jiffies. */
static inline Timestamp make_jiffies(click_jiffies_t jiffies);
/** @overload */
static inline Timestamp make_jiffies(click_jiffies_difference_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;
}
/** @brief Return the smallest nonzero timestamp, Timestamp(0, 1). */
static inline Timestamp epsilon() {
return Timestamp(0, 1);
}
/** @brief Clear this timestamp. */
inline void clear() {
assign(0, 0);
}
/** 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));
}
/** @cond never */
/** 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;
/** @brief Deprecated synonym for assign_now().
* @deprecated Use Timestamp::assign_now() instead. */
inline void set_now() CLICK_DEPRECATED;
/** @endcond never */
#if !CLICK_LINUXMODULE && !CLICK_BSDMODULE && !CLICK_MINIOS
int set_timeval_ioctl(int fd, int ioctl_selector);
#endif
/** @brief Return the current system time.
*
* System time is measured in seconds since January 1, 1970 GMT.
* Produces the most precise timestamp available.
*
* @note System time can jump forwards or backwards as a result of user
* actions. For a clock that never moves backwards, see now_steady().
* @sa recent(), assign_now(), now_steady() */
static inline Timestamp now();
/** @brief Set this timestamp to the current system time.
*
* Like "*this = Timestamp::now()".
* @sa now(), assign_recent() */
inline void assign_now();
/** @brief Return a recent system time.
*
* The Timestamp::now() function calculates the current system time, which
* is relatively expensive. Timestamp::recent() can be faster, but is
* less precise: it returns a cached copy of a recent system time.
* @sa now(), assign_recent() */
static inline Timestamp recent();
/** @brief Set this timestamp to a recent system time.
*
* Like "*this = Timestamp::recent()".
* @sa recent(), assign_now() */
inline void assign_recent();
/** @brief Return the current steady-clock time.
*
* The steady clock, often called a monotonic clock, is a system clock
* that never moves backwards. Steady-clock time is measured in seconds
* since an undefined start point (often related to the most recent boot).
* Produces the most precise timestamp available.
*
* @note Steady-clock times and system times are incomparable, since they
* have different start points.
*
* @sa recent_steady(), assign_now_steady() */
static inline Timestamp now_steady();
/** @brief Set this timestamp to the current steady-clock time.
*
* Like "*this = Timestamp::now_steady()".
* @sa now_steady() */
inline void assign_now_steady();
/** @brief Return a recent steady-clock time.
*
* The Timestamp::now_steady() function calculates the current
* steady-clock time, which is relatively expensive.
* Timestamp::recent_steady() can be faster, but is less precise: it
* returns a cached copy of a recent steady-clock time.
* @sa now_steady(), assign_recent_steady() */
static inline Timestamp recent_steady();
/** @brief Set this timestamp to a recent steady-clock time.
*
* Like "*this = Timestamp::recent_steady()".
* @sa recent_steady(), assign_now_steady() */
inline void assign_recent_steady();
/** @brief Unparse this timestamp into a String.
*
* Returns a string formatted like "10.000000", with at least six
* subsecond digits. (Nanosecond-precision timestamps where the number of
* nanoseconds is not evenly divisible by 1000 are given nine subsecond
* digits.) */
String unparse() const;
/** @brief Unparse this timestamp into a String as an interval.
*
* Returns a string formatted like "1us" or "1.000002s". */
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);
}
/** @brief Type of a Timestamp representation.
*
* This type is rarely useful for Timestamp users; we export it to avoid
* strict-aliasing warnings in unions. */
union rep_t {
#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;
# endif
#endif
#if TIMESTAMP_PUNS_TIMEVAL
struct timeval tv;
#elif TIMESTAMP_PUNS_TIMESPEC
struct timespec tspec;
#endif
};
#if TIMESTAMP_WARPABLE
/** @name Timewarping */
//@{
enum warp_class_type {
warp_none = 0, ///< Run in real time (the default).
warp_linear = 1, ///< Run in speeded-up or slowed-down real time.
warp_nowait = 2, ///< Run in speeded-up or slowed-down real time,
// but don't wait for timers.
warp_simulation = 3 ///< Run in simulation time.
};
/** @brief Return the active timewarp class. */
static inline int warp_class();
/** @brief Return the timewarp speed.
*
* Timewarp speed measures how much faster Timestamp::now() appears to
* move compared with wall-clock time. Only meaningful if warp_class() is
* #warp_linear or #warp_nowait. */
static inline double warp_speed();
/** @brief Set the timewarp class to @a w.
* @param w warp class
* @param s speed (\> 0, meaningful when @a w == #warp_linear)
*
* The timewarp classes are as follows:
*
* <dl>
* <dt>#warp_none</dt>
* <dd>Click time corresponds to real time. This is the default.</dd>
*
* <dt>#warp_linear</dt>
* <dd>Click time is a speeded-up or slowed-down version of real time.
* The speedup factor is @a s. If @a s \> 1, then time as measured by
* Timestamp::now() will appear to move a factor of @a s faster than real
* time: for instance, a Timer set using Timer::schedule_after_s(2) from
* now will fire after just 1 second of wall-clock time.</dd>
*
* <dt>#warp_nowait</dt>
* <dd>Like #warp_linear, but the Click driver never waits for a timer to
* expire. Instead, time appears to "jump" ahead to the next expiration
* time.</dd>
*
* <dt>#warp_simulation</dt>
* <dd>Click time is completely divorced from real time. Every call to
* Timestamp::now() appears to increase the current time by
* Timestamp::epsilon() and the Click driver never waits for a timer to
* expire. This mode effectively turns Click into an event-driven
* simulator.</dd>
* </dl>
*/
static void warp_set_class(warp_class_type w, double s = 1.0);
/** @brief Reset current time.
* @a t_system new system time
* @a t_steady new steady-clock time
*
* Only usable when warp_class() is not #warp_none. */
static void warp_set_now(const Timestamp &t_system, const Timestamp &t_steady);
/** @brief Return the wall-clock time corresponding to a delay. */
inline Timestamp warp_real_delay() const;
/** @brief Return true iff time skips ahead around timer expirations. */
static inline bool warp_jumping();
/** @brief Move Click time past a timer expiration.
*
* Does nothing if warp_jumping() is false or @a expiry is in the past. */
static void warp_jump_steady(const Timestamp &expiry);
/** @brief Return the warp-free current system time.
*
* Like now(), but the time returned is unaffected by timewarping.
* @sa now(), assign_now_unwarped() */
static inline Timestamp now_unwarped();
/** @brief Set this timestamp to the warp-free current system time.
*
* Like assign_now(), but the time assigned is unaffected by timewarping.
* @sa assign_now(), now_unwarped() */
inline void assign_now_unwarped();
/** @brief Return the warp-free current steady-clock time.
*
* Like now_steady(), but the time returned is unaffected by timewarping.
* @sa now_steady(), assign_now_steady_unwarped() */
static inline Timestamp now_steady_unwarped();
/** @brief Set this timestamp to the warp-free current steady-clock time.
*
* Like assign_now_steady(), but the time assigned is unaffected by
* timewarping.
* @sa assign_now_steady(), now_steady_unwarped() */
inline void assign_now_steady_unwarped();
//@}
#endif
private:
rep_t _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) {
return int_divide(a, b);
}
static inline void value_div_mod(int32_t &div, int32_t &rem,
value_type a, uint32_t b) {
value_type quot;
rem = int_remainder(a, b, quot);
div = quot;
}
inline void assign_now(bool recent, bool steady, bool unwarped);
#if TIMESTAMP_WARPABLE
static inline void warp_adjust(bool steady, const Timestamp &t_raw, const Timestamp &t_warped);
inline Timestamp warped(bool steady) const;
void warp(bool steady, bool from_now);
#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);
};
#if TIMESTAMP_WARPABLE
/** @cond never */
class TimestampWarp {
static Timestamp::warp_class_type kind;
static double speed;
static Timestamp flat_offset[2];
static double offset[2];
friend class Timestamp;
};
/** @endcond never */
inline int Timestamp::warp_class() {
return TimestampWarp::kind;
}
inline double Timestamp::warp_speed() {
return TimestampWarp::speed;
}
inline bool Timestamp::warp_jumping() {
return TimestampWarp::kind >= warp_nowait;
}
inline Timestamp Timestamp::warped(bool steady) const {
Timestamp t = *this;
if (TimestampWarp::kind)
t.warp(steady, false);
return t;
}
#endif
/** @brief Create a Timestamp measuring @a tv.
@param tv timeval structure */
inline
Timestamp::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 */
inline
Timestamp::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. */
inline
Timestamp::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
}
inline void
Timestamp::assign_now(bool recent, bool steady, bool unwarped)
{
(void) recent, (void) steady, (void) unwarped;
#if TIMESTAMP_PUNS_TIMESPEC
# define TIMESTAMP_DECLARE_TSP struct timespec &tsp = _t.tspec
# define TIMESTAMP_RESOLVE_TSP /* nothing */
#else
# define TIMESTAMP_DECLARE_TSP struct timespec ts, &tsp = ts
# define TIMESTAMP_RESOLVE_TSP assign(tsp.tv_sec, nsec_to_subsec(tsp.tv_nsec))
#endif
#if TIMESTAMP_PUNS_TIMEVAL
# define TIMESTAMP_DECLARE_TVP struct timeval &tvp = _t.tv
# define TIMESTAMP_RESOLVE_TVP /* nothing */
#else
# define TIMESTAMP_DECLARE_TVP struct timeval tv, &tvp = tv
# define TIMESTAMP_RESOLVE_TVP assign(tvp.tv_sec, usec_to_subsec(tvp.tv_usec))
#endif
#if CLICK_LINUXMODULE
# if !TIMESTAMP_NANOSEC
if (!recent && !steady) {
TIMESTAMP_DECLARE_TVP;
do_gettimeofday(&tvp);
TIMESTAMP_RESOLVE_TVP;
return;
}
# endif
TIMESTAMP_DECLARE_TSP;
if (recent && steady) {
# if HAVE_LINUX_GET_MONOTONIC_COARSE
tsp = get_monotonic_coarse();
# elif HAVE_LINUX_GETBOOTTIME && HAVE_LINUX_KTIME_MONO_TO_ANY
// XXX Is this even worth it????? Would it be faster to just get the
// current time?
tsp = current_kernel_time();
struct timespec delta =
ktime_to_timespec(ktime_mono_to_any(ktime_set(0, 0), TK_OFFS_REAL));
set_normalized_timespec(&tsp, tsp.tv_sec - delta.tv_sec,
tsp.tv_nsec - delta.tv_nsec);
# elif HAVE_LINUX_GETBOOTTIME
tsp = current_kernel_time();
struct timespec delta;
getboottime(&delta);
monotonic_to_bootbased(&delta);
set_normalized_timespec(&tsp, tsp.tv_sec - delta.tv_sec,
tsp.tv_nsec - delta.tv_nsec);
# else
// older kernels don't export enough information to produce a recent
// steady timestamp; produce a current steady timestamp
ktime_get_ts(&tsp);
# endif
} else if (recent)
tsp = current_kernel_time();
else if (steady)
ktime_get_ts(&tsp);
else
getnstimeofday(&tsp);
TIMESTAMP_RESOLVE_TSP;
#elif TIMESTAMP_NANOSEC && CLICK_BSDMODULE
TIMESTAMP_DECLARE_TSP;
if (recent && steady)
getnanouptime(&tsp);
else if (recent)
getnanotime(&tsp);
else if (steady)
nanouptime(&tsp);
else
nanotime(&tsp);
TIMESTAMP_RESOLVE_TSP;
#elif CLICK_BSDMODULE
TIMESTAMP_DECLARE_TVP;
if (recent && steady)
getmicrouptime(&tvp);
else if (recent)
getmicrotime(&tvp);
else if (steady)
microuptime(&tvp);
else
microtime(&tvp);
TIMESTAMP_RESOLVE_TVP;
#elif CLICK_MINIOS
TIMESTAMP_DECLARE_TVP;
gettimeofday(&tvp, (struct timezone *) 0);
TIMESTAMP_RESOLVE_TVP;
#elif CLICK_NS
if (schedule_granularity == usec_per_sec) {
TIMESTAMP_DECLARE_TVP;
simclick_gettimeofday(&tvp);
TIMESTAMP_RESOLVE_TVP;
} else {
assert(0 && "nanosecond precision not available yet");
}
#elif HAVE_USE_CLOCK_GETTIME
TIMESTAMP_DECLARE_TSP;
if (steady)
clock_gettime(CLOCK_MONOTONIC, &tsp);
else
clock_gettime(CLOCK_REALTIME, &tsp);
TIMESTAMP_RESOLVE_TSP;
#else
TIMESTAMP_DECLARE_TVP;
gettimeofday(&tvp, (struct timezone *) 0);
TIMESTAMP_RESOLVE_TVP;
#endif
#undef TIMESTAMP_DECLARE_TSP
#undef TIMESTAMP_RESOLVE_TSP
#undef TIMESTAMP_DECLARE_TVP
#undef TIMESTAMP_RESOLVE_TVP
#if TIMESTAMP_WARPABLE
// timewarping
if (!unwarped && TimestampWarp::kind)
warp(steady, true);
#endif
}
inline void
Timestamp::assign_now()
{
assign_now(false, false, false);
}
inline Timestamp
Timestamp::now()
{
Timestamp t = Timestamp::uninitialized_t();
t.assign_now();
return t;
}
inline void
Timestamp::assign_recent()
{
assign_now(true, false, false);
}
inline Timestamp
Timestamp::recent()
{
Timestamp t = Timestamp::uninitialized_t();
t.assign_recent();
return t;
}
inline void
Timestamp::assign_now_steady()
{
assign_now(false, true, false);
}
inline Timestamp
Timestamp::now_steady()
{
Timestamp t = Timestamp::uninitialized_t();
t.assign_now_steady();
return t;
}
inline void
Timestamp::assign_recent_steady()
{
assign_now(true, true, false);
}
inline Timestamp
Timestamp::recent_steady()
{
Timestamp t = Timestamp::uninitialized_t();
t.assign_recent_steady();
return t;
}
#if TIMESTAMP_WARPABLE
inline void
Timestamp::assign_now_unwarped()
{
assign_now(false, false, true);
}
inline Timestamp
Timestamp::now_unwarped()
{
Timestamp t = Timestamp::uninitialized_t();
t.assign_now_unwarped();
return t;
}
inline void
Timestamp::assign_now_steady_unwarped()
{
assign_now(false, true, true);
}
inline Timestamp
Timestamp::now_steady_unwarped()
{
Timestamp t = Timestamp::uninitialized_t();
t.assign_now_steady_unwarped();
return t;
}
#endif
/** @brief Set this timestamp's seconds component.
The subseconds component is left unchanged. */
inline void
Timestamp::set_sec(seconds_type sec)
{
#if TIMESTAMP_REP_FLAT64
uint32_t ss = subsec();
_t.x = (int64_t) sec * subsec_per_sec + ss;
#else
_t.sec = sec;
#endif
}
/** @brief Set this timestamp's subseconds component.
@param subsec number of subseconds
The seconds component is left unchanged. */
inline void
Timestamp::set_subsec(uint32_t subsec)
{
#if TIMESTAMP_REP_FLAT64
seconds_type s = sec();
_t.x = (int64_t) s * subsec_per_sec + subsec;
#else
_t.subsec = subsec;
#endif
}
/** @brief Return this timestamp's seconds component. */
inline Timestamp::seconds_type
Timestamp::sec() const
{
#if TIMESTAMP_REP_FLAT64
if (unlikely(_t.x < 0))
return -value_div(-(_t.x + 1), subsec_per_sec) - 1;
else
return value_div(_t.x, subsec_per_sec);
#else
return _t.sec;
#endif
}
/** @brief Return this timestamp's subseconds component. */
inline uint32_t
Timestamp::subsec() const
{
#if TIMESTAMP_REP_FLAT64
return _t.x - (uint32_t) sec() * subsec_per_sec;
#else
return _t.subsec;
#endif
}
/** @brief Return this timestamp's subseconds component, converted to
milliseconds. */
inline uint32_t
Timestamp::msec() const
{
return subsec_to_msec(subsec());
}
/** @brief Return this timestamp's subseconds component, converted to
microseconds. */
inline uint32_t
Timestamp::usec() const
{
return subsec_to_usec(subsec());
}
/** @brief Return this timestamp's subseconds component, converted to
nanoseconds. */
inline uint32_t
Timestamp::nsec() const
{
return subsec_to_nsec(subsec());
}
/** @brief Return this timestamp's interval length, converted to
milliseconds.
Will overflow on intervals of more than 2147483.647 seconds. */
inline Timestamp::seconds_type
Timestamp::msec1() const
{
#if TIMESTAMP_REP_FLAT64
return value_div(_t.x, subsec_per_sec / msec_per_sec);
#else
return _t.sec * msec_per_sec + subsec_to_msec(_t.subsec);
#endif
}
/** @brief Return this timestamp's interval length, converted to
microseconds.
Will overflow on intervals of more than 2147.483647 seconds. */
inline Timestamp::seconds_type
Timestamp::usec1() const
{
#if TIMESTAMP_REP_FLAT64
return value_div(_t.x, subsec_per_sec / usec_per_sec);
#else
return _t.sec * usec_per_sec + subsec_to_usec(_t.subsec);
#endif
}
/** @brief Return this timestamp's interval length, converted to
nanoseconds.
Will overflow on intervals of more than 2.147483647 seconds. */
inline Timestamp::seconds_type
Timestamp::nsec1() const
{
#if TIMESTAMP_REP_FLAT64
return _t.x * (nsec_per_sec / subsec_per_sec);
#else
return _t.sec * nsec_per_sec + subsec_to_nsec(_t.subsec);
#endif
}
#if !CLICK_TOOL
inline click_jiffies_t
Timestamp::jiffies() const
{
# if TIMESTAMP_REP_FLAT64
// This is not very precise when CLICK_HZ doesn't divide NSUBSEC evenly.
return value_div(_t.x, subsec_per_sec / CLICK_HZ);
# else
click_jiffies_t j = ((click_jiffies_t) sec()) * CLICK_HZ;
# if CLICK_HZ == 100 || CLICK_HZ == 1000 || CLICK_HZ == 10000 || CLICK_HZ == 100000 || CLICK_HZ == 1000000
return j + ((click_jiffies_t) subsec()) / (subsec_per_sec / CLICK_HZ);
# else
// This is not very precise when CLICK_HZ doesn't divide NSUBSEC evenly.
return j + ((click_jiffies_t) subsec()) / (subsec_per_sec / CLICK_HZ);
# endif
# endif
}
inline Timestamp
Timestamp::make_jiffies(click_jiffies_t jiffies)
{
// Not very precise when CLICK_HZ doesn't evenly divide subsec_per_sec.
Timestamp t = Timestamp::uninitialized_t();
# if TIMESTAMP_REP_FLAT64
t._t.x = (int64_t) jiffies * (subsec_per_sec / CLICK_HZ);
# else
t._t.sec = jiffies / CLICK_HZ;
t._t.subsec = (jiffies - t._t.sec * CLICK_HZ) * (subsec_per_sec / CLICK_HZ);
# endif
return t;
}
inline Timestamp
Timestamp::make_jiffies(click_jiffies_difference_t jiffies)
{
// Not very precise when CLICK_HZ doesn't evenly divide subsec_per_sec.
Timestamp t = Timestamp::uninitialized_t();
# if TIMESTAMP_REP_FLAT64
t._t.x = (int64_t) jiffies * (subsec_per_sec / CLICK_HZ);
# else
if (jiffies < 0)
t._t.sec = -(-(jiffies + 1) / CLICK_HZ) - 1;
else
t._t.sec = jiffies / CLICK_HZ;
t._t.subsec = (jiffies - t._t.sec * CLICK_HZ) * (subsec_per_sec / CLICK_HZ);
# endif
return t;
}
#endif
/** @cond never */
inline void Timestamp::set_now() {
assign_now(false, false, false);
}
inline void Timestamp::set(seconds_type sec, uint32_t subsec) {
assign(sec, subsec);
}
inline void Timestamp::set_usec(seconds_type sec, uint32_t usec) {
assign_usec(sec, usec);
}
inline void Timestamp::set_nsec(seconds_type sec, uint32_t nsec) {
assign_nsec(sec, nsec);
}
/** @endcond never */
/** @relates Timestamp
@brief Compare two timestamps for equality.
Returns true iff the two operands have the same seconds and subseconds
components. */
inline bool
operator==(const Timestamp &a, const Timestamp &b)
{
#if TIMESTAMP_REP_FLAT64 || TIMESTAMP_MATH_FLAT64
return a._t.x == b._t.x;
#else
return a.sec() == b.sec() && a.subsec() == b.subsec();
#endif
}
/** @relates Timestamp
@brief Compare two timestamps for inequality.
Returns true iff !(@a a == @a b). */
inline bool
operator!=(const Timestamp &a, const Timestamp &b)
{
return !(a == b);
}
/** @relates Timestamp
@brief Compare two timestamps.
Returns true iff @a a represents a shorter interval than @a b, or
considered as absolute time, @a a happened before @a b. */
inline bool
operator<(const Timestamp &a, const Timestamp &b)
{
#if TIMESTAMP_REP_FLAT64 || TIMESTAMP_MATH_FLAT64
return a._t.x < b._t.x;
#else
return a.sec() < b.sec() || (a.sec() == b.sec() && a.subsec() < b.subsec());
#endif
}
/** @overload */
inline bool
operator<(const Timestamp &a, int b)
{
return a < Timestamp(b);
}
/** @relates Timestamp
@brief Compare two timestamps.
Returns true iff @a a measures an interval no larger than @a b, or
considered as absolute time, @a a happened at or before @a b. */
inline bool
operator<=(const Timestamp &a, const Timestamp &b)
{
return !(b < a);
}
/** @overload */
inline bool
operator<=(const Timestamp &a, int b)
{
return a <= Timestamp(b);
}
/** @relates Timestamp
@brief Compare two timestamps.
Returns true iff @a a measures an interval no shorter than @a b, or
considered as absolute time, @a a happened at or after @a b. */
inline bool
operator>=(const Timestamp &a, const Timestamp &b)
{
return !(a < b);
}
/** @overload */
inline bool
operator>=(const Timestamp &a, int b)
{
return a >= Timestamp(b);
}
/** @relates Timestamp
@brief Compare two timestamps.
Returns true iff @a a measures a longer interval than @a b, or considered
as absolute time, @a a happened after @a b. */
inline bool
operator>(const Timestamp &a, const Timestamp &b)
{
return b < a;
}
/** @overload */
inline bool
operator>(const Timestamp &a, int b)
{
return a > Timestamp(b);
}
/** @brief Add @a b to @a a.
Returns the result (the new value of @a a). */
inline Timestamp &
operator+=(Timestamp &a, const Timestamp &b)
{
#if TIMESTAMP_REP_FLAT64 || TIMESTAMP_MATH_FLAT64
a._t.x += b._t.x;
#else
a._t.sec += b._t.sec;
a._t.subsec += b._t.subsec;
#endif
a.add_fix();
return a;
}
/** @brief Subtract @a b from @a a.
Returns the result (the new value of @a a). */
inline Timestamp &
operator-=(Timestamp &a, const Timestamp &b)
{
#if TIMESTAMP_REP_FLAT64 || TIMESTAMP_MATH_FLAT64
a._t.x -= b._t.x;
#else
a._t.sec -= b._t.sec;
a._t.subsec -= b._t.subsec;
#endif
a.sub_fix();
return a;
}
/** @brief Add the two operands and return the result. */
inline Timestamp
operator+(Timestamp a, const Timestamp &b)
{
a += b;
return a;
}
/** @brief Subtract @a b from @a a and return the result. */
inline Timestamp
operator-(Timestamp a, const Timestamp &b)
{
a -= b;
return a;
}
/** @brief Negate @a a and return the result. */
inline Timestamp
operator-(const Timestamp &a)
{
#if TIMESTAMP_REP_FLAT64
Timestamp t = Timestamp::uninitialized_t();
t._t.x = -a._t.x;
return t;
#else
if (a.subsec())
return Timestamp(-(a.sec() + 1), Timestamp::subsec_per_sec - a.subsec());
else
return Timestamp(-a.sec(), 0);
#endif
}
#if HAVE_FLOAT_TYPES
/** @brief Return this timestamp's value, converted to a real number. */
inline double
Timestamp::doubleval() const
{
# if TIMESTAMP_REP_FLAT64
return _t.x / (double) subsec_per_sec;
# else
return _t.sec + (_t.subsec / (double) subsec_per_sec);
# endif
}
/** @brief Create a timestamp measuring @a d seconds. */
inline
Timestamp::Timestamp(double d)
{
# if TIMESTAMP_REP_FLAT64
_t.x = (int64_t) floor(d * subsec_per_sec + 0.5);
# else
double dfloor = floor(d);
_t.sec = (seconds_type) dfloor;
_t.subsec = (uint32_t) ((d - dfloor) * subsec_per_sec + 0.5);
add_fix();
# endif
}
/** @brief Scale @a a by a factor of @a b and return the result. */
inline Timestamp
operator*(const Timestamp &a, double b)
{
return Timestamp(a.doubleval() * b);
}
inline Timestamp
operator*(const Timestamp &a, int b)
{
return Timestamp(a.doubleval() * b);
}
inline Timestamp
operator*(const Timestamp &a, unsigned b)
{
return Timestamp(a.doubleval() * b);
}
inline Timestamp
operator*(double a, const Timestamp &b)
{
return Timestamp(b.doubleval() * a);
}
inline Timestamp
operator*(int a, const Timestamp &b)
{
return Timestamp(b.doubleval() * a);
}
inline Timestamp
operator*(unsigned a, const Timestamp &b)
{
return Timestamp(b.doubleval() * a);
}
/** @brief Scale @a a down by a factor of @a b and return the result. */
inline Timestamp
operator/(const Timestamp &a, double b)
{
return Timestamp(a.doubleval() / b);
}
inline Timestamp
operator/(const Timestamp &a, int b)
{
return Timestamp(a.doubleval() / b);
}
inline Timestamp
operator/(const Timestamp &a, unsigned b)
{
return Timestamp(a.doubleval() / b);
}
/** @brief Divide @a a by @a b and return the result. */
inline double
operator/(const Timestamp &a, const Timestamp &b)
{
return a.doubleval() / b.doubleval();
}
#endif /* HAVE_FLOAT_TYPES */
StringAccum& operator<<(StringAccum&, const Timestamp&);
#if TIMESTAMP_WARPABLE
inline Timestamp
Timestamp::warp_real_delay() const
{
if (likely(!TimestampWarp::kind) || TimestampWarp::speed == 1.0)
return *this;
else
return *this / TimestampWarp::speed;
}
#endif
#if TIMESTAMP_PUNS_TIMEVAL
inline const struct timeval &
Timestamp::timeval() const
{
return _t.tv;
}
inline const struct timeval &
Timestamp::timeval_ceil() const
{
return _t.tv;
}
#else
/** @brief Return a struct timeval that approximates this timestamp.
If Timestamp and struct timeval have the same size and representation,
then this operation returns a "const struct timeval &" whose address is
the same as this Timestamp. If Timestamps have nanosecond precision,
the conversion rounds down, so Timestamp(t.timeval()) <= t. */
inline struct timeval
Timestamp::timeval() const
{
struct timeval tv;
tv.tv_sec = sec();
tv.tv_usec = usec();
return tv;
}
/** @brief Return the minimum struct timeval >= this timestamp.
If Timestamp and struct timeval have the same size and representation,
then this operation returns a "const struct timeval &" whose address is
the same as this Timestamp. */
inline struct timeval
Timestamp::timeval_ceil() const
{
return (*this + Timestamp(0, subsec_per_usec - 1)).timeval();
}
#endif
#if HAVE_STRUCT_TIMESPEC
# if TIMESTAMP_PUNS_TIMESPEC
inline const struct timespec &
Timestamp::timespec() const
{
return _t.tspec;
}
# else
/** @brief Return a struct timespec with the same value as this timestamp.
If Timestamp and struct timespec have the same size and representation,
then this operation returns a "const struct timespec &" whose address is
the same as this Timestamp. */
inline struct timespec
Timestamp::timespec() const
{
struct timespec ts;
ts.tv_sec = sec();
ts.tv_nsec = nsec();
return ts;
}
# endif
#endif
class ArgContext;
extern const ArgContext blank_args;
bool cp_time(const String &str, Timestamp *result, bool allow_negative);
/** @class TimestampArg
@brief Parser class for timestamps. */
class TimestampArg { public:
TimestampArg(bool is_signed = false)
: is_signed(is_signed) {
}
bool parse(const String &str, Timestamp &value, const ArgContext &args = blank_args) {
(void) args;
return cp_time(str, &value, is_signed);
}
bool is_signed;
};
template<> struct DefaultArg<Timestamp> : public TimestampArg {};
template<> struct has_trivial_copy<Timestamp> : public true_type {};
CLICK_ENDDECLS
#endif