diff --git a/src/common/data-rate.h b/src/common/data-rate.h index 746338bc3..60a804f21 100644 --- a/src/common/data-rate.h +++ b/src/common/data-rate.h @@ -125,8 +125,8 @@ ATTRIBUTE_HELPER_HEADER (DataRate); * \param rhs * \return Bits transmitted in rhs seconds at lhs b/s */ -double operator*(const DataRate& lhs, const TimeUnit<1>& rhs); -double operator*(const TimeUnit<1>& lhs, const DataRate& rhs); +double operator*(const DataRate& lhs, const Time& rhs); +double operator*(const Time& lhs, const DataRate& rhs); } //namespace ns3 diff --git a/src/devices/csma/backoff.cc b/src/devices/csma/backoff.cc index 08c4cd13e..de1f82c79 100644 --- a/src/devices/csma/backoff.cc +++ b/src/devices/csma/backoff.cc @@ -67,7 +67,7 @@ Backoff::GetBackoffTime (void) uint32_t backoffSlots = (uint32_t)m_rng.GetValue(minSlot, maxSlot); - backoff = Scalar(backoffSlots) * m_slotTime; + backoff = Scalar (backoffSlots) * m_slotTime; return (backoff); } diff --git a/src/internet-stack/ndisc-cache.cc b/src/internet-stack/ndisc-cache.cc index d31730f65..ff9889be9 100644 --- a/src/internet-stack/ndisc-cache.cc +++ b/src/internet-stack/ndisc-cache.cc @@ -157,7 +157,7 @@ NdiscCache::Entry::Entry (NdiscCache* nd) m_retransTimer(Timer::CANCEL_ON_DESTROY), m_probeTimer(Timer::CANCEL_ON_DESTROY), m_delayTimer(Timer::CANCEL_ON_DESTROY), - m_lastReachabilityConfirmation(Timer::CANCEL_ON_DESTROY), + m_lastReachabilityConfirmation(Seconds (0.0)), m_nsRetransmit (0) { NS_LOG_FUNCTION_NOARGS (); diff --git a/src/mobility/waypoint.cc b/src/mobility/waypoint.cc index ee891c627..32a356746 100644 --- a/src/mobility/waypoint.cc +++ b/src/mobility/waypoint.cc @@ -28,8 +28,8 @@ Waypoint::Waypoint (const Time &waypointTime, const Vector &waypointPosition) position (waypointPosition) {} Waypoint::Waypoint () - : time (0.0), - position (0,0,0) + : time (Seconds (0.0)), + position (0,0,0) {} std::ostream &operator << (std::ostream &os, const Waypoint &waypoint) diff --git a/src/simulator/default-simulator-impl.cc b/src/simulator/default-simulator-impl.cc index 86bb0f19d..c17042098 100644 --- a/src/simulator/default-simulator-impl.cc +++ b/src/simulator/default-simulator-impl.cc @@ -40,7 +40,7 @@ TypeId DefaultSimulatorImpl::GetTypeId (void) { static TypeId tid = TypeId ("ns3::DefaultSimulatorImpl") - .SetParent () + .SetParent () .AddConstructor () ; return tid; diff --git a/src/simulator/high-precision-128.cc b/src/simulator/high-precision-128.cc index a53c16f66..918ed1a6d 100644 --- a/src/simulator/high-precision-128.cc +++ b/src/simulator/high-precision-128.cc @@ -1,30 +1,59 @@ #include "high-precision-128.h" -#include "ns3/fatal-error.h" +#include "ns3/abort.h" +#include "ns3/assert.h" #include +#ifdef COUNT_OPS +#include +#endif namespace ns3 { +#ifdef COUNT_OPS +uint128_t HighPrecision::g_nAdd = 0; +uint128_t HighPrecision::g_nMuli = 0; +uint128_t HighPrecision::g_nMul = 0; +uint128_t HighPrecision::g_nDiv = 0; +uint128_t HighPrecision::g_nCmp = 0; +HighPrecision::Printer HighPrecision::g_printer; +HighPrecision::Printer::~Printer () +{ + std::cout << "add=" << (double)g_nAdd << " mul=" << (double)g_nMul << " div=" << (double)g_nDiv + << " muli=" << (double)g_nMuli << " cmp=" << (double)g_nCmp; +} +#endif + +#define OUTPUT_SIGN(sa,sb,ua,ub) \ + ({bool negA, negB; \ + negA = sa < 0; \ + negB = sb < 0; \ + ua = negA?-sa:sa; \ + ub = negB?-sb:sb; \ + (negA && !negB) || (!negA && negB);}) + + #define MASK_LO ((((uint128_t)1)<<64)-1) #define MASK_HI (~MASK_LO) void HighPrecision::Mul (HighPrecision const &o) { - bool negResult, negA, negB; - // take the sign of the operands - negA = m_value < 0; - negB = o.m_value < 0; - // the result is negative only if one of the operand is negative - negResult = (negA && !negB) || (!negA && negB); - // now take the absolute part to make sure that the resulting operands are positive + bool negResult; uint128_t a, b; - a = negA?-m_value:m_value; - b = negB?-o.m_value:o.m_value; + negResult = OUTPUT_SIGN (m_value, o.m_value, a, b); + int128_t result = Umul (a, b); + // add the sign to the result + result = negResult ? -result : result; + m_value = result; +} + +uint128_t +HighPrecision::Umul (uint128_t a, uint128_t b) +{ + INC_MUL; uint128_t aL = a & MASK_LO; uint128_t bL = b & MASK_LO; uint128_t aH = (a >> 64) & MASK_LO; uint128_t bH = (b >> 64) & MASK_LO; - uint128_t result; uint128_t hiPart,loPart,midPart; @@ -42,28 +71,25 @@ HighPrecision::Mul (HighPrecision const &o) // truncate the high part and only use the low part result |= ((hiPart & MASK_LO) << 64) + (midPart & MASK_HI); // if the high part is not zero, put a warning - if ((hiPart & MASK_HI) != 0) - { - NS_FATAL_ERROR ("High precision 128 bits multiplication error: multiplication overflow."); - } - // add the sign to the result - result = negResult ? -result:result; - m_value = result; + NS_ABORT_MSG_IF ((hiPart & MASK_HI) != 0, + "High precision 128 bits multiplication error: multiplication overflow."); + return result; } void HighPrecision::Div (HighPrecision const &o) { - bool negResult, negA, negB; - // take the sign of the operands - negA = m_value < 0; - negB = o.m_value < 0; - // the result is negative only if one of the operand is negative - negResult = (negA && !negB) || (!negA && negB); - // now take the absolute part to make sure that the resulting operands are positive + bool negResult; uint128_t a, b; - a = negA?-m_value:m_value; - b = negB?-o.m_value:o.m_value; + negResult = OUTPUT_SIGN (m_value, o.m_value, a, b); + int128_t result = Divu (a, b); + result = negResult ? -result:result; + m_value = result; +} +uint128_t +HighPrecision::Divu (uint128_t a, uint128_t b) +{ + INC_DIV; uint128_t quo = a / b; uint128_t rem = (a % b); uint128_t result = quo << 64; @@ -82,8 +108,50 @@ HighPrecision::Div (HighPrecision const &o) } quo = rem / div; result = result + quo; - result = negResult ? -result:result; - m_value = result; + return result; +} + +void +HighPrecision::MulByInvert (const HighPrecision &o) +{ + bool negResult = m_value < 0; + uint128_t a = negResult?-m_value:m_value; + uint128_t result = UmulByInvert (a, o.m_value); + + m_value = negResult?-result:result; +} +uint128_t +HighPrecision::UmulByInvert (uint128_t a, uint128_t b) +{ + INC_MULI; + uint128_t result, ah, bh, al, bl; + uint128_t hi, mid; + ah = a >> 64; + bh = b >> 64; + al = a & MASK_LO; + bl = b & MASK_LO; + hi = ah * bh; + mid = ah * bl + al * bh; + mid >>= 64; + result = ah * bh + mid; + return result; +} +HighPrecision +HighPrecision::Invert (uint64_t v) +{ + NS_ASSERT (v > 1); + uint128_t a; + a = 1; + a <<= 64; + HighPrecision result; + result.m_value = Divu (a, v); + HighPrecision tmp = HighPrecision (v, false); + tmp.MulByInvert (result); + if (tmp.GetInteger () != 1) + { + result.m_value += 1; + } + return result; } } // namespace ns3 diff --git a/src/simulator/high-precision-128.h b/src/simulator/high-precision-128.h index 19e9cf929..a9b8a2c63 100644 --- a/src/simulator/high-precision-128.h +++ b/src/simulator/high-precision-128.h @@ -24,19 +24,37 @@ #include #include +#define noCOUNT_OPS 1 + #if defined(HAVE___UINT128_T) and !defined(HAVE_UINT128_T) typedef __uint128_t uint128_t; typedef __int128_t int128_t; #endif +#ifdef COUNT_OPS +#define INC_ADD HighPrecision::g_nAdd++ +#define INC_SUB HighPrecision::g_nAdd++ +#define INC_MUL HighPrecision::g_nMul++ +#define INC_DIV HighPrecision::g_nDiv++ +#define INC_MULI HighPrecision::g_nMuli++ +#define INC_CMP HighPrecision::g_nCmp++ +#else +#define INC_ADD +#define INC_SUB +#define INC_MUL +#define INC_DIV +#define INC_MULI +#define INC_CMP +#endif + namespace ns3 { class HighPrecision { public: inline HighPrecision (); - inline HighPrecision (int64_t value, bool dummy); - inline HighPrecision (double value); + explicit inline HighPrecision (int64_t value, bool dummy); + explicit inline HighPrecision (double value); inline int64_t GetInteger (void) const; inline double GetDouble (void) const; @@ -44,11 +62,28 @@ public: inline void Sub (HighPrecision const &o); void Mul (HighPrecision const &o); void Div (HighPrecision const &o); + void MulByInvert (const HighPrecision &o); + static HighPrecision Invert (uint64_t v); inline int Compare (HighPrecision const &o) const; inline static HighPrecision Zero (void); private: + static uint128_t UmulByInvert (uint128_t a, uint128_t b); + static uint128_t Umul (uint128_t a, uint128_t b); + static uint128_t Divu (uint128_t a, uint128_t b); + int128_t m_value; + +#ifdef COUNT_OPS + static uint128_t g_nAdd; + static uint128_t g_nMuli; + static uint128_t g_nMul; + static uint128_t g_nDiv; + static uint128_t g_nCmp; + static struct Printer { + ~Printer (); + } g_printer; +#endif }; } // namespace ns3 @@ -75,17 +110,20 @@ int64_t HighPrecision::GetInteger (void) const void HighPrecision::Add (HighPrecision const &o) { + INC_ADD; m_value += o.m_value; } void HighPrecision::Sub (HighPrecision const &o) { + INC_SUB; m_value -= o.m_value; } int HighPrecision::Compare (HighPrecision const &o) const { + INC_CMP; return (m_value < o.m_value)?-1:(m_value == o.m_value)?0:1; } diff --git a/src/simulator/high-precision-cairo.cc b/src/simulator/high-precision-cairo.cc index 217d660f3..77893f2ec 100644 --- a/src/simulator/high-precision-cairo.cc +++ b/src/simulator/high-precision-cairo.cc @@ -19,17 +19,31 @@ */ #include "high-precision-cairo.h" #include "ns3/test.h" -#include "ns3/fatal-error.h" +#include "ns3/abort.h" +#include "ns3/assert.h" #include #include namespace ns3 { + +#define OUTPUT_SIGN(sa,sb,ua,ub) \ + ({bool negA, negB; \ + negA = _cairo_int128_negative (sa); \ + negB = _cairo_int128_negative (sb); \ + ua = _cairo_int128_to_uint128 (sa); \ + ub = _cairo_int128_to_uint128 (sb); \ + ua = negA ? _cairo_uint128_negate (ua) : ua; \ + ub = negB ? _cairo_uint128_negate (ub) : ub; \ + (negA && !negB) || (!negA && negB);}) + void HighPrecision::Mul (HighPrecision const &o) { - // use the 128 bits multiplication - m_value = Mul128 (m_value,o.m_value); + cairo_uint128_t a, b, result; + bool sign = OUTPUT_SIGN (m_value, o.m_value, a, b); + result = Umul (a, b); + m_value = sign ? _cairo_uint128_negate (result) : result; } @@ -39,22 +53,9 @@ HighPrecision::Mul (HighPrecision const &o) * as the fractional part. It takes into account the sign * of the operands to produce a signed 128 bits result. */ -cairo_int128_t -HighPrecision::Mul128 (cairo_int128_t sa, cairo_int128_t sb ) const +cairo_uint128_t +HighPrecision::Umul (cairo_uint128_t a, cairo_uint128_t b) { - bool negResult, negA, negB; - - negA = _cairo_int128_negative (sa); - negB = _cairo_int128_negative (sb); - // the result is negative only if one of the operand is negative - negResult = (negA && !negB) || (!negA && negB); - // now take the absolute part to make sure that the resulting operands are positive - cairo_uint128_t a, b; - a = _cairo_int128_to_uint128 (sa); - b = _cairo_int128_to_uint128 (sb); - a = negA ? _cairo_uint128_negate (a) : a; - b = negB ? _cairo_uint128_negate (b) : b; - cairo_uint128_t result; cairo_uint128_t hiPart,loPart,midPart; @@ -73,38 +74,23 @@ HighPrecision::Mul128 (cairo_int128_t sa, cairo_int128_t sb ) const // truncate the high part and only use the low part result.hi = _cairo_uint64_add (hiPart.lo,midPart.hi); // if the high part is not zero, put a warning - if (hiPart.hi != 0) - { - NS_FATAL_ERROR ("High precision 128 bits multiplication error: multiplication overflow."); - } - // add the sign to the result - result = negResult ? _cairo_uint128_negate (result) : result; - return _cairo_uint128_to_int128 (result); + NS_ABORT_MSG_IF (hiPart.hi != 0, + "High precision 128 bits multiplication error: multiplication overflow."); + return result; } void HighPrecision::Div (HighPrecision const &o) { - cairo_int128_t result = Div128 (m_value, o.m_value); - m_value = result; + cairo_uint128_t a, b, result; + bool sign = OUTPUT_SIGN (m_value, o.m_value, a, b); + result = Udiv (a, b); + m_value = sign ? _cairo_uint128_negate (result) : result; } -cairo_int128_t -HighPrecision::Div128 (cairo_int128_t sa, cairo_int128_t sb) const +cairo_uint128_t +HighPrecision::Udiv (cairo_uint128_t a, cairo_uint128_t b) { - bool negResult, negA, negB; - // take the sign of the operands - negA = _cairo_int128_negative (sa); - negB = _cairo_int128_negative (sb); - // the result is negative only if one of the operand is negative - negResult = (negA && !negB) || (!negA && negB); - // now take the absolute part to make sure that the resulting operands are positive - cairo_uint128_t a, b; - a = _cairo_int128_to_uint128 (sa); - b = _cairo_int128_to_uint128 (sb); - a = negA ? _cairo_uint128_negate (a) : a; - b = negB ? _cairo_uint128_negate (b) : b; - cairo_uquorem128_t qr = _cairo_uint128_divrem (a, b); cairo_uint128_t result = _cairo_uint128_lsl (qr.quo, 64); // Now, manage the remainder @@ -123,9 +109,56 @@ HighPrecision::Div128 (cairo_int128_t sa, cairo_int128_t sb) const } qr = _cairo_uint128_divrem (rem, div); result = _cairo_uint128_add (result, qr.quo); - result = negResult ? _cairo_uint128_negate (result) : result; - return _cairo_uint128_to_int128 (result); + return result; } +void +HighPrecision::MulByInvert (const HighPrecision &o) +{ + bool negResult = _cairo_int128_negative (m_value); + cairo_uint128_t a = negResult?_cairo_int128_negate(m_value):m_value; + cairo_uint128_t result = UmulByInvert (a, o.m_value); + + m_value = negResult?_cairo_int128_negate(result):result; +} +cairo_uint128_t +HighPrecision::UmulByInvert (cairo_uint128_t a, cairo_uint128_t b) +{ + cairo_uint128_t result; + cairo_uint128_t hi, mid; + hi = _cairo_uint64x64_128_mul (a.hi, b.hi); + mid = _cairo_uint128_add (_cairo_uint64x64_128_mul (a.hi, b.lo), + _cairo_uint64x64_128_mul (a.lo, b.hi)); + mid.lo = mid.hi; + mid.hi = 0; + result = _cairo_uint128_add (hi,mid); + return result; +} +HighPrecision +HighPrecision::Invert (uint64_t v) +{ + NS_ASSERT (v > 1); + cairo_uint128_t a, factor; + a.hi = 1; + a.lo = 0; + factor.hi = 0; + factor.lo = v; + HighPrecision result; + result.m_value = Udiv (a, factor); + HighPrecision tmp = HighPrecision (v, false); + tmp.MulByInvert (result); + if (tmp.GetInteger () != 1) + { + cairo_uint128_t one = {1, 0}; + result.m_value = _cairo_uint128_add (result.m_value, one); + } + return result; +} + + } // namespace ns3 +// include directly to allow optimizations within the compilation unit. +extern "C" { +#include "cairo-wideint.c" +} diff --git a/src/simulator/high-precision-cairo.h b/src/simulator/high-precision-cairo.h index daeb935ca..1f5abd88e 100644 --- a/src/simulator/high-precision-cairo.h +++ b/src/simulator/high-precision-cairo.h @@ -37,37 +37,6 @@ * Division operations (there are really really super costly) * and Comparison operations (because there are typically a lot of * these in any complex timekeeping code). - * - * So, the code tries really hard to perform any of these 128 bit - * operations by doing all arithmetic on 64 bit integers when possible - * (i.e., when there is no fractional part. This is a very common case). - * Hence, the following code has a m_fastValue (64 bits) and a - * m_slowValue (128 bits). m_fastValue is used by default and the code - * converts it to a m_slowValue when needed. - * - * If you want to monitor the efficiency of this strategy, you can - * enable the macro HP128INC below and call the HighPrecision::PrintStats - * method at the end of the simulation. - * - * Explanation of Slow and Fast values: - * - * HighPrecision class create a fastValue and a slowValue depending on the - * input number. If the input is an integer with 0 fractional part, it will - * use the fastValue which will contain the integer in a 64 bits format. If - * it has a fractional part, the slowValue will be used. It is represented - * simply as a high part slowValue.hi which will contain the integer part - * and the fractional part slowValue.lo which will contain the factional - * part as an integer (obtained by multiplying the fractional part by 2^64). - * - * Explanation of Slow and Fast operations: - * - * If both operands are fastValues, we will perform fast operations, i-e - * simply using integer operations. If we have though one of the value is - * slowValue we need to convert the fastValue into a slow one. It is simply - * obtained by putting the slowValue.lo = 0 and slowValue.hi = fastValue. - * After that we apply the slow operation which will be a 128 bits operation - * with two 128 bits operands. - * */ namespace ns3 { @@ -76,8 +45,8 @@ class HighPrecision { public: inline HighPrecision (); - inline HighPrecision (int64_t value, bool dummy); - inline HighPrecision (double value); + explicit inline HighPrecision (int64_t value, bool dummy); + explicit inline HighPrecision (double value); inline int64_t GetInteger (void) const; inline double GetDouble (void) const; @@ -85,12 +54,15 @@ public: inline void Sub (HighPrecision const &o); void Mul (HighPrecision const &o); void Div (HighPrecision const &o); + void MulByInvert (const HighPrecision &o); + static HighPrecision Invert (uint64_t v); inline int Compare (HighPrecision const &o) const; inline static HighPrecision Zero (void); private: - cairo_uint128_t Mul128 (cairo_uint128_t, cairo_uint128_t ) const; - cairo_int128_t Div128 (cairo_int128_t sa, cairo_int128_t sb) const; + static cairo_uint128_t Umul (cairo_uint128_t a, cairo_uint128_t b); + static cairo_uint128_t Udiv (cairo_uint128_t a, cairo_uint128_t b); + static cairo_uint128_t UmulByInvert (cairo_uint128_t a, cairo_uint128_t b); inline bool IsNegative (void) const; cairo_int128_t m_value; diff --git a/src/simulator/high-precision-double.h b/src/simulator/high-precision-double.h index d28120da1..f25fa8099 100644 --- a/src/simulator/high-precision-double.h +++ b/src/simulator/high-precision-double.h @@ -35,8 +35,8 @@ class HighPrecision { public: inline HighPrecision (); - inline HighPrecision (int64_t value, bool dummy); - inline HighPrecision (double value); + explicit inline HighPrecision (int64_t value, bool dummy); + explicit inline HighPrecision (double value); inline int64_t GetInteger (void) const; inline double GetDouble (void) const; @@ -44,6 +44,8 @@ public: inline void Sub (HighPrecision const &o); inline void Mul (HighPrecision const &o); inline void Div (HighPrecision const &o); + inline void MulByInvert (const HighPrecision &o); + inline static HighPrecision Invert (uint64_t v); inline int Compare (HighPrecision const &o) const; inline static HighPrecision Zero (void); @@ -101,10 +103,21 @@ HighPrecision::Div (HighPrecision const &o) { m_value /= o.m_value; } +void +HighPrecision::MulByInvert (const HighPrecision &o) +{ + m_value *= o.m_value; +} +HighPrecision +HighPrecision::Invert (uint64_t v) +{ + return HighPrecision (1.0 / v); +} + int HighPrecision::Compare (HighPrecision const &o) const { - return m_value < o.m_value; + return (m_value < o.m_value)?-1:(m_value == o.m_value)?0:1; } HighPrecision HighPrecision::Zero (void) diff --git a/src/simulator/high-precision.cc b/src/simulator/high-precision.cc index 257a49e6d..23573554a 100644 --- a/src/simulator/high-precision.cc +++ b/src/simulator/high-precision.cc @@ -282,6 +282,70 @@ Hp128CompareTestCase::DoRun (void) return false; } +class Hp128InvertTestCase : public TestCase +{ +public: + Hp128InvertTestCase (); + virtual bool DoRun (void); +}; + +Hp128InvertTestCase::Hp128InvertTestCase () + : TestCase ("Test case for invertion") +{ +} + +bool +Hp128InvertTestCase::DoRun (void) +{ +#define TEST(factor) \ + do { \ + HighPrecision a; \ + a = HighPrecision::Invert (factor); \ + HighPrecision b = V (factor); \ + b.MulByInvert (a); \ + NS_TEST_ASSERT_MSG_EQ (b.GetInteger (), 1, \ + "x * 1/x should be 1 for x=" << factor); \ + HighPrecision c = V (1); \ + c.MulByInvert (a); \ + NS_TEST_ASSERT_MSG_EQ (c.GetInteger (), 0, \ + "1 * 1/x should be 0 for x=" << factor); \ + HighPrecision d = V (1); \ + d.Div (V(factor)); \ + NS_TEST_ASSERT_MSG_EQ (d.GetDouble (), c.GetDouble (), \ + "1 * 1/x should be equal to 1/x for x=" << factor); \ + HighPrecision e = V (-factor); \ + e.MulByInvert (a); \ + NS_TEST_ASSERT_MSG_EQ (e.GetInteger (), -1, \ + "-x * 1/x should be -1 for x=" << factor); \ + } while(false) + + TEST(2); + TEST(3); + TEST(4); + TEST(5); + TEST(6); + TEST(10); + TEST(99); + TEST(100); + TEST(1000); + TEST(10000); + TEST(100000); + TEST(100000); + TEST(1000000); + TEST(10000000); + TEST(100000000); + TEST(1000000000); + TEST(10000000000LL); + TEST(100000000000LL); + TEST(1000000000000LL); + TEST(10000000000000LL); + TEST(100000000000000LL); + TEST(1000000000000000LL); +#undef TEST + return false; +} + + static class HighPrecision128TestSuite : public TestSuite { public: @@ -292,6 +356,7 @@ public: AddTestCase (new Hp128Bug455TestCase ()); AddTestCase (new Hp128Bug863TestCase ()); AddTestCase (new Hp128CompareTestCase ()); + AddTestCase (new Hp128InvertTestCase ()); } } g_highPrecision128TestSuite; diff --git a/src/simulator/nstime.h b/src/simulator/nstime.h index ca4bf0881..fd28f96fa 100644 --- a/src/simulator/nstime.h +++ b/src/simulator/nstime.h @@ -30,34 +30,6 @@ namespace ns3 { -namespace TimeStepPrecision { - -enum precision_t -{ - S = 0, - MS = 3, - US = 6, - NS = 9, - PS = 12, - FS = 15 -}; -/** - * \param precision the new precision to use - * - * This should be invoked before any Time object - * is created. i.e., it should be invoked at the very start - * of every simulation. The unit specified by this method - * is used as the unit of the internal simulation time - * which is stored as a 64 bit integer. - */ -void Set (precision_t precision); -/** - * \returns the currently-used time precision. - */ -precision_t Get (void); - -} // namespace TimeStepPrecision - /** * \ingroup simulator @@ -109,251 +81,107 @@ precision_t Get (void); * - \ref ns3-Time-Max ns3::Max * - \ref ns3-Time-Min ns3::Min */ -template -class TimeUnit +/** + * \ingroup time + * \brief keep track of time values and allow control of global simulation resolution + * + * This class defines all the classic C++ arithmetic + * operators +, -, *, /, and all the classic comparison operators: + * ==, !=, <, >, <=, >=. It is thus easy to add, substract, or + * multiply multiple Time objects. + * + * The ns3::Scalar, ns3::TimeSquare, and ns3::TimeInvert classes + * are backward-compatibility aliases for ns3::Time. + * + * For example: + * \code + * Time t1 = Seconds (10.0); + * Time t2 = Seconds (10.0); + * Time t3 = t1 * t2; + * Time t4 = t1 / t2; + * Time t5 = t3 * t1; + * Time t6 = t1 / t5; + * Time t7 = t3; + * \endcode + * + * You can also use the following non-member functions to manipulate + * any of these ns3::Time object: + * - \ref ns3-Time-Abs ns3::Abs + * - \ref ns3-Time-Max ns3::Max + * - \ref ns3-Time-Min ns3::Min + * + * This class also controls + * the resolution of the underlying time value . The default resolution + * is nanoseconds. That is, TimeStep (1).GetNanoSeconds () will return + * 1. It is possible to either increase or decrease the resolution and the + * code tries really hard to make this easy. + * + * If your resolution is X (say, nanoseconds) and if you create Time objects + * with a lower resolution (say, picoseconds), don't expect that this + * code will return 1: PicoSeconds (1).GetPicoSeconds (). It will most + * likely return 0 because the Time object has only 64 bits of fractional + * precision which means that PicoSeconds (1) is stored as a 64-bit aproximation + * of 1/1000 in the Time object. If you later multiply it again by the exact + * value 1000, the result is unlikely to be 1 exactly. It will be close to + * 1 but not exactly 1. + * + * In general, it is thus a really bad idea to try to use time objects of a + * resolution higher than the global resolution controlled through + * TimeBase::SetResolution. If you do need to use picoseconds, it's thus best + * to switch the global resolution to picoseconds to avoid nasty surprises. + * + * Another important issue to keep in mind is that if you increase the + * global resolution, you also implicitely decrease the range of your simulation. + * i.e., the global simulation time is stored in a 64 bit integer whose interpretation + * will depend on the global resolution so, 2^64 picoseconds which is the maximum + * duration of your simulation if the global resolution is picoseconds + * is smaller than 2^64 nanoseconds which is the maximum duration of your simulation + * if the global resolution is nanoseconds. + * + * Finally, don't even think about ever changing the global resolution after + * creating Time objects: all Time objects created before the call to SetResolution + * will contain values which are not updated to the new resolution. In practice, + * the default value for the attributes of many models is indeed calculated + * before the main function of the main program enters. Because of this, if you + * use one of these models (and it's likely), it's going to be hard to change + * the global simulation resolution in a way which gives reasonable results. This + * issue has been filed as bug 954 in the ns-3 bugzilla installation. + */ +class Time { public: - TimeUnit (); - TimeUnit (TimeUnit const &o); - TimeUnit operator = (TimeUnit const &o); - TimeUnit (HighPrecision data); - /** - * \return true if the time is zero, false otherwise. + * The unit to use to interpret a number representing time */ - bool IsZero (void) const; - /** - * \return true if the time is negative or zero, false otherwise. - */ - bool IsNegative (void) const; - /** - * \return true if the time is positive or zero, false otherwise. - */ - bool IsPositive (void) const; - /** - * \return true if the time is strictly negative, false otherwise. - */ - bool IsStrictlyNegative (void) const; - /** - * \return true if the time is strictly positive, false otherwise. - */ - bool IsStrictlyPositive (void) const; + enum Unit + { + S = 0, + MS = 1, + US = 2, + NS = 3, + PS = 4, + FS = 5, + LAST = 6 + }; - /** - * This is really an internal method exported for the needs of - * the implementation. Please, Do not try to use this method, ever. - * - * \return the ns3::HighPrecision object which holds the value - * stored in this Time type. - */ - HighPrecision const &GetHighPrecision (void) const; - HighPrecision * PeekHighPrecision (void); + inline Time &operator = (const Time &o) + { + m_data = o.m_data; + return *this; + } + inline Time () + : m_data () + {} + inline Time(const Time &o) + : m_data (o.m_data) + {} + explicit inline Time (const HighPrecision &data) + : m_data (data) + {} -private: - HighPrecision m_data; -}; - -template -TimeUnit::TimeUnit () - : m_data () -{ -} -template -TimeUnit::TimeUnit (TimeUnit const &o) - : m_data (o.m_data) -{ -} -template -TimeUnit -TimeUnit::operator = (TimeUnit const &o) -{ - m_data = o.m_data; - return *this; -} -template -TimeUnit::TimeUnit (HighPrecision data) - : m_data (data) -{ -} - -template -HighPrecision const & -TimeUnit::GetHighPrecision (void) const -{ - return m_data; -} -template -HighPrecision * -TimeUnit::PeekHighPrecision (void) -{ - return &m_data; -} -template -bool -TimeUnit::IsZero (void) const -{ - return m_data.Compare (HighPrecision::Zero ()) == 0; -} -template -bool -TimeUnit::IsNegative (void) const -{ - return m_data.Compare (HighPrecision::Zero ()) <= 0; -} -template -bool -TimeUnit::IsPositive (void) const -{ - return m_data.Compare (HighPrecision::Zero ()) >= 0; -} -template -bool -TimeUnit::IsStrictlyNegative (void) const -{ - return m_data.Compare (HighPrecision::Zero ()) < 0; -} -template -bool -TimeUnit::IsStrictlyPositive (void) const -{ - return m_data.Compare (HighPrecision::Zero ()) > 0; -} - -template -bool -operator == (TimeUnit const &lhs, TimeUnit const &rhs) -{ - return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) == 0; -} -template -bool -operator != (TimeUnit const &lhs, TimeUnit const &rhs) -{ - return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) != 0; -} -template -bool -operator <= (TimeUnit const &lhs, TimeUnit const &rhs) -{ - return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) <= 0; -} -template -bool -operator >= (TimeUnit const &lhs, TimeUnit const &rhs) -{ - return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) >= 0; -} -template -bool -operator < (TimeUnit const &lhs, TimeUnit const &rhs) -{ - return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) < 0; -} -template -bool -operator > (TimeUnit const &lhs, TimeUnit const &rhs) -{ - return lhs.GetHighPrecision ().Compare (rhs.GetHighPrecision ()) > 0; -} -template -TimeUnit operator + (TimeUnit const &lhs, TimeUnit const &rhs) -{ - HighPrecision retval = lhs.GetHighPrecision (); - retval.Add (rhs.GetHighPrecision ()); - return TimeUnit (retval); -} -template -TimeUnit operator - (TimeUnit const &lhs, TimeUnit const &rhs) -{ - HighPrecision retval = lhs.GetHighPrecision (); - retval.Sub (rhs.GetHighPrecision ()); - return TimeUnit (retval); -} -template -TimeUnit operator * (TimeUnit const &lhs, TimeUnit const &rhs) -{ - HighPrecision retval = lhs.GetHighPrecision (); - retval.Mul (rhs.GetHighPrecision ()); - return TimeUnit (retval); -} -template -TimeUnit operator / (TimeUnit const &lhs, TimeUnit const &rhs) -{ - NS_ASSERT (rhs.GetHighPrecision ().GetDouble () != 0); - HighPrecision retval = lhs.GetHighPrecision (); - retval.Div (rhs.GetHighPrecision ()); - return TimeUnit (retval); -} -template -TimeUnit &operator += (TimeUnit &lhs, TimeUnit const &rhs) -{ - HighPrecision *lhsv = lhs.PeekHighPrecision (); - lhsv->Add (rhs.GetHighPrecision ()); - return lhs; -} -template -TimeUnit &operator -= (TimeUnit &lhs, TimeUnit const &rhs) -{ - HighPrecision *lhsv = lhs.PeekHighPrecision (); - lhsv->Sub (rhs.GetHighPrecision ()); - return lhs; -} - - -/** - * \anchor ns3-Time-Abs - * \relates ns3::TimeUnit - * \param time the input value - * \returns the absolute value of the input value. - */ -template -TimeUnit Abs (TimeUnit const &time) -{ - return TimeUnit (Abs (time.GetHighPrecision ())); -} -/** - * \anchor ns3-Time-Max - * \relates ns3::TimeUnit - * \param ta the first value - * \param tb the seconds value - * \returns the max of the two input values. - */ -template -TimeUnit Max (TimeUnit const &ta, TimeUnit const &tb) -{ - HighPrecision a = ta.GetHighPrecision (); - HighPrecision b = tb.GetHighPrecision (); - return TimeUnit (Max (a, b)); -} -/** - * \anchor ns3-Time-Min - * \relates ns3::TimeUnit - * \param ta the first value - * \param tb the seconds value - * \returns the min of the two input values. - */ -template -TimeUnit Min (TimeUnit const &ta, TimeUnit const &tb) -{ - HighPrecision a = ta.GetHighPrecision (); - HighPrecision b = tb.GetHighPrecision (); - return TimeUnit (Min (a, b)); -} - -// Explicit instantiation of the TimeUnit template for N=1, with a few -// additional methods that should not be available for N!=1 -// \class TimeUnit<1> - -class TimeValue; - -template <> -class TimeUnit<1> -{ - // -*- New methods -*- -public: /** * \brief String constructor - * Construct TimeUnit<1> object from common time expressions like " + * Construct Time object from common time expressions like " * 1ms" or "10s". Supported units include: * - s (seconds) * - ms (milliseconds) @@ -365,177 +193,378 @@ public: * There can be no white space between the numerical portion * and the units. Any otherwise malformed string causes a fatal error to * occur. - * \param s The string to parse into a TimeUnit<1> + * \param s The string to parse into a Time */ - TimeUnit<1> (const std::string & s); + Time (const std::string & s); + + /** + * \return true if the time is zero, false otherwise. + */ + inline bool IsZero (void) const + { + return m_data.Compare (HighPrecision::Zero ()) == 0; + } + /** + * \return true if the time is negative or zero, false otherwise. + */ + inline bool IsNegative (void) const + { + return m_data.Compare (HighPrecision::Zero ()) <= 0; + } + /** + * \return true if the time is positive or zero, false otherwise. + */ + inline bool IsPositive (void) const + { + return m_data.Compare (HighPrecision::Zero ()) >= 0; + } + /** + * \return true if the time is strictly negative, false otherwise. + */ + inline bool IsStrictlyNegative (void) const + { + return m_data.Compare (HighPrecision::Zero ()) < 0; + } + /** + * \return true if the time is strictly positive, false otherwise. + */ + inline bool IsStrictlyPositive (void) const + { + return m_data.Compare (HighPrecision::Zero ()) > 0; + } + + inline int Compare (const Time &o) const + { + return m_data.Compare (o.m_data); + } + + /** + * This is really an internal method exported for the needs of + * the implementation. Please, Do not try to use this method, ever. + * + * \return the ns3::HighPrecision object which holds the value + * stored in this instance of Time type. + */ + inline HighPrecision const &GetHighPrecision (void) const + { + return m_data; + } + inline HighPrecision *PeekHighPrecision (void) + { + return &m_data; + } + /** * \returns an approximation in seconds of the time stored in this * instance. */ - double GetSeconds (void) const; + inline double GetSeconds (void) const + { + return ToDouble (*this, Time::S); + } /** * \returns an approximation in milliseconds of the time stored in this * instance. */ - int64_t GetMilliSeconds (void) const; + inline int64_t GetMilliSeconds (void) const + { + return ToInteger (*this, Time::MS); + } /** * \returns an approximation in microseconds of the time stored in this * instance. */ - int64_t GetMicroSeconds (void) const; + inline int64_t GetMicroSeconds (void) const + { + return ToInteger (*this, Time::US); + } /** * \returns an approximation in nanoseconds of the time stored in this * instance. */ - int64_t GetNanoSeconds (void) const; + inline int64_t GetNanoSeconds (void) const + { + return ToInteger (*this, Time::NS); + } /** * \returns an approximation in picoseconds of the time stored in this * instance. */ - int64_t GetPicoSeconds (void) const; + inline int64_t GetPicoSeconds (void) const + { + return ToInteger (*this, Time::PS); + } /** * \returns an approximation in femtoseconds of the time stored in this * instance. */ - int64_t GetFemtoSeconds (void) const; + inline int64_t GetFemtoSeconds (void) const + { + return ToInteger (*this, Time::FS); + } /** * \returns an approximation of the time stored in this * instance in the units specified in m_tsPrecision. */ - int64_t GetTimeStep (void) const; - - // -*- The rest is the the same as in the generic template class -*- -public: - TimeUnit () - : m_data () + inline int64_t GetTimeStep (void) const { - } - TimeUnit (TimeUnit const &o) - : m_data (o.m_data) - { - } - TimeUnit operator = (TimeUnit const &o) - { - m_data = o.m_data; - return *this; - } - TimeUnit (HighPrecision data) - : m_data (data) - { - } - bool IsZero (void) const - { - return m_data.Compare (HighPrecision::Zero ()) == 0; - } - bool IsNegative (void) const - { - return m_data.Compare (HighPrecision::Zero ()) <= 0; - } - bool IsPositive (void) const - { - return m_data.Compare (HighPrecision::Zero ()) >= 0; - } - bool IsStrictlyNegative (void) const - { - return m_data.Compare (HighPrecision::Zero ()) < 0; - } - bool IsStrictlyPositive (void) const - { - return m_data.Compare (HighPrecision::Zero ()) > 0; - } - HighPrecision const &GetHighPrecision (void) const - { - return m_data; - } - HighPrecision * PeekHighPrecision (void) - { - return &m_data; + int64_t timeValue = m_data.GetInteger (); + return timeValue; } - static uint64_t UnitsToTimestep (uint64_t unitValue, - uint64_t unitFactor); + + /** + * \param resolution the new resolution to use + * + * Change the global resolution used to convert all + * user-provided time values in Time objects and Time objects + * in user-expected time units. + */ + static void SetResolution (enum Unit resolution); + /** + * \returns the current global resolution. + */ + static enum Unit GetResolution (void); + /** + * \param value to convert into a Time object + * \param timeUnit the unit of the value to convert + * \return a new Time object + * + * This method interprets the input value according to the input + * unit and constructs a matching Time object. + * + * \sa FromDouble, ToDouble, ToInteger + */ + inline static Time FromInteger (uint64_t value, enum Unit timeUnit) + { + struct Information *info = PeekInformation (timeUnit); + if (info->fromMul) + { + value *= info->factor; + return Time (HighPrecision (value, false)); + } + return From (HighPrecision (value, false), timeUnit); + } + /** + * \param value to convert into a Time object + * \param timeUnit the unit of the value to convert + * \return a new Time object + * + * \sa FromInteger, ToInteger, ToDouble + */ + inline static Time FromDouble (double value, enum Unit timeUnit) + { + return From (HighPrecision (value), timeUnit); + } + /** + * \param time a Time object + * \param timeUnit the unit of the value to return + * + * Convert the input time into an integer value according to the requested + * time unit. + */ + inline static uint64_t ToInteger (const Time &time, enum Unit timeUnit) + { + struct Information *info = PeekInformation (timeUnit); + uint64_t v = time.m_data.GetInteger (); + if (info->toMul) + { + v *= info->factor; + } + else + { + v /= info->factor; + } + return v; + } + /** + * \param time a Time object + * \param timeUnit the unit of the value to return + * + * Convert the input time into a floating point value according to the requested + * time unit. + */ + inline static double ToDouble (const Time &time, enum Unit timeUnit) + { + return To (time, timeUnit).GetDouble (); + } private: - HighPrecision m_data; + struct Information + { + bool toMul; + bool fromMul; + uint64_t factor; + HighPrecision timeTo; + HighPrecision timeFrom; + }; + struct Resolution + { + struct Information info[LAST]; + enum Time::Unit unit; + }; - /* - * \Returns the value of time_value in units of unitPrec. time_value - * must be specified in timestep units (which are the same as the - * m_tsPrecision units - */ - int64_t ConvertToUnits (int64_t timeValue, uint64_t unitFactor) const; + static inline struct Resolution *PeekResolution (void) + { + static struct Time::Resolution resolution = GetNsResolution (); + return &resolution; + } + static inline struct Information *PeekInformation (enum Unit timeUnit) + { + return &(PeekResolution ()->info[timeUnit]); + } + static inline Time From (HighPrecision tmp, enum Unit timeUnit) + { + struct Information *info = PeekInformation (timeUnit); + if (info->fromMul) + { + tmp.Mul (info->timeFrom); + } + else + { + tmp.MulByInvert (info->timeFrom); + } + return Time (tmp); + } + static inline HighPrecision To (const Time &time, enum Unit timeUnit) + { + struct Information *info = PeekInformation (timeUnit); + HighPrecision tmp = time.GetHighPrecision (); + if (info->toMul) + { + tmp.Mul (info->timeTo); + } + else + { + tmp.MulByInvert (info->timeTo); + } + return tmp; + } + + static struct Resolution GetNsResolution (void); + static void SetResolution (enum Unit unit, struct Resolution *resolution); + + HighPrecision m_data; }; +inline bool +operator == (Time const &lhs, Time const &rhs) +{ + return lhs.Compare (rhs) == 0; +} +inline bool +operator != (Time const &lhs, Time const &rhs) +{ + return lhs.Compare (rhs) != 0; +} +inline bool +operator <= (Time const &lhs, Time const &rhs) +{ + return lhs.Compare (rhs) <= 0; +} +inline bool +operator >= (Time const &lhs, Time const &rhs) +{ + return lhs.Compare (rhs) >= 0; +} +inline bool +operator < (Time const &lhs, Time const &rhs) +{ + return lhs.Compare (rhs) < 0; +} +inline bool +operator > (Time const &lhs, Time const &rhs) +{ + return lhs.Compare (rhs) > 0; +} +inline Time operator + (Time const &lhs, Time const &rhs) +{ + HighPrecision retval = lhs.GetHighPrecision (); + retval.Add (rhs.GetHighPrecision ()); + return Time (retval); +} +inline Time operator - (Time const &lhs, Time const &rhs) +{ + HighPrecision retval = lhs.GetHighPrecision (); + retval.Sub (rhs.GetHighPrecision ()); + return Time (retval); +} +inline Time operator * (Time const &lhs, Time const &rhs) +{ + HighPrecision retval = lhs.GetHighPrecision (); + retval.Mul (rhs.GetHighPrecision ()); + return Time (retval); +} +inline Time operator / (Time const &lhs, Time const &rhs) +{ + NS_ASSERT (rhs.GetHighPrecision ().GetDouble () != 0); + HighPrecision retval = lhs.GetHighPrecision (); + retval.Div (rhs.GetHighPrecision ()); + return Time (retval); +} +inline Time &operator += (Time &lhs, Time const &rhs) +{ + HighPrecision *lhsv = lhs.PeekHighPrecision (); + lhsv->Add (rhs.GetHighPrecision ()); + return lhs; +} +inline Time &operator -= (Time &lhs, Time const &rhs) +{ + HighPrecision *lhsv = lhs.PeekHighPrecision (); + lhsv->Sub (rhs.GetHighPrecision ()); + return lhs; +} +inline Time &operator *= (Time &lhs, Time const &rhs) +{ + HighPrecision *lhsv = lhs.PeekHighPrecision (); + lhsv->Mul (rhs.GetHighPrecision ()); + return lhs; +} +inline Time &operator /= (Time &lhs, Time const &rhs) +{ + HighPrecision *lhsv = lhs.PeekHighPrecision (); + lhsv->Div (rhs.GetHighPrecision ()); + return lhs; +} + + /** - * \brief keep track of seconds. - * - * This is an instance of type ns3::TimeUnit<1>: it is - * the return value of the ns3::Simulator::Now method - * and is needed for the Simulator::Schedule methods. - * The precision of the underlying Time unit can be - * changed with calls to TimeStepPrecision::Set. - * - * Time instances can be created through any of the following functions: - * - ns3::Seconds - * - ns3::MilliSeconds - * - ns3::MicroSeconds - * - ns3::NanoSeconds - * - ns3::PicoSeconds - * - ns3::FemtoSeconds - * - ns3::Now - * - * Time instances can be added, substracted, multipled and divided using - * the standard C++ operators (if you make sure to obey the rules - * of the ns3::TimeUnit class template) - * To scale a Time instance, you can multiply it with an instance of - * the ns3::Scalar class. - * Time instances can also be manipulated through the following non-member - * functions: - * - \ref ns3-Time-Abs ns3::Abs - * - \ref ns3-Time-Max ns3::Max - * - \ref ns3-Time-Min ns3::Min - * - * The Time class has the following additional methods not available in - * the generic TimeUnit template: - * - * \code - * double GetSeconds (void) const; - * \endcode - * returns an approximation in seconds of the time stored in this - * instance. - * - * \code - * int64_t GetMilliSeconds (void) const; - * \endcode - * returns an approximation in milliseconds of the time stored in this - * instance. - * - * \code - * int64_t GetMicroSeconds (void) const; - * \endcode - * returns an approximation in microseconds of the time stored in this - * instance. - * - * \code - * int64_t GetNanoSeconds (void) const; - * \endcode - * returns an approximation in nanoseconds of the time stored in this - * instance. - * - * \code - * int64_t GetPicoSeconds (void) const; - * \endcode - * returns an approximation in picoseconds of the time stored in this - * instance. - * - * \code - * int64_t GetFemtoSeconds (void) const; - * \endcode - * returns an approximation in femtoseconds of the time stored in this - * instance. + * \anchor ns3-Time-Abs + * \relates ns3::TimeUnit + * \param time the input value + * \returns the absolute value of the input value. */ -typedef TimeUnit<1> Time; +inline Time Abs (Time const &time) +{ + return Time (Abs (time.GetHighPrecision ())); +} +/** + * \anchor ns3-Time-Max + * \relates ns3::TimeUnit + * \param ta the first value + * \param tb the seconds value + * \returns the max of the two input values. + */ +inline Time Max (Time const &ta, Time const &tb) +{ + HighPrecision a = ta.GetHighPrecision (); + HighPrecision b = tb.GetHighPrecision (); + return Time (Max (a, b)); +} +/** + * \anchor ns3-Time-Min + * \relates ns3::TimeUnit + * \param ta the first value + * \param tb the seconds value + * \returns the min of the two input values. + */ +inline Time Min (Time const &ta, Time const &tb) +{ + HighPrecision a = ta.GetHighPrecision (); + HighPrecision b = tb.GetHighPrecision (); + return Time (Min (a, b)); +} std::ostream& operator<< (std::ostream& os, const Time & time); @@ -551,7 +580,10 @@ std::istream& operator>> (std::istream& is, Time & time); * \endcode * \param seconds seconds value */ -Time Seconds (double seconds); +inline Time Seconds (double seconds) +{ + return Time::FromDouble (seconds, Time::S); +} /** * \brief create ns3::Time instances in units of milliseconds. @@ -563,7 +595,10 @@ Time Seconds (double seconds); * \endcode * \param ms milliseconds value */ -Time MilliSeconds (uint64_t ms); +inline Time MilliSeconds (uint64_t ms) +{ + return Time::FromInteger (ms, Time::MS); +} /** * \brief create ns3::Time instances in units of microseconds. * @@ -574,7 +609,10 @@ Time MilliSeconds (uint64_t ms); * \endcode * \param us microseconds value */ -Time MicroSeconds (uint64_t us); +inline Time MicroSeconds (uint64_t us) +{ + return Time::FromInteger (us, Time::US); +} /** * \brief create ns3::Time instances in units of nanoseconds. * @@ -585,7 +623,10 @@ Time MicroSeconds (uint64_t us); * \endcode * \param ns nanoseconds value */ -Time NanoSeconds (uint64_t ns); +inline Time NanoSeconds (uint64_t ns) +{ + return Time::FromInteger (ns, Time::NS); +} /** * \brief create ns3::Time instances in units of picoseconds. * @@ -596,7 +637,10 @@ Time NanoSeconds (uint64_t ns); * \endcode * \param ps picoseconds value */ -Time PicoSeconds (uint64_t ps); +inline Time PicoSeconds (uint64_t ps) +{ + return Time::FromInteger (ps, Time::PS); +} /** * \brief create ns3::Time instances in units of femtoseconds. * @@ -607,104 +651,55 @@ Time PicoSeconds (uint64_t ps); * \endcode * \param fs femtoseconds value */ -Time FemtoSeconds (uint64_t fs); +inline Time FemtoSeconds (uint64_t fs) +{ + return Time::FromInteger (fs, Time::FS); +} // internal function not publicly documented -Time TimeStep (uint64_t ts); - -// Explicit instantiation of the TimeUnit template for N=0, with a few -// additional methods that should not be available for N != 0 -template <> -class TimeUnit<0> +inline Time TimeStep (uint64_t ts) { - // -*- New methods -*- -public: - double GetDouble (void) const; - TimeUnit<0> (double scalar); + return Time (HighPrecision (ts, false)); +} - // -*- The rest is the the same as in the generic template class -*- +class Scalar +{ public: - TimeUnit () - : m_data () + inline Scalar () + : m_v (0.0) + {} + explicit inline Scalar (double v) + : m_v (v) + {} + explicit inline Scalar (uint32_t v) + : m_v (v) + {} + explicit inline Scalar (int32_t v) + : m_v (v) + {} + explicit inline Scalar (uint64_t v) + : m_v (v) + {} + explicit inline Scalar (int64_t v) + : m_v (v) + {} + inline Scalar (Time t) + : m_v (t.GetHighPrecision ().GetDouble ()) + {} + inline operator Time () { + return Time (HighPrecision (m_v)); } - TimeUnit (TimeUnit const &o) - : m_data (o.m_data) + inline double GetDouble (void) const { + return m_v; } - TimeUnit operator = (TimeUnit const &o) - { - m_data = o.m_data; - return *this; - } - TimeUnit (HighPrecision data) - : m_data (data) - { - } - bool IsZero (void) const - { - return m_data.Compare (HighPrecision::Zero ()) == 0; - } - bool IsNegative (void) const - { - return m_data.Compare (HighPrecision::Zero ()) <= 0; - } - bool IsPositive (void) const - { - return m_data.Compare (HighPrecision::Zero ()) >= 0; - } - bool IsStrictlyNegative (void) const - { - return m_data.Compare (HighPrecision::Zero ()) < 0; - } - bool IsStrictlyPositive (void) const - { - return m_data.Compare (HighPrecision::Zero ()) > 0; - } - HighPrecision const &GetHighPrecision (void) const - { - return m_data; - } - HighPrecision * PeekHighPrecision (void) - { - return &m_data; - } - private: - HighPrecision m_data; + double m_v; }; -/** - * \brief hold scalar values - * - * This class is used both to construct scalar values to multiply - * ns3::Time instances and to hold the return value of - * an expression which returns a scalar. For example, the - * following code will output on your terminal 1.5: - * \code - * Scalar s0 = Scalar (1.5); - * Time t1 = Seconds (10.0) * s0; - * Time t2 = Seconds (10.0) * Scalar (2.5); - * Scalar s1 = Seconds (15.0) / Seconds (10.0); - * std::cout << s1.GetDouble () << std::endl; - * \endcode - * - * The Scalar class has the following additional methods not available in - * the generic TimeUnit template: - * \code - * double GetDouble (void) const; - * \endcode - * returns the C double contained in the Scalar instance - * - * \code - * Scalar(double scalar); - * \endcode - * Constructs a Scalar instance from a C double. - */ -typedef TimeUnit<0> Scalar; - -typedef TimeUnit<-1> TimeInvert; -typedef TimeUnit<2> TimeSquare; +typedef Time TimeInvert; +typedef Time TimeSquare; /** * \class ns3::TimeValue @@ -712,8 +707,8 @@ typedef TimeUnit<2> TimeSquare; */ -ATTRIBUTE_ACCESSOR_DEFINE (Time); ATTRIBUTE_VALUE_DEFINE (Time); +ATTRIBUTE_ACCESSOR_DEFINE (Time); ATTRIBUTE_CHECKER_DEFINE (Time); } // namespace ns3 diff --git a/src/simulator/realtime-simulator-impl.cc b/src/simulator/realtime-simulator-impl.cc index 0e63f4e0f..ed192480c 100644 --- a/src/simulator/realtime-simulator-impl.cc +++ b/src/simulator/realtime-simulator-impl.cc @@ -45,7 +45,7 @@ TypeId RealtimeSimulatorImpl::GetTypeId (void) { static TypeId tid = TypeId ("ns3::RealtimeSimulatorImpl") - .SetParent () + .SetParent () .AddConstructor () .AddAttribute ("SynchronizationMode", "What to do if the simulation cannot keep up with real time.", diff --git a/src/simulator/simulator-impl.cc b/src/simulator/simulator-impl.cc new file mode 100644 index 000000000..f65ccfd19 --- /dev/null +++ b/src/simulator/simulator-impl.cc @@ -0,0 +1,14 @@ +#include "simulator-impl.h" + +namespace ns3 { + +TypeId +SimulatorImpl::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SimulatorImpl") + .SetParent () + ; + return tid; +} + +} // namespace ns3 diff --git a/src/simulator/simulator-impl.h b/src/simulator/simulator-impl.h index 74f297aea..063a9deb5 100644 --- a/src/simulator/simulator-impl.h +++ b/src/simulator/simulator-impl.h @@ -35,6 +35,8 @@ class Scheduler; class SimulatorImpl : public Object { public: + static TypeId GetTypeId (void); + /** * Every event scheduled by the Simulator::insertAtDestroy method is * invoked. Then, we ensure that any memory allocated by the diff --git a/src/simulator/synchronizer.cc b/src/simulator/synchronizer.cc index 765ed98ab..a28758191 100644 --- a/src/simulator/synchronizer.cc +++ b/src/simulator/synchronizer.cc @@ -112,49 +112,15 @@ Synchronizer::EventEnd (void) uint64_t Synchronizer::TimeStepToNanosecond (uint64_t ts) { - switch (TimeStepPrecision::Get ()) { - case TimeStepPrecision::S: - return ts * 1000000000; - case TimeStepPrecision::MS: - return ts * 1000000; - case TimeStepPrecision::US: - return ts * 1000; - case TimeStepPrecision::NS: - return ts; - case TimeStepPrecision::PS: - return ts / 1000; - case TimeStepPrecision::FS: - return ts / 1000000; - default: - NS_ASSERT_MSG (false, "Synchronizer::TimeStepToNanosecond: " - "Unexpected precision not implemented"); - return 0; - } + return TimeStep (ts).GetNanoSeconds (); } uint64_t Synchronizer::NanosecondToTimeStep (uint64_t ns) { - switch (TimeStepPrecision::Get ()) { - case TimeStepPrecision::S: - return ns / 1000000000; - case TimeStepPrecision::MS: - return ns / 1000000; - case TimeStepPrecision::US: - return ns / 1000; - case TimeStepPrecision::NS: - return ns; - case TimeStepPrecision::PS: - return ns * 1000; - case TimeStepPrecision::FS: - return ns * 1000000; - default: - NS_ASSERT_MSG (false, "Synchronizer::NanosecondToTimeStep: " - "Unexpected precision not implemented"); - return 0; - } + return NanoSeconds (ns).GetTimeStep (); } -}; // namespace ns3 +} // namespace ns3 diff --git a/src/simulator/time-base.cc b/src/simulator/time-base.cc new file mode 100644 index 000000000..10a9d7a92 --- /dev/null +++ b/src/simulator/time-base.cc @@ -0,0 +1,59 @@ +#include "time-base.h" +#include "ns3/assert.h" + +namespace ns3 { + +struct TimeBase::Resolution +TimeBase::GetNsResolution (void) +{ + struct Resolution resolution; + SetResolution (TimeBase::NS, &resolution); + return resolution; +} +void +TimeBase::SetResolution (enum Unit resolution) +{ + SetResolution (resolution, PeekResolution ()); +} +void +TimeBase::SetResolution (enum Unit unit, struct Resolution *resolution) +{ + int8_t power [LAST] = {15, 12, 9, 6, 3, 0}; + for (int i = 0; i < TimeBase::LAST; i++) + { + int shift = power[i] - power[(int)unit]; + uint64_t factor = (uint64_t) pow (10, fabs (shift)); + struct Information *info = &resolution->info[i]; + info->factor = factor; + if (shift == 0) + { + info->timeFrom = HighPrecision (1, false); + info->timeTo = HighPrecision (1, false); + info->toMul = true; + info->fromMul = true; + } + else if (shift > 0) + { + info->timeFrom = HighPrecision (factor, false); + info->timeTo = HighPrecision::Invert (factor); + info->toMul = false; + info->fromMul = true; + } + else + { + NS_ASSERT (shift < 0); + info->timeFrom = HighPrecision::Invert (factor); + info->timeTo = HighPrecision (factor, false); + info->toMul = true; + info->fromMul = false; + } + } + resolution->unit = unit; +} +enum TimeBase::Unit +TimeBase::GetResolution (void) +{ + return PeekResolution ()->unit; +} + +} // namespace ns3 diff --git a/src/simulator/time-base.h b/src/simulator/time-base.h new file mode 100644 index 000000000..f8440eade --- /dev/null +++ b/src/simulator/time-base.h @@ -0,0 +1,336 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef TIME_BASE_H +#define TIME_BASE_H + +#include "high-precision.h" + +namespace ns3 { + +/** + * \ingroup time + * \brief keep track of global simulation resolution + * + * This class is the base class for all time-related classes. It controls + * the resolution of the underlying time value . The default resolution + * is nanoseconds. That is, TimeStep (1).GetNanoSeconds () will return + * 1. It is possible to either increase or decrease the resolution and the + * code tries really hard to make this easy. + * + * If your resolution is X (say, nanoseconds) and if you create Time objects + * with a lower resolution (say, picoseconds), don't expect that this + * code will return 1: PicoSeconds (1).GetPicoSeconds (). It will most + * likely return 0 because the Time object has only 64 bits of fractional + * precision which means that PicoSeconds (1) is stored as a 64-bit aproximation + * of 1/1000 in the Time object. If you later multiply it again by the exact + * value 1000, the result is unlikely to be 1 exactly. It will be close to + * 1 but not exactly 1. + * + * In general, it is thus a really bad idea to try to use time objects of a + * resolution higher than the global resolution controlled through + * TimeBase::SetResolution. If you do need to use picoseconds, it's thus best + * to switch the global resolution to picoseconds to avoid nasty surprises. + * + * Another important issue to keep in mind is that if you increase the + * global resolution, you also implicitely decrease the range of your simulation. + * i.e., the global simulation time is stored in a 64 bit integer whose interpretation + * will depend on the global resolution so, 2^64 picoseconds which is the maximum + * duration of your simulation if the global resolution is picoseconds + * is smaller than 2^64 nanoseconds which is the maximum duration of your simulation + * if the global resolution is nanoseconds. + * + * Finally, don't even think about ever changing the global resolution after + * creating Time objects: all Time objects created before the call to SetResolution + * will contain values which are not updated to the new resolution. In practice, + * the default value for the attributes of many models is indeed calculated + * before the main function of the main program enters. Because of this, if you + * use one of these models (and it's likely), it's going to be hard to change + * the global simulation resolution in a way which gives reasonable results. This + * issue has been filed as bug 954 in the ns-3 bugzilla installation. + */ +class TimeBase +{ +public: + /** + * The unit to use to interpret a number representing time + */ + enum Unit + { + S = 0, + MS = 1, + US = 2, + NS = 3, + PS = 4, + FS = 5, + LAST = 6 + }; + /** + * \param resolution the new resolution to use + * + * Change the global resolution used to convert all + * user-provided time values in Time objects and Time objects + * in user-expected time units. + */ + static void SetResolution (enum Unit resolution); + /** + * \returns the current global resolution. + */ + static enum Unit GetResolution (void); + /** + * \param value to convert into a Time object + * \param timeUnit the unit of the value to convert + * \return a new Time object + * + * This method interprets the input value according to the input + * unit and constructs a matching Time object. + * + * \sa FromDouble, ToDouble, ToInteger + */ + inline static TimeBase FromInteger (uint64_t value, enum Unit timeUnit); + /** + * \param value to convert into a Time object + * \param timeUnit the unit of the value to convert + * \return a new Time object + * + * \sa FromInteger, ToInteger, ToDouble + */ + inline static TimeBase FromDouble (double value, enum Unit timeUnit); + /** + * \param time a Time object + * \param timeUnit the unit of the value to return + * + * Convert the input time into an integer value according to the requested + * time unit. + */ + inline static uint64_t ToInteger (const TimeBase &time, enum Unit timeUnit); + /** + * \param time a Time object + * \param timeUnit the unit of the value to return + * + * Convert the input time into a floating point value according to the requested + * time unit. + */ + inline static double ToDouble (const TimeBase &time, enum Unit timeUnit); + + inline TimeBase (); + inline TimeBase (const TimeBase &o); + inline TimeBase operator = (const TimeBase &o); + inline TimeBase (const HighPrecision &data); + /** + * \return true if the time is zero, false otherwise. + */ + inline bool IsZero (void) const; + /** + * \return true if the time is negative or zero, false otherwise. + */ + inline bool IsNegative (void) const; + /** + * \return true if the time is positive or zero, false otherwise. + */ + inline bool IsPositive (void) const; + /** + * \return true if the time is strictly negative, false otherwise. + */ + inline bool IsStrictlyNegative (void) const; + /** + * \return true if the time is strictly positive, false otherwise. + */ + inline bool IsStrictlyPositive (void) const; + + /** + * This is really an internal method exported for the needs of + * the implementation. Please, Do not try to use this method, ever. + * + * \return the ns3::HighPrecision object which holds the value + * stored in this instance of Time type. + */ + inline HighPrecision const &GetHighPrecision (void) const; + inline HighPrecision * PeekHighPrecision (void); + +protected: + HighPrecision m_data; +private: + struct Information + { + bool toMul; + bool fromMul; + uint64_t factor; + HighPrecision timeTo; + HighPrecision timeFrom; + }; + struct Resolution + { + struct Information info[LAST]; + enum TimeBase::Unit unit; + }; + + inline static struct Resolution *PeekResolution (void); + inline static struct Information *PeekInformation (enum Unit timeUnit); + static struct Resolution GetNsResolution (void); + static void SetResolution (enum Unit unit, struct Resolution *resolution); + inline static TimeBase From (HighPrecision tmp, enum Unit timeUnit); + inline static HighPrecision To (const TimeBase &time, enum Unit timeUnit); +}; + +} // namespace ns3 + +namespace ns3 { + +TimeBase::TimeBase () + : m_data () +{ +} +TimeBase::TimeBase (const TimeBase &o) + : m_data (o.m_data) +{ +} +TimeBase TimeBase::operator = (const TimeBase &o) +{ + m_data = o.m_data; + return *this; +} +TimeBase::TimeBase (const HighPrecision &data) + : m_data (data) +{ +} + +HighPrecision const & +TimeBase::GetHighPrecision (void) const +{ + return m_data; +} + +HighPrecision * +TimeBase::PeekHighPrecision (void) +{ + return &m_data; +} + +bool +TimeBase::IsZero (void) const +{ + return m_data.Compare (HighPrecision::Zero ()) == 0; +} + +bool +TimeBase::IsNegative (void) const +{ + return m_data.Compare (HighPrecision::Zero ()) <= 0; +} + +bool +TimeBase::IsPositive (void) const +{ + return m_data.Compare (HighPrecision::Zero ()) >= 0; +} + +bool +TimeBase::IsStrictlyNegative (void) const +{ + return m_data.Compare (HighPrecision::Zero ()) < 0; +} + +bool +TimeBase::IsStrictlyPositive (void) const +{ + return m_data.Compare (HighPrecision::Zero ()) > 0; +} + +struct TimeBase::Resolution * +TimeBase::PeekResolution (void) +{ + static struct TimeBase::Resolution resolution = GetNsResolution (); + return &resolution; +} +struct TimeBase::Information * +TimeBase::PeekInformation (enum Unit timeUnit) +{ + return &(PeekResolution ()->info[timeUnit]); +} +TimeBase +TimeBase::From (HighPrecision tmp, enum Unit timeUnit) +{ + struct Information *info = PeekInformation (timeUnit); + if (info->fromMul) + { + tmp.Mul (info->timeFrom); + } + else + { + tmp.MulByInvert (info->timeFrom); + } + return TimeBase (tmp); +} +HighPrecision +TimeBase::To (const TimeBase &time, enum Unit timeUnit) +{ + struct Information *info = PeekInformation (timeUnit); + HighPrecision tmp = time.GetHighPrecision (); + if (info->toMul) + { + tmp.Mul (info->timeTo); + } + else + { + tmp.MulByInvert (info->timeTo); + } + return tmp; +} + +TimeBase +TimeBase::FromInteger (uint64_t value, enum Unit timeUnit) +{ + struct Information *info = PeekInformation (timeUnit); + if (info->fromMul) + { + value *= info->factor; + return TimeBase (HighPrecision (value, false)); + } + return From (HighPrecision (value, false), timeUnit); +} +TimeBase +TimeBase::FromDouble (double value, enum Unit timeUnit) +{ + return From (HighPrecision (value), timeUnit); +} +uint64_t +TimeBase::ToInteger (const TimeBase &time, enum Unit timeUnit) +{ + struct Information *info = PeekInformation (timeUnit); + uint64_t v = time.m_data.GetInteger (); + if (info->toMul) + { + v *= info->factor; + } + else + { + v /= info->factor; + } + return v; +} +double +TimeBase::ToDouble (const TimeBase &time, enum Unit timeUnit) +{ + return To (time, timeUnit).GetDouble (); +} + +} // namespace ns3 + +#endif /* TIME_BASE_H */ diff --git a/src/simulator/time.cc b/src/simulator/time.cc index a0af0c42d..1fb68105d 100644 --- a/src/simulator/time.cc +++ b/src/simulator/time.cc @@ -20,54 +20,18 @@ * TimeStep support by Emmanuelle Laprise */ #include "nstime.h" -#include "ns3/fatal-error.h" +#include "ns3/abort.h" #include "ns3/global-value.h" #include "ns3/enum.h" #include "ns3/string.h" #include "ns3/object.h" #include "ns3/config.h" #include +#include namespace ns3 { -namespace TimeStepPrecision { - -static const uint64_t MS_FACTOR = (uint64_t)1000; -static const uint64_t US_FACTOR = (uint64_t)1000000; -static const uint64_t NS_FACTOR = (uint64_t)1000000 * (uint64_t)1000; -static const uint64_t PS_FACTOR = (uint64_t)1000000 * (uint64_t)1000000; -static const uint64_t FS_FACTOR = (uint64_t)1000000 * (uint64_t)1000000 * (uint64_t)1000; -static uint64_t g_tsPrecFactor = NS_FACTOR; - -static GlobalValue g_precisionDefaultValue ("TimeStepPrecision", - "The time unit of the internal 64 bit integer time.", - EnumValue (NS), - MakeEnumChecker (NS, "NS", - S, "S", - MS, "MS", - US, "US", - PS, "PS", - FS, "FS") - ); - -precision_t -Get (void) -{ - EnumValue v; - g_precisionDefaultValue.GetValue (v); - return (precision_t) v.Get (); -} - -void -Set (precision_t precision) -{ - g_precisionDefaultValue.SetValue (EnumValue (precision)); - g_tsPrecFactor = (uint64_t)pow (10, precision); -} - -} // namespace TimeStepPrecision - -TimeUnit<1>::TimeUnit (const std::string& s) +Time::Time (const std::string& s) { std::string::size_type n = s.find_first_not_of ("0123456789."); if (n != std::string::npos) @@ -79,40 +43,35 @@ TimeUnit<1>::TimeUnit (const std::string& s) std::string trailer = s.substr (n, std::string::npos); if (trailer == std::string ("s")) { - m_data = HighPrecision (r * TimeStepPrecision::g_tsPrecFactor); + *this = Time::FromDouble (r, Time::S); return; } if (trailer == std::string ("ms")) { - m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,3))), - false); + *this = Time::FromDouble (r, Time::MS); return; } if (trailer == std::string ("us")) { - m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,6))), - false); + *this = Time::FromDouble (r, Time::US); return; } if (trailer == std::string ("ns")) { - m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,9))), - false); + *this = Time::FromDouble (r, Time::NS); return; } if (trailer == std::string ("ps")) { - m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,12))), - false); + *this = Time::FromDouble (r, Time::PS); return; } if (trailer == std::string ("fs")) { - m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,15))), - false); + *this = Time::FromDouble (r, Time::FS); return; } - NS_FATAL_ERROR ("Can't Parse Time " << s); + NS_ABORT_MSG ("Can't Parse Time " << s); } // else // they didn't provide units, assume seconds @@ -120,84 +79,60 @@ TimeUnit<1>::TimeUnit (const std::string& s) iss.str (s); double v; iss >> v; - m_data = HighPrecision (v * TimeStepPrecision::g_tsPrecFactor); + *this = Time::FromDouble (v, Time::S); } -double -TimeUnit<1>::GetSeconds (void) const -{ - double timeValue = GetHighPrecision ().GetDouble (); - return timeValue / TimeStepPrecision::g_tsPrecFactor; +struct Time::Resolution +Time::GetNsResolution (void) +{ + struct Resolution resolution; + SetResolution (Time::NS, &resolution); + return resolution; } - -int64_t -TimeUnit<1>::ConvertToUnits (int64_t timeValue, uint64_t unitFactor) const +void +Time::SetResolution (enum Unit resolution) { - uint64_t precFactor; - // In order to avoid conversion to double, precFactor can't be less 1 - if (TimeStepPrecision::g_tsPrecFactor < unitFactor) + SetResolution (resolution, PeekResolution ()); +} +void +Time::SetResolution (enum Unit unit, struct Resolution *resolution) +{ + int8_t power [LAST] = {15, 12, 9, 6, 3, 0}; + for (int i = 0; i < Time::LAST; i++) { - precFactor = unitFactor / TimeStepPrecision::g_tsPrecFactor; - timeValue = timeValue * precFactor; + int shift = power[i] - power[(int)unit]; + uint64_t factor = (uint64_t) pow (10, fabs (shift)); + struct Information *info = &resolution->info[i]; + info->factor = factor; + if (shift == 0) + { + info->timeFrom = HighPrecision (1, false); + info->timeTo = HighPrecision (1, false); + info->toMul = true; + info->fromMul = true; + } + else if (shift > 0) + { + info->timeFrom = HighPrecision (factor, false); + info->timeTo = HighPrecision::Invert (factor); + info->toMul = false; + info->fromMul = true; + } + else + { + NS_ASSERT (shift < 0); + info->timeFrom = HighPrecision::Invert (factor); + info->timeTo = HighPrecision (factor, false); + info->toMul = true; + info->fromMul = false; + } } - else - { - precFactor = TimeStepPrecision::g_tsPrecFactor / unitFactor; - timeValue = timeValue / precFactor; - } - return timeValue; + resolution->unit = unit; } - - -int64_t -TimeUnit<1>::GetMilliSeconds (void) const +enum Time::Unit +Time::GetResolution (void) { - int64_t ts = GetTimeStep (); - int64_t ms = ConvertToUnits (ts, TimeStepPrecision::MS_FACTOR); - - return ms; -} -int64_t -TimeUnit<1>::GetMicroSeconds (void) const -{ - int64_t ts = GetTimeStep (); - int64_t us = ConvertToUnits (ts, TimeStepPrecision::US_FACTOR); - - return us; -} -int64_t -TimeUnit<1>::GetNanoSeconds (void) const -{ - int64_t ts = GetTimeStep (); - int64_t ns = ConvertToUnits (ts, TimeStepPrecision::NS_FACTOR); - - return ns; -} -int64_t -TimeUnit<1>::GetPicoSeconds (void) const -{ - int64_t ts = GetTimeStep (); - int64_t ps = ConvertToUnits (ts, TimeStepPrecision::PS_FACTOR); - - return ps; -} -int64_t -TimeUnit<1>::GetFemtoSeconds (void) const -{ - int64_t ts = GetTimeStep (); - int64_t fs = ConvertToUnits (ts, TimeStepPrecision::FS_FACTOR); - - return fs; -} - -/** - * This returns the value with the precision returned by TimeStepPrecision::Get - */ -int64_t -TimeUnit<1>::GetTimeStep (void) const -{ - int64_t timeValue = GetHighPrecision ().GetInteger (); - return timeValue; + return PeekResolution ()->unit; } @@ -205,491 +140,52 @@ std::ostream& operator<< (std::ostream& os, const Time & time) { std::string unit; - switch (TimeStepPrecision::Get ()) + switch (Time::GetResolution ()) { - case TimeStepPrecision::S: + case Time::S: unit = "s"; break; - case TimeStepPrecision::MS: + case Time::MS: unit = "ms"; break; - case TimeStepPrecision::US: + case Time::US: unit = "us"; break; - case TimeStepPrecision::NS: + case Time::NS: unit = "ns"; break; - case TimeStepPrecision::PS: + case Time::PS: unit = "ps"; break; - case TimeStepPrecision::FS: + case Time::FS: unit = "fs"; break; + case Time::LAST: + NS_ABORT_MSG ("can't be reached"); + unit = "unreachable"; + break; } - os << time.GetTimeStep () << unit; + double v = Time::ToDouble (time, Time::GetResolution ()); + os << v << unit; return os; } std::istream& operator>> (std::istream& is, Time & time) { std::string value; is >> value; - std::string::size_type n = value.find_first_not_of ("0123456789."); - if (n == std::string::npos) - { - is.setstate (std::ios_base::failbit); - return is; - } - std::string trailer = value.substr (n, value.size () - n); - std::istringstream iss; - iss.str (value.substr (0, n)); - - if (trailer == std::string ("s")) - { - double v; - iss >> v; - time = Seconds (v); - return is; - } - uint64_t integer; - iss >> integer; - if (is.bad () || is.fail ()) - { - is.setstate (std::ios_base::failbit); - } - else if (trailer == std::string ("ms")) - { - time = MilliSeconds (integer); - } - else if (trailer == std::string ("us")) - { - time = MicroSeconds (integer); - } - else if (trailer == std::string ("ns")) - { - time = NanoSeconds (integer); - } - else if (trailer == std::string ("ps")) - { - time = PicoSeconds (integer); - } - else if (trailer == std::string ("fs")) - { - time = FemtoSeconds (integer); - } - else - { - is.setstate (std::ios_base::failbit); - } + time = Time (value); return is; } -Time Seconds (double seconds) -{ - double d_sec = seconds * TimeStepPrecision::g_tsPrecFactor; - return Time (HighPrecision (d_sec)); - // return Time (HighPrecision ((int64_t)d_sec, false)); -} - -uint64_t -TimeUnit<1>::UnitsToTimestep (uint64_t unitValue, - uint64_t unitFactor) -{ - uint64_t precFactor; - // In order to avoid conversion to double, precFactor can't be less 1 - if (TimeStepPrecision::g_tsPrecFactor < unitFactor) - { - precFactor = unitFactor / TimeStepPrecision::g_tsPrecFactor; - unitValue = unitValue / precFactor; - } - else - { - precFactor = TimeStepPrecision::g_tsPrecFactor / unitFactor; - unitValue = unitValue * precFactor; - } - return unitValue; -} - ATTRIBUTE_VALUE_IMPLEMENT (Time); ATTRIBUTE_CHECKER_IMPLEMENT (Time); -Time MilliSeconds (uint64_t ms) -{ - uint64_t ts = TimeUnit<1>::UnitsToTimestep (ms, TimeStepPrecision::MS_FACTOR); - return TimeStep (ts); -} - -Time MicroSeconds (uint64_t us) -{ - uint64_t ts = TimeUnit<1>::UnitsToTimestep (us, TimeStepPrecision::US_FACTOR); - return TimeStep (ts); -} - -Time NanoSeconds (uint64_t ns) -{ - uint64_t ts = TimeUnit<1>::UnitsToTimestep (ns, TimeStepPrecision::NS_FACTOR); - return TimeStep (ts); -} -Time PicoSeconds (uint64_t ps) -{ - uint64_t ts = TimeUnit<1>::UnitsToTimestep (ps, TimeStepPrecision::PS_FACTOR); - return TimeStep (ts); -} -Time FemtoSeconds (uint64_t fs) -{ - uint64_t ts = TimeUnit<1>::UnitsToTimestep (fs, TimeStepPrecision::FS_FACTOR); - return TimeStep (ts); -} - - -/* - * The timestep value passed to this function must be of the precision - * of TimeStepPrecision::Get - */ -Time TimeStep (uint64_t ts) -{ - return Time (HighPrecision (ts, false)); -} - -TimeUnit<0>::TimeUnit (double scalar) - : m_data (HighPrecision (scalar)) -{ -} - -double -TimeUnit<0>::GetDouble (void) const -{ - return GetHighPrecision ().GetDouble (); -} - } // namespace ns3 #include "ns3/test.h" namespace ns3 { -#define PRECISION(mult) (pow (10,-((double)(ns3::TimeStepPrecision::Get ()))) * mult) -#define ASSERT_MSG_EQ(a,b,mult,msg) \ - NS_TEST_ASSERT_MSG_EQ (((a) < ((b) - PRECISION (mult)) || (a) > ((b) + PRECISION (mult))),false, \ - msg << " Values are not equal within requested precision range: " << \ - (a) << "!=" << (b) << " ~ " << PRECISION (mult)) -#define ASSERT_MSG_EQ_INT(a,b,mult,msg) \ - ASSERT_MSG_EQ (((int64_t)(a)),((int64_t)(b)),mult,msg) -#define ASSERT_EQ(a,b) \ - ASSERT_MSG_EQ (a,b,1,"") - -class OldTimeTestCase : public TestCase -{ -public: - OldTimeTestCase (); - virtual bool DoRun (void); -}; - -OldTimeTestCase::OldTimeTestCase () - : TestCase ("Sanity check of common time operations") -{ -} -bool -OldTimeTestCase::DoRun (void) -{ - NS_TEST_ASSERT_MSG_EQ (TimeStepPrecision::Get (), - TimeStepPrecision::NS, - "Invalid precision mode"); - - Time t0 = Seconds (10.0); - ASSERT_EQ (t0.GetSeconds (), 10.0); - - Time t1 = Seconds (11.0); - ASSERT_EQ (t1.GetSeconds (), 11.0); - - t0 = Seconds (1.5); - ASSERT_EQ (t0.GetSeconds (), 1.5); - - t0 = Seconds (-1.5); - ASSERT_EQ (t0.GetSeconds (), -1.5); - - t0 = MilliSeconds ((uint64_t)10.0); - ASSERT_EQ (t0.GetSeconds (), 0.01); - - t1 = MilliSeconds ((uint64_t)11.0); - ASSERT_EQ (t1.GetSeconds (), 0.011); - - - Time t2, t3; - - t2 = t1 - t0; - NS_TEST_ASSERT_MSG_EQ (t2.IsStrictlyPositive (),true, "Variable should be positive"); - ASSERT_EQ (t2.GetSeconds (), t1.GetSeconds () - t0.GetSeconds ()); - - t2 = t1 - t1; - NS_TEST_ASSERT_MSG_EQ (t2.IsZero (),true, "Variable should be zero"); - ASSERT_EQ (t2.GetSeconds (), t1.GetSeconds () - t1.GetSeconds ()); - - t2 = t0 - t1; - NS_TEST_ASSERT_MSG_EQ (t2.IsStrictlyNegative (),true, "Variable should be negative"); - ASSERT_EQ (t2.GetSeconds (), t0.GetSeconds () - t1.GetSeconds ()); - - Time tmp = MilliSeconds (0); - NS_TEST_ASSERT_MSG_EQ ((MilliSeconds (0) == NanoSeconds (0)), true, "Zero is not Zero ?"); - NS_TEST_ASSERT_MSG_EQ ((MilliSeconds (0) > NanoSeconds (0)), false, "Zero is bigger than Zero ?"); - NS_TEST_ASSERT_MSG_EQ ((MilliSeconds (0) < NanoSeconds (0)), false, "Zero is smaller than Zero ?"); - - Time t4 = Seconds (10.0) * Scalar (1.5); - ASSERT_EQ (t4.GetSeconds (), 15.0); - - Time t5 = NanoSeconds (10) * Scalar (1.5); - ASSERT_EQ (t5.GetNanoSeconds (), 15.0); - - Time t6 = Seconds (10.0) * Scalar (15) / Scalar (10); - ASSERT_EQ (t6.GetSeconds (), 15.0); - - Time t7 = NanoSeconds (10) * Scalar (15) / Scalar (10); - ASSERT_EQ (t7.GetNanoSeconds (), 15.0); - - ASSERT_EQ ((t1 + t2).GetSeconds (), t1.GetSeconds () + t2.GetSeconds ()); - - ASSERT_EQ ((t1 / t2).GetDouble (), t1.GetSeconds () / t2.GetSeconds ()); - - return false; -} - -class OperationsTimeTestCase : public TestCase -{ -public: - OperationsTimeTestCase (); - virtual bool DoRun (void); -}; - -OperationsTimeTestCase::OperationsTimeTestCase () - : TestCase ("Check the +, -, * and / operators for the TimeUnit<1>") -{ -} - -bool -OperationsTimeTestCase::DoRun (void) -{ - // What happens if you set these values ? - // t0 = Seconds ((uint64_t)10.0); - // t1 = Seconds ((uint64_t)11.0); - - Time t0 = MilliSeconds (10); - Time t1 = MilliSeconds (11); - - ASSERT_EQ ((t0 - t1).GetSeconds (), - (t0.GetSeconds () - t1.GetSeconds ())); - ASSERT_EQ (((t0 - t1) * t0 / t0).GetSeconds (), - ((t0.GetSeconds () - t1.GetSeconds ()) * t0.GetSeconds () / t0.GetSeconds ())); - ASSERT_EQ (((t0 - t1) * t0 / t1).GetSeconds (), - ((t0.GetSeconds () - t1.GetSeconds ()) * t0.GetSeconds () / t1.GetSeconds ())); - ASSERT_EQ ((t0 * (t0 - t1) / t1).GetSeconds (), - (t0.GetSeconds () * (t0.GetSeconds () - t1.GetSeconds ()) / t1.GetSeconds ())); - ASSERT_EQ ((t0 * t1 / (t0 - t1)).GetSeconds (), - (t0.GetSeconds () * t1.GetSeconds () / (t0.GetSeconds () - t1.GetSeconds ()))); - ASSERT_EQ ((t0 * (t1 / (t0 - t1))).GetSeconds (), - (t0.GetSeconds () * (t1.GetSeconds () / (t0.GetSeconds () - t1.GetSeconds ())))); - ASSERT_EQ (((t0 * t1) / (t0 - t1)).GetSeconds (), - ((t0.GetSeconds () * t1.GetSeconds ()) / (t0.GetSeconds () - t1.GetSeconds ()))); - ASSERT_EQ ((t0 / t1 * (t0 - t1)).GetSeconds (), - (t0.GetSeconds () / t1.GetSeconds () * (t0.GetSeconds () - t1.GetSeconds ()))); - ASSERT_EQ (((t0 / t1) * (t0 - t1)).GetSeconds (), - (t0.GetSeconds () / t1.GetSeconds ()) * (t0.GetSeconds () - t1.GetSeconds ())); - ASSERT_EQ ((t0 * Scalar (10.0)).GetSeconds (), (t0.GetSeconds () * 10.0)); - ASSERT_EQ ((Scalar (10.0) * t0).GetSeconds (), (10.0 * t0.GetSeconds ())); - - // Note: we need to multiply by 1e9 because GetSeconds is multiplying - ASSERT_EQ (((t0 / (t1 * (t0 - t1))).GetHighPrecision ().GetDouble () * 1e9), - (t0.GetSeconds () / (t1.GetSeconds () * (t0.GetSeconds () - t1.GetSeconds ())))); - - ASSERT_EQ ((t0 / t1).GetDouble (),(t0.GetSeconds () / t1.GetSeconds ())); - - - ASSERT_EQ ((t0 * t1 / ((t0 - t1) * t0)).GetDouble (), - (t0.GetSeconds () * t1.GetSeconds () / ((t0.GetSeconds () - t1.GetSeconds ()) * t0.GetSeconds ()))); - return false; -} - -class TimeStepTestCase : public TestCase -{ -public: - TimeStepTestCase (); - virtual bool DoRun (void); -}; - -TimeStepTestCase::TimeStepTestCase () - : TestCase ("Check boundaries of TimeStep") -{ -} -bool -TimeStepTestCase::DoRun (void) -{ - Time tooBig = TimeStep (0x8000000000000000LL); - NS_TEST_ASSERT_MSG_EQ (tooBig.IsNegative (), true, "Is not negative ?"); - tooBig = TimeStep (0xffffffffffffffffLL); - NS_TEST_ASSERT_MSG_EQ (tooBig.IsNegative (), true, "Is not negative ?"); - tooBig = TimeStep (0x7fffffffffffffffLL); - NS_TEST_ASSERT_MSG_EQ (tooBig.IsPositive (), true, "Is not negative ?"); - tooBig += TimeStep (1); - NS_TEST_ASSERT_MSG_EQ (tooBig.IsNegative (), true, "Is not negative ?"); - return false; -} - -class GlobalPrecisionTestCase : public TestCase -{ -public: - GlobalPrecisionTestCase (); - virtual bool DoRun (void); - virtual void DoTeardown (void); -}; - -GlobalPrecisionTestCase::GlobalPrecisionTestCase () - : TestCase ("Check that global value actually changes the underlying precision") -{ -} -#define CHECK_PRECISION(prec) \ - Config::SetGlobal ("TimeStepPrecision", StringValue (# prec)); \ - NS_TEST_ASSERT_MSG_EQ (TimeStepPrecision::Get (), TimeStepPrecision::prec, "Could not set precision " << # prec) -bool -GlobalPrecisionTestCase::DoRun (void) -{ - CHECK_PRECISION (S); - CHECK_PRECISION (MS); - CHECK_PRECISION (US); - CHECK_PRECISION (NS); - CHECK_PRECISION (PS); - CHECK_PRECISION (FS); - return false; -} - -void -GlobalPrecisionTestCase::DoTeardown (void) -{ - TimeStepPrecision::Set (TimeStepPrecision::NS); -} - -#if 0 -// disable this test because it triggers crazy -// compiler behavior (ICE+unbounded memory usage) -class ConversionTestCase : public TestCase -{ -public: - ConversionTestCase (); - virtual bool DoRun (void); - virtual void DoTeardown (void); -}; - -ConversionTestCase::ConversionTestCase () - : TestCase ("Check crazy time conversions") -{ -} - -void ConversionTestCase::DoTeardown (void) -{ - TimeStepPrecision::Set (TimeStepPrecision::NS); -} - -#define CHECK_CONVERSIONS(tmp) \ - do { \ - double val = tmp; \ - Time t_sec = Seconds (val); \ - ASSERT_MSG_EQ (t_sec.GetSeconds (), val * 1e0, 1e0, "conv sec s"); \ - ASSERT_MSG_EQ_INT (t_sec.GetMilliSeconds (), val * 1e3, 1e3, "conv sec ms"); \ - ASSERT_MSG_EQ_INT (t_sec.GetMicroSeconds (), val * 1e6, 1e6, "conv sec us"); \ - ASSERT_MSG_EQ_INT (t_sec.GetNanoSeconds (), val * 1e9, 1e9, "conv sec ns"); \ - ASSERT_MSG_EQ_INT (t_sec.GetPicoSeconds (), val * 1e12, 1e12, "conv sec ps"); \ - ASSERT_MSG_EQ_INT (t_sec.GetFemtoSeconds (), val * 1e15, 1e15, "conv sec fs"); \ - uint64_t int_val = (uint64_t)val; \ - Time t_ms = MilliSeconds (int_val); \ - ASSERT_MSG_EQ (t_ms.GetSeconds (), val * 1e-3, 1e0, "conv ms s"); \ - ASSERT_MSG_EQ_INT (t_ms.GetMilliSeconds (), val * 1e0, 1e3, "conv ms ms"); \ - ASSERT_MSG_EQ_INT (t_ms.GetMicroSeconds (), val * 1e3, 1e6, "conv ms us"); \ - ASSERT_MSG_EQ_INT (t_ms.GetNanoSeconds (), val * 1e6, 1e9, "conv ms ns"); \ - ASSERT_MSG_EQ_INT (t_ms.GetPicoSeconds (), val * 1e9, 1e12, "conv ms fs"); \ - ASSERT_MSG_EQ_INT (t_ms.GetFemtoSeconds (), val * 1e12, 1e15, "conv ms ps"); \ - Time t_us = MicroSeconds (int_val); \ - ASSERT_MSG_EQ (t_us.GetSeconds (), val * 1e-6, 1e0, "conv us s"); \ - ASSERT_MSG_EQ_INT (t_us.GetMilliSeconds (), val * 1e-3, 1e3, "conv us ms"); \ - ASSERT_MSG_EQ_INT (t_us.GetMicroSeconds (), val * 1e0, 1e6, "conv us us"); \ - ASSERT_MSG_EQ_INT (t_us.GetNanoSeconds (), val * 1e3, 1e9, "conv us ns"); \ - ASSERT_MSG_EQ_INT (t_us.GetPicoSeconds (), val * 1e6, 1e12, "conv us ps"); \ - ASSERT_MSG_EQ_INT (t_us.GetFemtoSeconds (), val * 1e9, 1e15, "conv us fs"); \ - Time t_ns = NanoSeconds (int_val); \ - ASSERT_MSG_EQ (t_ns.GetSeconds (), val * 1e-9, 1e0, "conv ns s"); \ - ASSERT_MSG_EQ_INT (t_ns.GetMilliSeconds (), val * 1e-6, 1e3, "conv ns ms"); \ - ASSERT_MSG_EQ_INT (t_ns.GetMicroSeconds (), val * 1e-3, 1e6, "conv ns us"); \ - ASSERT_MSG_EQ_INT (t_ns.GetNanoSeconds (), val * 1e0, 1e9, "conv ns ns"); \ - ASSERT_MSG_EQ_INT (t_ns.GetPicoSeconds (), val * 1e3, 1e12, "conv ns ps"); \ - ASSERT_MSG_EQ_INT (t_ns.GetFemtoSeconds (), val * 1e6, 1e15, "conv ns fs"); \ - Time t_ps = PicoSeconds (int_val); \ - ASSERT_MSG_EQ (t_ps.GetSeconds (), val * 1e-12, 1e0, "conv ps s"); \ - ASSERT_MSG_EQ_INT (t_ps.GetMilliSeconds (), val * 1e-9, 1e3, "conv ps ms"); \ - ASSERT_MSG_EQ_INT (t_ps.GetMicroSeconds (), val * 1e-6, 1e6, "conv ps us"); \ - ASSERT_MSG_EQ_INT (t_ps.GetNanoSeconds (), val * 1e-3, 1e9, "conv ps ns"); \ - ASSERT_MSG_EQ_INT (t_ps.GetPicoSeconds (), val * 1e0, 1e12, "conv ps ps"); \ - ASSERT_MSG_EQ_INT (t_ps.GetFemtoSeconds (), val * 1e3, 1e15, "conv ps fs"); \ - Time t_fs = FemtoSeconds (int_val); \ - ASSERT_MSG_EQ (t_fs.GetSeconds (), val * 1e-15, 1e0, "conv fs sec"); \ - ASSERT_MSG_EQ_INT (t_fs.GetMilliSeconds (), val * 1e-12, 1e3, "conv fs ms"); \ - ASSERT_MSG_EQ_INT (t_fs.GetMicroSeconds (), val * 1e-9, 1e6, "conv fs us"); \ - ASSERT_MSG_EQ_INT (t_fs.GetNanoSeconds (), val * 1e-6, 1e9, "conv fs ns"); \ - ASSERT_MSG_EQ_INT (t_fs.GetPicoSeconds (), val * 1e-3, 1e12, "conv fs ps"); \ - ASSERT_MSG_EQ_INT (t_fs.GetFemtoSeconds (), val * 1e0, 1e15, "conv fs fs"); \ - } while (false) - -bool -ConversionTestCase::DoRun (void) -{ - CHECK_CONVERSIONS (5); - CHECK_CONVERSIONS (0); - CHECK_CONVERSIONS (783); - CHECK_CONVERSIONS (1132); - // triggers overflow - // XXX - // CHECK_CONVERSIONS(3341039); - - TimeStepPrecision::Set (TimeStepPrecision::US); - CHECK_CONVERSIONS (7); - CHECK_CONVERSIONS (546); - CHECK_CONVERSIONS (6231); - // triggers overflow - // XXX - // CHECK_CONVERSIONS(1234639); - - TimeStepPrecision::Set (TimeStepPrecision::MS); - CHECK_CONVERSIONS (3); - CHECK_CONVERSIONS (134); - CHECK_CONVERSIONS (2341); - // triggers overflow - // XXX - // CHECK_CONVERSIONS(8956239); - - TimeStepPrecision::Set (TimeStepPrecision::NS); - CHECK_CONVERSIONS (4); - CHECK_CONVERSIONS (342); - CHECK_CONVERSIONS (1327); - // triggers overflow - // XXX - // CHECK_CONVERSIONS(5439627); - - TimeStepPrecision::Set (TimeStepPrecision::PS); - CHECK_CONVERSIONS (4); - CHECK_CONVERSIONS (342); - CHECK_CONVERSIONS (1327); - // triggers overflow - // XXX - // CHECK_CONVERSIONS(5439627); - - TimeStepPrecision::Set (TimeStepPrecision::NS); - CHECK_CONVERSIONS (12); - - TimeStepPrecision::Set (TimeStepPrecision::S); - CHECK_CONVERSIONS (7); - - TimeStepPrecision::Set (TimeStepPrecision::FS); - CHECK_CONVERSIONS (5); - - return false; -} -#endif - class Bug863TestCase : public TestCase { public: @@ -709,18 +205,100 @@ bool Bug863TestCase::DoRun (void) return false; } +class TimeSimpleTestCase : public TestCase +{ +public: + TimeSimpleTestCase (enum Time::Unit resolution); +private: + virtual bool DoRun (void); + virtual void DoTearDown (void); + enum Time::Unit m_originalResolution; + enum Time::Unit m_resolution; +}; + +TimeSimpleTestCase::TimeSimpleTestCase (enum Time::Unit resolution) + : TestCase ("Sanity check of common time operations"), + m_resolution (resolution) +{} +bool +TimeSimpleTestCase::DoRun (void) +{ + m_originalResolution = Time::GetResolution (); + Time::SetResolution (m_resolution); + NS_TEST_ASSERT_MSG_EQ_TOL (Seconds (1.0).GetSeconds (), 1.0, TimeStep (1).GetSeconds (), + "is 1 really 1 ?"); + NS_TEST_ASSERT_MSG_EQ_TOL (Seconds (10.0).GetSeconds (), 10.0, TimeStep (1).GetSeconds (), + "is 10 really 10 ?"); + NS_TEST_ASSERT_MSG_EQ (MilliSeconds (1).GetMilliSeconds (), 1, + "is 1ms really 1ms ?"); + NS_TEST_ASSERT_MSG_EQ (MicroSeconds (1).GetMicroSeconds (), 1, + "is 1us really 1us ?"); +#if 0 + Time ns = NanoSeconds (1); + ns.GetNanoSeconds (); + NS_TEST_ASSERT_MSG_EQ (NanoSeconds (1).GetNanoSeconds (), 1, + "is 1ns really 1ns ?"); + NS_TEST_ASSERT_MSG_EQ (PicoSeconds (1).GetPicoSeconds (), 1, + "is 1ps really 1ps ?"); + NS_TEST_ASSERT_MSG_EQ (FemtoSeconds (1).GetFemtoSeconds (), 1, + "is 1fs really 1fs ?"); +#endif + return false; +} + +void +TimeSimpleTestCase::DoTearDown (void) +{ + Time::SetResolution (m_originalResolution); +} + +class ArithTestCase : public TestCase +{ +public: + ArithTestCase (); +private: + virtual bool DoRun (void); +}; + +ArithTestCase::ArithTestCase () + : TestCase ("check arithmetic operators") +{ +} +bool +ArithTestCase::DoRun (void) +{ + Time a, b, c; + c = a + b; + c = a * b; + c = a / Seconds (1.0); + c = a - b; + c += a; + c -= a; + c /= Seconds (1.0); + c *= a; + bool x; + x = a < b; + x = a > b; + x = a <= b; + x = a >= b; + x = a == b; + x = a != b; + //a = 1.0; + //a = 1; + return false; +} + + + static class TimeTestSuite : public TestSuite { public: TimeTestSuite () : TestSuite ("time", UNIT) { - AddTestCase (new OldTimeTestCase ()); - AddTestCase (new OperationsTimeTestCase ()); - AddTestCase (new TimeStepTestCase ()); - AddTestCase (new GlobalPrecisionTestCase ()); AddTestCase (new Bug863TestCase ()); - // AddTestCase(new ConversionTestCase()); + AddTestCase (new TimeSimpleTestCase (Time::US)); + AddTestCase (new ArithTestCase ()); } } g_timeTestSuite; diff --git a/src/simulator/wscript b/src/simulator/wscript index 254cee93c..cadfa9330 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -55,6 +55,7 @@ def build(bld): sim = bld.create_ns3_module('simulator', ['core']) sim.source = [ 'high-precision.cc', + 'time-base.cc', 'time.cc', 'event-id.cc', 'scheduler.cc', @@ -65,6 +66,7 @@ def build(bld): 'ns2-calendar-scheduler.cc', 'event-impl.cc', 'simulator.cc', + 'simulator-impl.cc', 'default-simulator-impl.cc', 'timer.cc', 'watchdog.cc', @@ -76,6 +78,7 @@ def build(bld): headers.module = 'simulator' headers.source = [ 'high-precision.h', + 'time-base.h', 'nstime.h', 'event-id.h', 'event-impl.h', @@ -105,7 +108,7 @@ def build(bld): elif env['USE_HIGH_PRECISION_CAIRO']: sim.source.extend([ 'high-precision-cairo.cc', - 'cairo-wideint.c', +# 'cairo-wideint.c', ]) headers.source.extend([ 'high-precision-cairo.h',