From b1e17bf18447b6f4dd73fd58cac0678008d6bd30 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 6 Jul 2010 15:40:16 +0200 Subject: [PATCH 01/24] use proper parent class --- src/simulator/realtime-simulator-impl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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.", From bb11b3999351fc6348ecdd71c5080b7a4dad85db Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 6 Jul 2010 15:41:15 +0200 Subject: [PATCH 02/24] use proper parent classname --- src/simulator/default-simulator-impl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; From 3db48958f6ff6a12680a6e47d212935686c9a94e Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 6 Jul 2010 15:41:54 +0200 Subject: [PATCH 03/24] add GetTypeId --- src/simulator/simulator-impl.cc | 14 ++++++++++++++ src/simulator/simulator-impl.h | 2 ++ src/simulator/wscript | 1 + 3 files changed, 17 insertions(+) create mode 100644 src/simulator/simulator-impl.cc 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 787769948..f58076c2e 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); + virtual void Destroy () = 0; virtual bool IsFinished (void) const = 0; virtual Time Next (void) const = 0; diff --git a/src/simulator/wscript b/src/simulator/wscript index 254cee93c..3cb61ac89 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -65,6 +65,7 @@ def build(bld): 'ns2-calendar-scheduler.cc', 'event-impl.cc', 'simulator.cc', + 'simulator-impl.cc', 'default-simulator-impl.cc', 'timer.cc', 'watchdog.cc', From 0b5fd59ac5907c8c71a97910392564faa5bfd4a5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 7 Jul 2010 16:22:09 +0200 Subject: [PATCH 04/24] no need to use timestep logic. --- src/simulator/synchronizer.cc | 40 +++-------------------------------- 1 file changed, 3 insertions(+), 37 deletions(-) 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 From 3f330b7a0166e44dd96926deb2ce89ef4ee1aec5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 7 Jul 2010 16:56:35 +0200 Subject: [PATCH 05/24] rewrite time integer support for 32bit systems. --- src/simulator/high-precision-cairo.cc | 170 +++++-- src/simulator/high-precision-cairo.h | 70 +-- src/simulator/high-precision.cc | 63 +++ src/simulator/nstime.h | 331 +++---------- src/simulator/time-base.cc | 59 +++ src/simulator/time-base.h | 258 ++++++++++ src/simulator/time.cc | 664 ++++---------------------- src/simulator/wscript | 4 +- 8 files changed, 700 insertions(+), 919 deletions(-) create mode 100644 src/simulator/time-base.cc create mode 100644 src/simulator/time-base.h diff --git a/src/simulator/high-precision-cairo.cc b/src/simulator/high-precision-cairo.cc index 217d660f3..37e89efcf 100644 --- a/src/simulator/high-precision-cairo.cc +++ b/src/simulator/high-precision-cairo.cc @@ -19,17 +19,41 @@ */ #include "high-precision-cairo.h" #include "ns3/test.h" -#include "ns3/fatal-error.h" +#include "ns3/abort.h" +#include "ns3/log.h" +#include "ns3/assert.h" #include #include namespace ns3 { +NS_LOG_COMPONENT_DEFINE ("HighPrecisionCairo"); + + +#define ABS_ARGS(sa,sb,ua,ub) \ + 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 */ \ + 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 + +#define SIGN_RESULT(result) \ + negResult ? _cairo_uint128_negate (result) : result + + 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; + ABS_ARGS (m_value, o.m_value, a, b); + result = Umul (a, b); + m_value = SIGN_RESULT (result); } @@ -39,22 +63,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 +84,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; + ABS_ARGS(m_value, o.m_value, a, b); + result = Udiv (a, b); + m_value = SIGN_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 +119,95 @@ 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::MulFactor (uint64_t factor) +{ + if (m_value.hi == 0 && m_value.lo == 0) + { + return; + } + // 1000 = 2^10 - 2^4 - 2^3 +#if 0 + // 1000000 = 2^20 - 2^16 + 2^14 + 2^9 + 2^6 + uint8_t powers [] = {20, 16, 14, 9, 6}; + int8_t signs [] = {1, -1, 1, 1, 1}; +#else + // 1000000000 = 2^30 - 2^26 - 2^23 + 2^21 - 2^18 - 2^16 - 2^14 + 2^11 + 2^9 + uint8_t powers [] = {9, 11, 14, 16, 18, 21, 23, 26, 30}; + int8_t signs [] = {1, 1, -1, -1, -1, 1, -1, -1, 1}; +#endif + cairo_uint128_t result; + result.hi = 0; + result.lo = 0; + for (uint8_t i = 0; i < sizeof (powers); i++) + { + uint8_t shift = powers[i]; + cairo_uint128_t tmp; + tmp.hi = (m_value.hi << shift) + (m_value.lo >> (64-shift)); + tmp.lo = m_value.lo << shift; + if (signs[i] < 0) + { + result = Sub (result, tmp); + } + else + { + result = Add (result, tmp); + } + } + m_value = 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 7e79f7f0d..8cb533450 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 { @@ -77,7 +46,7 @@ class HighPrecision public: inline HighPrecision (); inline HighPrecision (int64_t value, bool dummy); - inline HighPrecision (double value); + explicit inline HighPrecision (double value); inline int64_t GetInteger (void) const; inline double GetDouble (void) const; @@ -85,12 +54,20 @@ 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); + + void MulFactor (uint64_t factor); + 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 inline cairo_uint128_t Add (cairo_uint128_t a, cairo_uint128_t b); + static inline cairo_uint128_t Sub (cairo_uint128_t a, cairo_uint128_t b); + 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; @@ -124,6 +101,31 @@ HighPrecision::GetInteger (void) const { return m_value.hi; } +cairo_uint128_t +HighPrecision::Add (cairo_uint128_t a, cairo_uint128_t b) +{ + cairo_uint128_t result; + result.hi = a.hi + b.hi; + result.lo = a.lo + b.lo; + if (result.lo < a.lo) + { + result.hi++; + } + return result; +} +cairo_uint128_t +HighPrecision::Sub (cairo_uint128_t a, cairo_uint128_t b) +{ + cairo_uint128_t result; + result.hi = a.hi - b.hi; + result.lo = a.lo - b.lo; + if (result.lo > a.lo) + { + result.hi--; + } + return result; +} + void HighPrecision::Add (HighPrecision const &o) { diff --git a/src/simulator/high-precision.cc b/src/simulator/high-precision.cc index 257a49e6d..e753e4542 100644 --- a/src/simulator/high-precision.cc +++ b/src/simulator/high-precision.cc @@ -282,6 +282,68 @@ Hp128CompareTestCase::DoRun (void) return false; } +class Hp128InvertTestCase : public TestCase +{ +public: + Hp128InvertTestCase (); + virtual bool DoRun (void); +}; + +Hp128InvertTestCase::Hp128InvertTestCase () + : TestCase ("Test case for invertion") +{ +} +#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) + +bool +Hp128InvertTestCase::DoRun (void) +{ + 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); + return false; +} + + static class HighPrecision128TestSuite : public TestSuite { public: @@ -292,6 +354,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..61c90b1f8 100644 --- a/src/simulator/nstime.h +++ b/src/simulator/nstime.h @@ -27,37 +27,10 @@ #include #include #include "high-precision.h" +#include "time-base.h" 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 @@ -110,115 +83,14 @@ precision_t Get (void); * - \ref ns3-Time-Min ns3::Min */ template -class TimeUnit +class TimeUnit : public TimeBase { public: - TimeUnit (); - TimeUnit (TimeUnit const &o); - TimeUnit operator = (TimeUnit const &o); - TimeUnit (HighPrecision data); - - /** - * \return true if the time is zero, false otherwise. - */ - 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; - - /** - * 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); - -private: - HighPrecision m_data; + explicit inline TimeUnit (const HighPrecision &data) + : TimeBase (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) @@ -347,7 +219,7 @@ TimeUnit Min (TimeUnit const &ta, TimeUnit const &tb) class TimeValue; template <> -class TimeUnit<1> +class TimeUnit<1> : public TimeBase { // -*- New methods -*- public: @@ -368,103 +240,71 @@ public: * \param s The string to parse into a TimeUnit<1> */ TimeUnit<1> (const std::string & s); + /** * \returns an approximation in seconds of the time stored in this * instance. */ - double GetSeconds (void) const; + inline double GetSeconds (void) const + { + return TimeBase::ToDouble (*this, TimeBase::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 TimeBase::ToInteger (*this, TimeBase::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 TimeBase::ToInteger (*this, TimeBase::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 TimeBase::ToInteger (*this, TimeBase::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 TimeBase::ToInteger (*this, TimeBase::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 TimeBase::ToInteger (*this, TimeBase::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 { + int64_t timeValue = GetHighPrecision ().GetInteger (); + return timeValue; } - 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; - } - - static uint64_t UnitsToTimestep (uint64_t unitValue, - uint64_t unitFactor); - -private: - HighPrecision m_data; - - /* - * \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; + inline TimeUnit () + : TimeBase () {} + inline TimeUnit (const TimeBase &o) + : TimeBase (o) {} + explicit inline TimeUnit<1> (const HighPrecision &o) + : TimeBase (o) {} }; /** @@ -551,7 +391,10 @@ std::istream& operator>> (std::istream& is, Time & time); * \endcode * \param seconds seconds value */ -Time Seconds (double seconds); +inline Time Seconds (double seconds) +{ + return TimeBase::FromDouble (seconds, TimeBase::S); +} /** * \brief create ns3::Time instances in units of milliseconds. @@ -563,7 +406,10 @@ Time Seconds (double seconds); * \endcode * \param ms milliseconds value */ -Time MilliSeconds (uint64_t ms); +inline Time MilliSeconds (uint64_t ms) +{ + return TimeBase::FromInteger (ms, TimeBase::MS); +} /** * \brief create ns3::Time instances in units of microseconds. * @@ -574,7 +420,10 @@ Time MilliSeconds (uint64_t ms); * \endcode * \param us microseconds value */ -Time MicroSeconds (uint64_t us); +inline Time MicroSeconds (uint64_t us) +{ + return TimeBase::FromInteger (us, TimeBase::US); +} /** * \brief create ns3::Time instances in units of nanoseconds. * @@ -585,7 +434,10 @@ Time MicroSeconds (uint64_t us); * \endcode * \param ns nanoseconds value */ -Time NanoSeconds (uint64_t ns); +inline Time NanoSeconds (uint64_t ns) +{ + return TimeBase::FromInteger (ns, TimeBase::NS); +} /** * \brief create ns3::Time instances in units of picoseconds. * @@ -596,7 +448,10 @@ Time NanoSeconds (uint64_t ns); * \endcode * \param ps picoseconds value */ -Time PicoSeconds (uint64_t ps); +inline Time PicoSeconds (uint64_t ps) +{ + return TimeBase::FromInteger (ps, TimeBase::PS); +} /** * \brief create ns3::Time instances in units of femtoseconds. * @@ -607,71 +462,29 @@ Time PicoSeconds (uint64_t ps); * \endcode * \param fs femtoseconds value */ -Time FemtoSeconds (uint64_t fs); +inline Time FemtoSeconds (uint64_t fs) +{ + return TimeBase::FromInteger (fs, TimeBase::FS); +} // internal function not publicly documented -Time TimeStep (uint64_t ts); +inline Time TimeStep (uint64_t ts) +{ + return Time (HighPrecision (ts, false)); +} // 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> +class TimeUnit<0> : public TimeBase { // -*- New methods -*- public: double GetDouble (void) const; TimeUnit<0> (double scalar); - - // -*- The rest is the the same as in the generic template class -*- -public: - TimeUnit () - : m_data () - { - } - 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; - } - -private: - HighPrecision m_data; + TimeUnit<0> (); + TimeUnit<0> (const TimeUnit &o); + explicit TimeUnit<0> (const HighPrecision &o); }; /** 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..547d112ed --- /dev/null +++ b/src/simulator/time-base.h @@ -0,0 +1,258 @@ +/* -*- 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 + */ +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 + }; + static void SetResolution (enum Unit resolution); + static enum Unit GetResolution (void); + inline static TimeBase FromInteger (uint64_t value, enum Unit timeUnit); + inline static TimeBase FromDouble (double value, enum Unit timeUnit); + inline static uint64_t ToInteger (const TimeBase &time, enum Unit timeUnit); + 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 437811cfe..08a72eba3 100644 --- a/src/simulator/time.cc +++ b/src/simulator/time.cc @@ -20,7 +20,7 @@ * 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" @@ -30,43 +30,6 @@ 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) { std::string::size_type n = s.find_first_not_of ("0123456789."); @@ -79,40 +42,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,244 +78,68 @@ TimeUnit<1>::TimeUnit (const std::string& s) iss.str (s); double v; iss >> v; - m_data = HighPrecision (v); - m_data.Mul (HighPrecision (TimeStepPrecision::g_tsPrecFactor, false)); + *this = Time::FromDouble (v, Time::S); } -double -TimeUnit<1>::GetSeconds (void) const -{ - HighPrecision tmp = GetHighPrecision (); - HighPrecision factor = HighPrecision (TimeStepPrecision::g_tsPrecFactor, false); - tmp.Div (factor); - return tmp.GetDouble (); -} - -int64_t -TimeUnit<1>::ConvertToUnits (int64_t timeValue, uint64_t unitFactor) const -{ - 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; - timeValue = timeValue * precFactor; - } - else - { - precFactor = TimeStepPrecision::g_tsPrecFactor / unitFactor; - timeValue = timeValue / precFactor; - } - return timeValue; -} - - -int64_t -TimeUnit<1>::GetMilliSeconds (void) const -{ - 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; -} - - std::ostream& operator<< (std::ostream& os, const Time & time) { std::string unit; - switch (TimeStepPrecision::Get ()) + switch (TimeBase::GetResolution ()) { - case TimeStepPrecision::S: + case TimeBase::S: unit = "s"; break; - case TimeStepPrecision::MS: + case TimeBase::MS: unit = "ms"; break; - case TimeStepPrecision::US: + case TimeBase::US: unit = "us"; break; - case TimeStepPrecision::NS: + case TimeBase::NS: unit = "ns"; break; - case TimeStepPrecision::PS: + case TimeBase::PS: unit = "ps"; break; - case TimeStepPrecision::FS: + case TimeBase::FS: unit = "fs"; break; + case TimeBase::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) -{ - HighPrecision tmp = HighPrecision (seconds); - HighPrecision factor = HighPrecision (TimeStepPrecision::g_tsPrecFactor, false); - tmp.Mul (factor); - return Time (tmp); -} - -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); -} +TimeUnit<0>::TimeUnit () + : TimeBase (HighPrecision ()) +{} -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 (const TimeUnit &o) + : TimeBase (o) +{} TimeUnit<0>::TimeUnit (double scalar) - : m_data (HighPrecision (scalar)) -{ -} + : TimeBase (HighPrecision (scalar)) +{} + +TimeUnit<0>::TimeUnit (const HighPrecision &o) + : TimeBase (o) {} + double TimeUnit<0>::GetDouble (void) const @@ -371,329 +153,6 @@ TimeUnit<0>::GetDouble (void) const 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: @@ -713,18 +172,61 @@ bool Bug863TestCase::DoRun (void) return false; } +class TimeSimpleTestCase : public TestCase +{ +public: + TimeSimpleTestCase (enum TimeBase::Unit resolution); +private: + virtual bool DoRun (void); + virtual void DoTearDown (void); + enum TimeBase::Unit m_originalResolution; + enum TimeBase::Unit m_resolution; +}; + +TimeSimpleTestCase::TimeSimpleTestCase (enum TimeBase::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); +} + 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 (TimeBase::US)); } } g_timeTestSuite; diff --git a/src/simulator/wscript b/src/simulator/wscript index 3cb61ac89..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', @@ -77,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', @@ -106,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', From 82a8fef4c9fcfa3bd8da2d586f71aff64e5a91ae Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 7 Jul 2010 16:57:19 +0200 Subject: [PATCH 06/24] What time unit is this ? --- src/mobility/waypoint.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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) From 4d19ee3038b019a6f67d5d3cc3a88d5f60564aad Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 7 Jul 2010 18:17:05 +0200 Subject: [PATCH 07/24] move macro definition to function where it is used --- src/simulator/high-precision.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/simulator/high-precision.cc b/src/simulator/high-precision.cc index e753e4542..23573554a 100644 --- a/src/simulator/high-precision.cc +++ b/src/simulator/high-precision.cc @@ -293,6 +293,10 @@ Hp128InvertTestCase::Hp128InvertTestCase () : TestCase ("Test case for invertion") { } + +bool +Hp128InvertTestCase::DoRun (void) +{ #define TEST(factor) \ do { \ HighPrecision a; \ @@ -315,9 +319,6 @@ Hp128InvertTestCase::Hp128InvertTestCase () "-x * 1/x should be -1 for x=" << factor); \ } while(false) -bool -Hp128InvertTestCase::DoRun (void) -{ TEST(2); TEST(3); TEST(4); @@ -340,6 +341,7 @@ Hp128InvertTestCase::DoRun (void) TEST(10000000000000LL); TEST(100000000000000LL); TEST(1000000000000000LL); +#undef TEST return false; } From c68f49ad25b3efbd99437d4b5dbc5eed24e58ff8 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 7 Jul 2010 18:17:21 +0200 Subject: [PATCH 08/24] add invert support --- src/simulator/high-precision-double.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/simulator/high-precision-double.h b/src/simulator/high-precision-double.h index d28120da1..091e37e5a 100644 --- a/src/simulator/high-precision-double.h +++ b/src/simulator/high-precision-double.h @@ -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,6 +103,17 @@ 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 { From 7a16a8d2f2a097ce80e2e05beacc5babd5c8404c Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 7 Jul 2010 18:17:52 +0200 Subject: [PATCH 09/24] kill dead code --- src/simulator/high-precision-cairo.cc | 39 --------------------------- src/simulator/high-precision-cairo.h | 30 --------------------- 2 files changed, 69 deletions(-) diff --git a/src/simulator/high-precision-cairo.cc b/src/simulator/high-precision-cairo.cc index 37e89efcf..766147ae7 100644 --- a/src/simulator/high-precision-cairo.cc +++ b/src/simulator/high-precision-cairo.cc @@ -122,45 +122,6 @@ HighPrecision::Udiv (cairo_uint128_t a, cairo_uint128_t b) return result; } -void -HighPrecision::MulFactor (uint64_t factor) -{ - if (m_value.hi == 0 && m_value.lo == 0) - { - return; - } - // 1000 = 2^10 - 2^4 - 2^3 -#if 0 - // 1000000 = 2^20 - 2^16 + 2^14 + 2^9 + 2^6 - uint8_t powers [] = {20, 16, 14, 9, 6}; - int8_t signs [] = {1, -1, 1, 1, 1}; -#else - // 1000000000 = 2^30 - 2^26 - 2^23 + 2^21 - 2^18 - 2^16 - 2^14 + 2^11 + 2^9 - uint8_t powers [] = {9, 11, 14, 16, 18, 21, 23, 26, 30}; - int8_t signs [] = {1, 1, -1, -1, -1, 1, -1, -1, 1}; -#endif - cairo_uint128_t result; - result.hi = 0; - result.lo = 0; - for (uint8_t i = 0; i < sizeof (powers); i++) - { - uint8_t shift = powers[i]; - cairo_uint128_t tmp; - tmp.hi = (m_value.hi << shift) + (m_value.lo >> (64-shift)); - tmp.lo = m_value.lo << shift; - if (signs[i] < 0) - { - result = Sub (result, tmp); - } - else - { - result = Add (result, tmp); - } - } - m_value = result; -} - - void HighPrecision::MulByInvert (const HighPrecision &o) { diff --git a/src/simulator/high-precision-cairo.h b/src/simulator/high-precision-cairo.h index 8cb533450..c16e2c0bf 100644 --- a/src/simulator/high-precision-cairo.h +++ b/src/simulator/high-precision-cairo.h @@ -56,15 +56,10 @@ public: void Div (HighPrecision const &o); void MulByInvert (const HighPrecision &o); static HighPrecision Invert (uint64_t v); - - void MulFactor (uint64_t factor); - inline int Compare (HighPrecision const &o) const; inline static HighPrecision Zero (void); private: - static inline cairo_uint128_t Add (cairo_uint128_t a, cairo_uint128_t b); - static inline cairo_uint128_t Sub (cairo_uint128_t a, cairo_uint128_t b); 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); @@ -101,31 +96,6 @@ HighPrecision::GetInteger (void) const { return m_value.hi; } -cairo_uint128_t -HighPrecision::Add (cairo_uint128_t a, cairo_uint128_t b) -{ - cairo_uint128_t result; - result.hi = a.hi + b.hi; - result.lo = a.lo + b.lo; - if (result.lo < a.lo) - { - result.hi++; - } - return result; -} -cairo_uint128_t -HighPrecision::Sub (cairo_uint128_t a, cairo_uint128_t b) -{ - cairo_uint128_t result; - result.hi = a.hi - b.hi; - result.lo = a.lo - b.lo; - if (result.lo > a.lo) - { - result.hi--; - } - return result; -} - void HighPrecision::Add (HighPrecision const &o) { From 50a560f7e3c6f78c36b400ff9c41c86cb041b206 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 8 Jul 2010 09:32:48 +0200 Subject: [PATCH 10/24] tests pass on 64bit systems --- src/simulator/high-precision-128.cc | 106 ++++++++++++++++++++-------- src/simulator/high-precision-128.h | 6 ++ 2 files changed, 83 insertions(+), 29 deletions(-) diff --git a/src/simulator/high-precision-128.cc b/src/simulator/high-precision-128.cc index a53c16f66..48423d443 100644 --- a/src/simulator/high-precision-128.cc +++ b/src/simulator/high-precision-128.cc @@ -1,30 +1,41 @@ #include "high-precision-128.h" -#include "ns3/fatal-error.h" +#include "ns3/abort.h" +#include "ns3/assert.h" #include namespace ns3 { +#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) +{ 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 +53,24 @@ 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) +{ uint128_t quo = a / b; uint128_t rem = (a % b); uint128_t result = quo << 64; @@ -82,8 +89,49 @@ 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) +{ + 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..8f10391e8 100644 --- a/src/simulator/high-precision-128.h +++ b/src/simulator/high-precision-128.h @@ -44,10 +44,16 @@ 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; }; From 57b7572e7503f72dfd829bf4392becd7f8c817d2 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 8 Jul 2010 09:33:06 +0200 Subject: [PATCH 11/24] rework 32bit version to match 64bit version --- src/simulator/high-precision-cairo.cc | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/simulator/high-precision-cairo.cc b/src/simulator/high-precision-cairo.cc index 766147ae7..57b1588fe 100644 --- a/src/simulator/high-precision-cairo.cc +++ b/src/simulator/high-precision-cairo.cc @@ -30,30 +30,23 @@ namespace ns3 { NS_LOG_COMPONENT_DEFINE ("HighPrecisionCairo"); -#define ABS_ARGS(sa,sb,ua,ub) \ - bool negResult, negA, negB; \ - /* take the sign of the operands */ \ +#define OUTPUT_SIGN(sa,sb,ua,ub) \ + ({bool 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 */ \ 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 - -#define SIGN_RESULT(result) \ - negResult ? _cairo_uint128_negate (result) : result - + ub = negB ? _cairo_uint128_negate (ub) : ub; \ + negResult = (negA && !negB) || (!negA && negB);}) void HighPrecision::Mul (HighPrecision const &o) { cairo_uint128_t a, b, result; - ABS_ARGS (m_value, o.m_value, a, b); + bool sign = OUTPUT_SIGN (m_value, o.m_value, a, b); result = Umul (a, b); - m_value = SIGN_RESULT (result); + m_value = sign ? _cairo_uint128_negate (result) : result; } @@ -93,9 +86,9 @@ void HighPrecision::Div (HighPrecision const &o) { cairo_uint128_t a, b, result; - ABS_ARGS(m_value, o.m_value, a, b); + bool sign = OUTPUT_SIGN (m_value, o.m_value, a, b); result = Udiv (a, b); - m_value = SIGN_RESULT (result); + m_value = sign ? _cairo_uint128_negate (result) : result; } cairo_uint128_t From 648660175a894268d901e1398cf34f517fded4b7 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 8 Jul 2010 09:38:09 +0200 Subject: [PATCH 12/24] add missing explicit keyword to match -cairo version of the code --- src/simulator/high-precision-128.h | 4 ++-- src/simulator/high-precision-double.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/simulator/high-precision-128.h b/src/simulator/high-precision-128.h index 8f10391e8..b2362d1ee 100644 --- a/src/simulator/high-precision-128.h +++ b/src/simulator/high-precision-128.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; diff --git a/src/simulator/high-precision-double.h b/src/simulator/high-precision-double.h index 091e37e5a..f47bf875c 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; From 4de0464482e906fb69f99312493f72021de89cb3 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 8 Jul 2010 09:38:33 +0200 Subject: [PATCH 13/24] variable is of type Time, not Timer. --- src/internet-stack/ndisc-cache.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 (); From d4d165fcfafdd8ad9056cc17f34a598f5183ccc0 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 8 Jul 2010 09:40:24 +0200 Subject: [PATCH 14/24] another missing explicit keyword --- src/simulator/high-precision-cairo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulator/high-precision-cairo.h b/src/simulator/high-precision-cairo.h index c16e2c0bf..1f5abd88e 100644 --- a/src/simulator/high-precision-cairo.h +++ b/src/simulator/high-precision-cairo.h @@ -45,7 +45,7 @@ class HighPrecision { public: inline HighPrecision (); - inline HighPrecision (int64_t value, bool dummy); + explicit inline HighPrecision (int64_t value, bool dummy); explicit inline HighPrecision (double value); inline int64_t GetInteger (void) const; From a361360823ed561b24581e28322a40c98e8756b1 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 8 Jul 2010 09:53:49 +0200 Subject: [PATCH 15/24] fix build typo --- src/simulator/high-precision-cairo.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulator/high-precision-cairo.cc b/src/simulator/high-precision-cairo.cc index 57b1588fe..2e0e43b9a 100644 --- a/src/simulator/high-precision-cairo.cc +++ b/src/simulator/high-precision-cairo.cc @@ -38,7 +38,7 @@ NS_LOG_COMPONENT_DEFINE ("HighPrecisionCairo"); ub = _cairo_int128_to_uint128 (sb); \ ua = negA ? _cairo_uint128_negate (ua) : ua; \ ub = negB ? _cairo_uint128_negate (ub) : ub; \ - negResult = (negA && !negB) || (!negA && negB);}) + (negA && !negB) || (!negA && negB);}) void HighPrecision::Mul (HighPrecision const &o) From 23a588f33680e5adcaf25e6368e8f712dd3d9975 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 8 Jul 2010 10:31:31 +0200 Subject: [PATCH 16/24] documentation --- src/simulator/time-base.h | 78 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/simulator/time-base.h b/src/simulator/time-base.h index 547d112ed..f8440eade 100644 --- a/src/simulator/time-base.h +++ b/src/simulator/time-base.h @@ -27,6 +27,43 @@ 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 { @@ -44,11 +81,52 @@ public: 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 (); From edb157f10857f8a17d563d8981469548b8b0b81a Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 8 Jul 2010 20:59:08 +0200 Subject: [PATCH 17/24] add missing include --- src/simulator/time.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/simulator/time.cc b/src/simulator/time.cc index 08a72eba3..c5b8e2450 100644 --- a/src/simulator/time.cc +++ b/src/simulator/time.cc @@ -27,6 +27,7 @@ #include "ns3/object.h" #include "ns3/config.h" #include +#include namespace ns3 { From c2a5c1ff92f2f443d3fc077376b180a06265bb02 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 9 Jul 2010 10:33:35 +0200 Subject: [PATCH 18/24] oops. implement Compare method correctly --- src/simulator/high-precision-double.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulator/high-precision-double.h b/src/simulator/high-precision-double.h index f47bf875c..f25fa8099 100644 --- a/src/simulator/high-precision-double.h +++ b/src/simulator/high-precision-double.h @@ -117,7 +117,7 @@ HighPrecision::Invert (uint64_t 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) From 491065204806c96d710f3cbd092a8847450a6c84 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 9 Jul 2010 12:52:09 +0200 Subject: [PATCH 19/24] no need to use TimeUnit<1> here --- src/common/data-rate.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 93032c887a7a145dc8e0a3cd8ba628044c5361a5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 9 Jul 2010 12:52:24 +0200 Subject: [PATCH 20/24] get rid of TimeUnit --- src/devices/csma/backoff.cc | 2 +- src/simulator/nstime.h | 729 ++++++++++++++++++++++-------------- src/simulator/time.cc | 104 +++-- 3 files changed, 525 insertions(+), 310 deletions(-) diff --git a/src/devices/csma/backoff.cc b/src/devices/csma/backoff.cc index 08c4cd13e..2e373d820 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 = backoffSlots * m_slotTime; return (backoff); } diff --git a/src/simulator/nstime.h b/src/simulator/nstime.h index 61c90b1f8..254bded8b 100644 --- a/src/simulator/nstime.h +++ b/src/simulator/nstime.h @@ -27,7 +27,6 @@ #include #include #include "high-precision.h" -#include "time-base.h" namespace ns3 { @@ -82,150 +81,135 @@ namespace ns3 { * - \ref ns3-Time-Max ns3::Max * - \ref ns3-Time-Min ns3::Min */ -template -class TimeUnit : public TimeBase -{ -public: - explicit inline TimeUnit (const HighPrecision &data) - : TimeBase (data) - {} -}; - -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. + * \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. */ -template -TimeUnit Abs (TimeUnit const &time) +class 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> : public TimeBase -{ - // -*- New methods -*- 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 + }; + + 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) + {} + inline Time (double v) + : m_data (HighPrecision (v)) + {} + inline Time (int64_t v) + : m_data (HighPrecision (v, false)) + {} + inline Time (uint64_t v) + : m_data (HighPrecision (v, false)) + {} + inline Time (int32_t v) + : m_data (HighPrecision (v, false)) + {} + inline Time (uint32_t v) + : m_data (HighPrecision (v, false)) + {} + inline Time (int16_t v) + : m_data (HighPrecision (v, false)) + {} + inline Time (uint16_t v) + : m_data (HighPrecision (v, false)) + {} + inline Time (int8_t v) + : m_data (HighPrecision (v, false)) + {} + inline Time (uint8_t v) + : m_data (HighPrecision (v, false)) + {} + + /** * \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) @@ -237,9 +221,66 @@ 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 @@ -247,7 +288,7 @@ public: */ inline double GetSeconds (void) const { - return TimeBase::ToDouble (*this, TimeBase::S); + return ToDouble (*this, Time::S); } /** @@ -256,7 +297,7 @@ public: */ inline int64_t GetMilliSeconds (void) const { - return TimeBase::ToInteger (*this, TimeBase::MS); + return ToInteger (*this, Time::MS); } /** * \returns an approximation in microseconds of the time stored in this @@ -264,7 +305,7 @@ public: */ inline int64_t GetMicroSeconds (void) const { - return TimeBase::ToInteger (*this, TimeBase::US); + return ToInteger (*this, Time::US); } /** * \returns an approximation in nanoseconds of the time stored in this @@ -272,7 +313,7 @@ public: */ inline int64_t GetNanoSeconds (void) const { - return TimeBase::ToInteger (*this, TimeBase::NS); + return ToInteger (*this, Time::NS); } /** * \returns an approximation in picoseconds of the time stored in this @@ -280,7 +321,7 @@ public: */ inline int64_t GetPicoSeconds (void) const { - return TimeBase::ToInteger (*this, TimeBase::PS); + return ToInteger (*this, Time::PS); } /** * \returns an approximation in femtoseconds of the time stored in this @@ -288,7 +329,7 @@ public: */ inline int64_t GetFemtoSeconds (void) const { - return TimeBase::ToInteger (*this, TimeBase::FS); + return ToInteger (*this, Time::FS); } /** * \returns an approximation of the time stored in this @@ -296,86 +337,270 @@ public: */ inline int64_t GetTimeStep (void) const { - int64_t timeValue = GetHighPrecision ().GetInteger (); + int64_t timeValue = m_data.GetInteger (); return timeValue; } - inline TimeUnit () - : TimeBase () {} - inline TimeUnit (const TimeBase &o) - : TimeBase (o) {} - explicit inline TimeUnit<1> (const HighPrecision &o) - : TimeBase (o) {} + inline double GetDouble (void) const + { + return m_data.GetDouble (); + } + inline int64_t GetInteger (void) const + { + return GetTimeStep (); + } + + + /** + * \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: + struct Information + { + bool toMul; + bool fromMul; + uint64_t factor; + HighPrecision timeTo; + HighPrecision timeFrom; + }; + struct Resolution + { + struct Information info[LAST]; + enum Time::Unit unit; + }; + + 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); @@ -393,7 +618,7 @@ std::istream& operator>> (std::istream& is, Time & time); */ inline Time Seconds (double seconds) { - return TimeBase::FromDouble (seconds, TimeBase::S); + return Time::FromDouble (seconds, Time::S); } /** @@ -408,7 +633,7 @@ inline Time Seconds (double seconds) */ inline Time MilliSeconds (uint64_t ms) { - return TimeBase::FromInteger (ms, TimeBase::MS); + return Time::FromInteger (ms, Time::MS); } /** * \brief create ns3::Time instances in units of microseconds. @@ -422,7 +647,7 @@ inline Time MilliSeconds (uint64_t ms) */ inline Time MicroSeconds (uint64_t us) { - return TimeBase::FromInteger (us, TimeBase::US); + return Time::FromInteger (us, Time::US); } /** * \brief create ns3::Time instances in units of nanoseconds. @@ -436,7 +661,7 @@ inline Time MicroSeconds (uint64_t us) */ inline Time NanoSeconds (uint64_t ns) { - return TimeBase::FromInteger (ns, TimeBase::NS); + return Time::FromInteger (ns, Time::NS); } /** * \brief create ns3::Time instances in units of picoseconds. @@ -450,7 +675,7 @@ inline Time NanoSeconds (uint64_t ns) */ inline Time PicoSeconds (uint64_t ps) { - return TimeBase::FromInteger (ps, TimeBase::PS); + return Time::FromInteger (ps, Time::PS); } /** * \brief create ns3::Time instances in units of femtoseconds. @@ -464,7 +689,7 @@ inline Time PicoSeconds (uint64_t ps) */ inline Time FemtoSeconds (uint64_t fs) { - return TimeBase::FromInteger (fs, TimeBase::FS); + return Time::FromInteger (fs, Time::FS); } // internal function not publicly documented @@ -473,51 +698,9 @@ inline Time TimeStep (uint64_t ts) return Time (HighPrecision (ts, false)); } -// 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> : public TimeBase -{ - // -*- New methods -*- -public: - double GetDouble (void) const; - TimeUnit<0> (double scalar); - TimeUnit<0> (); - TimeUnit<0> (const TimeUnit &o); - explicit TimeUnit<0> (const HighPrecision &o); -}; - -/** - * \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 Scalar; +typedef Time TimeInvert; +typedef Time TimeSquare; /** * \class ns3::TimeValue @@ -525,8 +708,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/time.cc b/src/simulator/time.cc index c5b8e2450..0ea58f119 100644 --- a/src/simulator/time.cc +++ b/src/simulator/time.cc @@ -31,7 +31,7 @@ namespace ns3 { -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) @@ -82,31 +82,85 @@ TimeUnit<1>::TimeUnit (const std::string& s) *this = Time::FromDouble (v, Time::S); } +struct Time::Resolution +Time::GetNsResolution (void) +{ + struct Resolution resolution; + SetResolution (Time::NS, &resolution); + return resolution; +} +void +Time::SetResolution (enum Unit resolution) +{ + 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++) + { + 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 Time::Unit +Time::GetResolution (void) +{ + return PeekResolution ()->unit; +} + + std::ostream& operator<< (std::ostream& os, const Time & time) { std::string unit; - switch (TimeBase::GetResolution ()) + switch (Time::GetResolution ()) { - case TimeBase::S: + case Time::S: unit = "s"; break; - case TimeBase::MS: + case Time::MS: unit = "ms"; break; - case TimeBase::US: + case Time::US: unit = "us"; break; - case TimeBase::NS: + case Time::NS: unit = "ns"; break; - case TimeBase::PS: + case Time::PS: unit = "ps"; break; - case TimeBase::FS: + case Time::FS: unit = "fs"; break; - case TimeBase::LAST: + case Time::LAST: NS_ABORT_MSG ("can't be reached"); unit = "unreachable"; break; @@ -126,28 +180,6 @@ std::istream& operator>> (std::istream& is, Time & time) ATTRIBUTE_VALUE_IMPLEMENT (Time); ATTRIBUTE_CHECKER_IMPLEMENT (Time); -TimeUnit<0>::TimeUnit () - : TimeBase (HighPrecision ()) -{} - -TimeUnit<0>::TimeUnit (const TimeUnit &o) - : TimeBase (o) -{} - -TimeUnit<0>::TimeUnit (double scalar) - : TimeBase (HighPrecision (scalar)) -{} - -TimeUnit<0>::TimeUnit (const HighPrecision &o) - : TimeBase (o) {} - - -double -TimeUnit<0>::GetDouble (void) const -{ - return GetHighPrecision ().GetDouble (); -} - } // namespace ns3 #include "ns3/test.h" @@ -176,15 +208,15 @@ bool Bug863TestCase::DoRun (void) class TimeSimpleTestCase : public TestCase { public: - TimeSimpleTestCase (enum TimeBase::Unit resolution); + TimeSimpleTestCase (enum Time::Unit resolution); private: virtual bool DoRun (void); virtual void DoTearDown (void); - enum TimeBase::Unit m_originalResolution; - enum TimeBase::Unit m_resolution; + enum Time::Unit m_originalResolution; + enum Time::Unit m_resolution; }; -TimeSimpleTestCase::TimeSimpleTestCase (enum TimeBase::Unit resolution) +TimeSimpleTestCase::TimeSimpleTestCase (enum Time::Unit resolution) : TestCase ("Sanity check of common time operations"), m_resolution (resolution) {} @@ -227,7 +259,7 @@ public: : TestSuite ("time", UNIT) { AddTestCase (new Bug863TestCase ()); - AddTestCase (new TimeSimpleTestCase (TimeBase::US)); + AddTestCase (new TimeSimpleTestCase (Time::US)); } } g_timeTestSuite; From 979c31d737fcb2ef2df25a78104b4ab899cb61d1 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 14 Jul 2010 21:24:17 +0200 Subject: [PATCH 21/24] remove un-needed log declaration --- src/simulator/high-precision-cairo.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/simulator/high-precision-cairo.cc b/src/simulator/high-precision-cairo.cc index 2e0e43b9a..77893f2ec 100644 --- a/src/simulator/high-precision-cairo.cc +++ b/src/simulator/high-precision-cairo.cc @@ -20,15 +20,12 @@ #include "high-precision-cairo.h" #include "ns3/test.h" #include "ns3/abort.h" -#include "ns3/log.h" #include "ns3/assert.h" #include #include namespace ns3 { -NS_LOG_COMPONENT_DEFINE ("HighPrecisionCairo"); - #define OUTPUT_SIGN(sa,sb,ua,ub) \ ({bool negA, negB; \ From 74f3f66a73a4c369b28990d512fcdf454500f506 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 14 Jul 2010 21:25:06 +0200 Subject: [PATCH 22/24] instrument arith ops --- src/simulator/high-precision-128.cc | 20 ++++++++++++++++++ src/simulator/high-precision-128.h | 32 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/simulator/high-precision-128.cc b/src/simulator/high-precision-128.cc index 48423d443..918ed1a6d 100644 --- a/src/simulator/high-precision-128.cc +++ b/src/simulator/high-precision-128.cc @@ -2,9 +2,26 @@ #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; \ @@ -31,6 +48,7 @@ HighPrecision::Mul (HighPrecision const &o) 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; @@ -71,6 +89,7 @@ HighPrecision::Div (HighPrecision const &o) 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; @@ -104,6 +123,7 @@ HighPrecision::MulByInvert (const HighPrecision &o) 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; diff --git a/src/simulator/high-precision-128.h b/src/simulator/high-precision-128.h index b2362d1ee..a9b8a2c63 100644 --- a/src/simulator/high-precision-128.h +++ b/src/simulator/high-precision-128.h @@ -24,11 +24,29 @@ #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 @@ -55,6 +73,17 @@ private: 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 @@ -81,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; } From 48db5b00b816e4c32217615fd214bf3b74924a55 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 14 Jul 2010 21:43:55 +0200 Subject: [PATCH 23/24] someone forgot and explicit Scalar --- src/devices/csma/backoff.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/csma/backoff.cc b/src/devices/csma/backoff.cc index 2e373d820..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 = backoffSlots * m_slotTime; + backoff = Scalar (backoffSlots) * m_slotTime; return (backoff); } From cde6db777a683d39e70b298fd282115b67f62287 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 14 Jul 2010 21:45:31 +0200 Subject: [PATCH 24/24] re-introduce Scalar class --- src/simulator/nstime.h | 73 +++++++++++++++++++++--------------------- src/simulator/time.cc | 39 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 37 deletions(-) diff --git a/src/simulator/nstime.h b/src/simulator/nstime.h index 254bded8b..fd28f96fa 100644 --- a/src/simulator/nstime.h +++ b/src/simulator/nstime.h @@ -178,34 +178,6 @@ public: explicit inline Time (const HighPrecision &data) : m_data (data) {} - inline Time (double v) - : m_data (HighPrecision (v)) - {} - inline Time (int64_t v) - : m_data (HighPrecision (v, false)) - {} - inline Time (uint64_t v) - : m_data (HighPrecision (v, false)) - {} - inline Time (int32_t v) - : m_data (HighPrecision (v, false)) - {} - inline Time (uint32_t v) - : m_data (HighPrecision (v, false)) - {} - inline Time (int16_t v) - : m_data (HighPrecision (v, false)) - {} - inline Time (uint16_t v) - : m_data (HighPrecision (v, false)) - {} - inline Time (int8_t v) - : m_data (HighPrecision (v, false)) - {} - inline Time (uint8_t v) - : m_data (HighPrecision (v, false)) - {} - /** * \brief String constructor @@ -340,14 +312,6 @@ public: int64_t timeValue = m_data.GetInteger (); return timeValue; } - inline double GetDouble (void) const - { - return m_data.GetDouble (); - } - inline int64_t GetInteger (void) const - { - return GetTimeStep (); - } /** @@ -698,7 +662,42 @@ inline Time TimeStep (uint64_t ts) return Time (HighPrecision (ts, false)); } -typedef Time Scalar; +class Scalar +{ +public: + 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)); + } + inline double GetDouble (void) const + { + return m_v; + } +private: + double m_v; +}; + typedef Time TimeInvert; typedef Time TimeSquare; diff --git a/src/simulator/time.cc b/src/simulator/time.cc index 0ea58f119..1fb68105d 100644 --- a/src/simulator/time.cc +++ b/src/simulator/time.cc @@ -252,6 +252,44 @@ 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: @@ -260,6 +298,7 @@ public: { AddTestCase (new Bug863TestCase ()); AddTestCase (new TimeSimpleTestCase (Time::US)); + AddTestCase (new ArithTestCase ()); } } g_timeTestSuite;