rewrite time integer support for 32bit systems.
This commit is contained in:
@@ -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 <math.h>
|
||||
#include <iostream>
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -27,37 +27,10 @@
|
||||
#include <math.h>
|
||||
#include <ostream>
|
||||
#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 <int N>
|
||||
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<N> type.
|
||||
*/
|
||||
HighPrecision const &GetHighPrecision (void) const;
|
||||
HighPrecision * PeekHighPrecision (void);
|
||||
|
||||
private:
|
||||
HighPrecision m_data;
|
||||
explicit inline TimeUnit (const HighPrecision &data)
|
||||
: TimeBase (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)
|
||||
@@ -347,7 +219,7 @@ TimeUnit<N> Min (TimeUnit<N> const &ta, TimeUnit<N> 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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
59
src/simulator/time-base.cc
Normal file
59
src/simulator/time-base.cc
Normal file
@@ -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
|
||||
258
src/simulator/time-base.h
Normal file
258
src/simulator/time-base.h
Normal file
@@ -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 <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
|
||||
*/
|
||||
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 */
|
||||
@@ -20,7 +20,7 @@
|
||||
* 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"
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user