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