bug 954: Changing the simulation time resolution does not work well with attributes
This commit is contained in:
@@ -313,7 +313,7 @@ section, so go ahead and expand that documentation node. Now, expand the
|
||||
``Debugging`` book and then select the ``Logging`` page.
|
||||
|
||||
You should now be looking at the Doxygen documentation for the Logging module.
|
||||
In the list of ``#define`` s at the top of the page you will see the entry
|
||||
In the list of ``#define``'s at the top of the page you will see the entry
|
||||
for ``NS_LOG_COMPONENT_DEFINE``. Before jumping in, it would probably be
|
||||
good to look for the "Detailed Description" of the logging module to get a
|
||||
feel for the overall operation. You can either scroll down or select the
|
||||
@@ -340,6 +340,20 @@ Just as in any C++ program, you need to define a main function that will be
|
||||
the first function run. There is nothing at all special here. Your
|
||||
|ns3| script is just a C++ program.
|
||||
|
||||
The next line sets the time resolution to one nanosecond, which happens
|
||||
to be the default value:
|
||||
|
||||
::
|
||||
|
||||
Time::SetResolution (Time::NS);
|
||||
|
||||
You can change the resolution exactly once (which must be before
|
||||
``Simulator::Run ()`` is called, below). The mechanism enabling this
|
||||
flexibility is somewhat memory hungry, so once the resolution has been
|
||||
set explicitly we release the memory, preventing further updates. (If
|
||||
you don't set the resolution explicitly, it will default to one nanosecond,
|
||||
and the memory will be released when the simulation starts.)
|
||||
|
||||
The next two lines of the script are used to enable two logging components that
|
||||
are built into the Echo Client and Echo Server applications:
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
Time::SetResolution (Time::NS);
|
||||
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
|
||||
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "int64x64.h"
|
||||
#include <stdint.h>
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
#include <ostream>
|
||||
|
||||
namespace ns3 {
|
||||
@@ -36,115 +37,48 @@ namespace ns3 {
|
||||
*/
|
||||
/**
|
||||
* \ingroup time
|
||||
* \brief keep track of time unit.
|
||||
* \brief Keep track of time values and allow control of global simulation resolution.
|
||||
*
|
||||
* This template class is used to keep track of the value
|
||||
* of a specific time unit: the type TimeUnit<1> is used to
|
||||
* keep track of seconds, the type TimeUnit<2> is used to keep
|
||||
* track of seconds squared, the type TimeUnit<-1> is used to
|
||||
* keep track of 1/seconds, etc.
|
||||
*
|
||||
* This base class defines all the functionality shared by all
|
||||
* these time unit objects: it defines all the classic arithmetic
|
||||
* operators +, -, *, /, and all the classic comparison operators:
|
||||
* This class defines the classic addition/subtraction C++ arithmetic
|
||||
* operators +, -, +=, -=, and all the classic comparison operators:
|
||||
* ==, !=, <, >, <=, >=. It is thus easy to add, substract, or
|
||||
* multiply multiple TimeUnit objects. The return type of any such
|
||||
* arithmetic expression is always a TimeUnit object.
|
||||
*
|
||||
* The ns3::uint64_t, ns3::Time, ns3::TimeSquare, and ns3::TimeInvert classes
|
||||
* are aliases for the TimeUnit<0>, TimeUnit<1>, TimeUnit<2> and TimeUnit<-1>
|
||||
* types respectively.
|
||||
*
|
||||
* For example:
|
||||
* \code
|
||||
* Time<1> t1 = Seconds (10.0);
|
||||
* Time<1> t2 = Seconds (10.0);
|
||||
* Time<2> t3 = t1 * t2;
|
||||
* Time<0> t4 = t1 / t2;
|
||||
* Time<3> t5 = t3 * t1;
|
||||
* Time<-2> t6 = t1 / t5;
|
||||
* TimeSquare t7 = t3;
|
||||
* uint64_t s = t4;
|
||||
* \endcode
|
||||
*
|
||||
* If you try to assign the result of an expression which does not
|
||||
* match the type of the variable it is assigned to, you will get a
|
||||
* compiler error. For example, the following will not compile:
|
||||
* \code
|
||||
* Time<1> = Seconds (10.0) * Seconds (1.5);
|
||||
* \endcode
|
||||
*
|
||||
* You can also use the following non-member functions to manipulate
|
||||
* any of these ns3::TimeUnit object:
|
||||
* - \ref ns3-Time-Abs ns3::Abs
|
||||
* - \ref ns3-Time-Max ns3::Max
|
||||
* - \ref ns3-Time-Min ns3::Min
|
||||
*/
|
||||
/**
|
||||
* \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::uint64_t, ns3::TimeSquare, and ns3::TimeInvert classes
|
||||
* are backward-compatibility aliases for ns3::Time.
|
||||
* compare Time objects.
|
||||
*
|
||||
* 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;
|
||||
* Time t3 = t1;
|
||||
* t3 += t2;
|
||||
* \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
|
||||
* - \ref Abs()
|
||||
* - \ref Max()
|
||||
* - \ref 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.
|
||||
* This class also controls the resolution of the underlying time value.
|
||||
* The resolution is the smallest representable time interval.
|
||||
* The default resolution is nanoseconds.
|
||||
*
|
||||
* 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
|
||||
* Time::SetResolution. If you do need to use picoseconds, it's thus best
|
||||
* to switch the global resolution to picoseconds to avoid nasty surprises.
|
||||
* To change the resolution, use SetResolution(). All Time objects created
|
||||
* before the call to SetResolution() will be updated to the new resolution.
|
||||
* This can only be done once! (Tracking each Time object uses 4 pointers.
|
||||
* For speed, once we convert the existing instances we discard the recording
|
||||
* data structure and stop tracking new instances, so we have no way
|
||||
* to do a second conversion.)
|
||||
*
|
||||
* 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.
|
||||
* Because of the memory (and modest construction cost) of tracking Time
|
||||
* objects, simulations should explicitly choose a resolution before
|
||||
* calling Simulator::Run ().
|
||||
*
|
||||
* 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.
|
||||
* If you increase the global resolution, you also implicitly decrease
|
||||
* the range of your simulation. The global simulation time is stored
|
||||
* in a 64 bit integer, whose interpretation will depend on the global
|
||||
* resolution. Therefore the maximum duration of your simulation,
|
||||
* if you use picoseconds, is 2^64 ps = 2^24 s = 7 months, whereas,
|
||||
* had you used nanoseconds, you could have run for 584 years.
|
||||
*/
|
||||
class Time
|
||||
{
|
||||
@@ -154,12 +88,12 @@ public:
|
||||
*/
|
||||
enum Unit
|
||||
{
|
||||
S = 0,
|
||||
MS = 1,
|
||||
US = 2,
|
||||
NS = 3,
|
||||
PS = 4,
|
||||
FS = 5,
|
||||
S = 0, //!< second
|
||||
MS = 1, //!< millisecond
|
||||
US = 2, //!< microsecond
|
||||
NS = 3, //!< nanosecond
|
||||
PS = 4, //!< picosecond
|
||||
FS = 5, //!< femtosecond
|
||||
LAST = 6
|
||||
};
|
||||
|
||||
@@ -168,44 +102,66 @@ public:
|
||||
m_data = o.m_data;
|
||||
return *this;
|
||||
}
|
||||
inline Time &operator = (const int64_t &value)
|
||||
{
|
||||
m_data = value;
|
||||
return *this;
|
||||
}
|
||||
inline Time ()
|
||||
: m_data ()
|
||||
{}
|
||||
{
|
||||
TimeSet (this);
|
||||
}
|
||||
inline Time(const Time &o)
|
||||
: m_data (o.m_data)
|
||||
{}
|
||||
{
|
||||
TimeSet (this);
|
||||
}
|
||||
explicit inline Time (double v)
|
||||
: m_data (lround (v))
|
||||
{}
|
||||
{
|
||||
TimeSet (this);
|
||||
}
|
||||
explicit inline Time (int v)
|
||||
: m_data (v)
|
||||
{}
|
||||
{
|
||||
TimeSet (this);
|
||||
}
|
||||
explicit inline Time (long int v)
|
||||
: m_data (v)
|
||||
{}
|
||||
{
|
||||
TimeSet (this);
|
||||
}
|
||||
explicit inline Time (long long int v)
|
||||
: m_data (v)
|
||||
{}
|
||||
{
|
||||
TimeSet (this);
|
||||
}
|
||||
explicit inline Time (unsigned int v)
|
||||
: m_data (v)
|
||||
{}
|
||||
{
|
||||
TimeSet (this);
|
||||
}
|
||||
explicit inline Time (unsigned long int v)
|
||||
: m_data (v)
|
||||
{}
|
||||
{
|
||||
TimeSet (this);
|
||||
}
|
||||
explicit inline Time (unsigned long long int v)
|
||||
: m_data (v)
|
||||
{}
|
||||
|
||||
{
|
||||
TimeSet (this);
|
||||
}
|
||||
/**
|
||||
* \brief String constructor
|
||||
* Construct Time object from common time expressions like "
|
||||
* 1ms" or "10s". Supported units include:
|
||||
* - s (seconds)
|
||||
* - ms (milliseconds)
|
||||
* - us (microseconds)
|
||||
* - ns (nanoseconds)
|
||||
* - ps (picoseconds)
|
||||
* - fs (femtoseconds)
|
||||
* \brief Construct Time object from common time expressions like "1ms"
|
||||
*
|
||||
* Supported units include:
|
||||
* - `s` (seconds)
|
||||
* - `ms` (milliseconds)
|
||||
* - `us` (microseconds)
|
||||
* - `ns` (nanoseconds)
|
||||
* - `ps` (picoseconds)
|
||||
* - `fs` (femtoseconds)
|
||||
*
|
||||
* There can be no white space between the numerical portion
|
||||
* and the units. Any otherwise malformed string causes a fatal error to
|
||||
@@ -214,6 +170,14 @@ public:
|
||||
*/
|
||||
explicit Time (const std::string & s);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Time ()
|
||||
{
|
||||
TimeUnset (this);
|
||||
}
|
||||
|
||||
/**
|
||||
* \return true if the time is zero, false otherwise.
|
||||
*/
|
||||
@@ -249,7 +213,9 @@ public:
|
||||
{
|
||||
return m_data > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return -1,0,+1 if `this < o`, `this == o`, or `this > o`
|
||||
*/
|
||||
inline int Compare (const Time &o) const
|
||||
{
|
||||
return (m_data < o.m_data) ? -1 : (m_data == o.m_data) ? 0 : 1;
|
||||
@@ -305,8 +271,7 @@ public:
|
||||
return ToInteger (Time::FS);
|
||||
}
|
||||
/**
|
||||
* \returns an approximation of the time stored in this
|
||||
* instance in the units specified in m_tsPrecision.
|
||||
* \returns the raw time value, in the current units
|
||||
*/
|
||||
inline int64_t GetTimeStep (void) const
|
||||
{
|
||||
@@ -436,30 +401,38 @@ public:
|
||||
}
|
||||
explicit inline Time (const int64x64_t &value)
|
||||
: m_data (value.GetHigh ())
|
||||
{}
|
||||
{
|
||||
TimeSet (this);
|
||||
}
|
||||
inline static Time From (const int64x64_t &value)
|
||||
{
|
||||
return Time (value);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* How to convert between other units and the current unit
|
||||
*/
|
||||
struct Information
|
||||
{
|
||||
bool toMul;
|
||||
bool fromMul;
|
||||
uint64_t factor;
|
||||
int64x64_t timeTo;
|
||||
int64x64_t timeFrom;
|
||||
bool toMul; //!< Multiply when converting To, otherwise divide
|
||||
bool fromMul; //!< Multiple when converting From, otherwise divide
|
||||
uint64_t factor; //!< Ratio of this unit / current unit
|
||||
int64x64_t timeTo; //!< Multiplier to convert to this unit
|
||||
int64x64_t timeFrom; //!< Multiplier to convert from this unit
|
||||
};
|
||||
/**
|
||||
* Current time unit, and conversion info.
|
||||
*/
|
||||
struct Resolution
|
||||
{
|
||||
struct Information info[LAST];
|
||||
enum Time::Unit unit;
|
||||
struct Information info[LAST]; //!< Conversion info from current unit
|
||||
enum Time::Unit unit; //!< Current time unit
|
||||
};
|
||||
|
||||
static inline struct Resolution *PeekResolution (void)
|
||||
{
|
||||
static struct Time::Resolution resolution = GetNsResolution ();
|
||||
static struct Time::Resolution resolution = SetDefaultNsResolution ();
|
||||
return &resolution;
|
||||
}
|
||||
static inline struct Information *PeekInformation (enum Unit timeUnit)
|
||||
@@ -467,8 +440,51 @@ private:
|
||||
return &(PeekResolution ()->info[timeUnit]);
|
||||
}
|
||||
|
||||
static struct Resolution GetNsResolution (void);
|
||||
static void SetResolution (enum Unit unit, struct Resolution *resolution);
|
||||
static struct Resolution SetDefaultNsResolution (void);
|
||||
static void SetResolution (enum Unit unit, struct Resolution *resolution,
|
||||
const bool convert = true);
|
||||
|
||||
/**
|
||||
* Record all instances of Time, so we can rescale them when
|
||||
* the resolution changes.
|
||||
*
|
||||
* \internal
|
||||
*
|
||||
* We use a std::set so we can remove the record easily when
|
||||
* ~Time() is called.
|
||||
*
|
||||
* We don't use Ptr<Time>, because we would have to bloat every Time
|
||||
* instance with SimpleRefCount<Time>.
|
||||
*
|
||||
* Seems like this should be std::set< Time * const >, but
|
||||
* http://stackoverflow.com/questions/5526019/compile-errors-stdset-with-const-members
|
||||
* (and gcc 4.2) say no.
|
||||
*/
|
||||
typedef std::set< Time * > TimesSet;
|
||||
/**
|
||||
* Get the TimesSet instance.
|
||||
*
|
||||
* \param [in] deleteMe If true delete the TimesSet, so that it returns a null pointer ever after
|
||||
*/
|
||||
static TimesSet * GetTimesSet ( const bool deleteMe = false );
|
||||
/**
|
||||
* Helper to clean up at Simulator::Run
|
||||
*/
|
||||
static void DeleteTimesSet ();
|
||||
/**
|
||||
* Record a Time instance with the TimesSet
|
||||
*/
|
||||
static void TimeSet (Time * const time);
|
||||
/**
|
||||
* Remove a Time instance from the TimesSet, called by ~Time()
|
||||
*/
|
||||
static void TimeUnset (Time * const time);
|
||||
|
||||
|
||||
/**
|
||||
* Convert existing Times to the new unit.
|
||||
*/
|
||||
static void ConvertTimes (const enum Unit unit);
|
||||
|
||||
friend bool operator == (const Time &lhs, const Time &rhs);
|
||||
friend bool operator != (const Time &lhs, const Time &rhs);
|
||||
@@ -537,8 +553,8 @@ inline Time &operator -= (Time &lhs, const Time &rhs)
|
||||
}
|
||||
|
||||
/**
|
||||
* \anchor ns3-Time-Abs
|
||||
* \relates ns3::TimeUnit
|
||||
* Absolute value function for Time
|
||||
*
|
||||
* \param time the input value
|
||||
* \returns the absolute value of the input value.
|
||||
*/
|
||||
@@ -547,8 +563,6 @@ inline Time Abs (const Time &time)
|
||||
return Time ((time.m_data < 0) ? -time.m_data : time.m_data);
|
||||
}
|
||||
/**
|
||||
* \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.
|
||||
@@ -558,8 +572,6 @@ inline Time Max (const Time &ta, const Time &tb)
|
||||
return Time ((ta.m_data < tb.m_data) ? tb : ta);
|
||||
}
|
||||
/**
|
||||
* \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.
|
||||
@@ -570,7 +582,19 @@ inline Time Min (const Time &ta, const Time &tb)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Time output streamer.
|
||||
*
|
||||
* Generates output such as "3.96ns"
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
std::ostream& operator<< (std::ostream& os, const Time & time);
|
||||
/**
|
||||
* \brief Time input streamer
|
||||
*
|
||||
* Uses the Time::Time (std::string) constructor
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
std::istream& operator>> (std::istream& is, Time & time);
|
||||
|
||||
/**
|
||||
@@ -582,6 +606,7 @@ std::istream& operator>> (std::istream& is, Time & time);
|
||||
* Simulator::Schedule (Seconds (5.0), ...);
|
||||
* \endcode
|
||||
* \param seconds seconds value
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time Seconds (double seconds)
|
||||
{
|
||||
@@ -597,6 +622,7 @@ inline Time Seconds (double seconds)
|
||||
* Simulator::Schedule (MilliSeconds (5), ...);
|
||||
* \endcode
|
||||
* \param ms milliseconds value
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time MilliSeconds (uint64_t ms)
|
||||
{
|
||||
@@ -611,6 +637,7 @@ inline Time MilliSeconds (uint64_t ms)
|
||||
* Simulator::Schedule (MicroSeconds (5), ...);
|
||||
* \endcode
|
||||
* \param us microseconds value
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time MicroSeconds (uint64_t us)
|
||||
{
|
||||
@@ -625,6 +652,7 @@ inline Time MicroSeconds (uint64_t us)
|
||||
* Simulator::Schedule (NanoSeconds (5), ...);
|
||||
* \endcode
|
||||
* \param ns nanoseconds value
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time NanoSeconds (uint64_t ns)
|
||||
{
|
||||
@@ -639,6 +667,7 @@ inline Time NanoSeconds (uint64_t ns)
|
||||
* Simulator::Schedule (PicoSeconds (5), ...);
|
||||
* \endcode
|
||||
* \param ps picoseconds value
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time PicoSeconds (uint64_t ps)
|
||||
{
|
||||
@@ -653,6 +682,7 @@ inline Time PicoSeconds (uint64_t ps)
|
||||
* Simulator::Schedule (FemtoSeconds (5), ...);
|
||||
* \endcode
|
||||
* \param fs femtoseconds value
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time FemtoSeconds (uint64_t fs)
|
||||
{
|
||||
@@ -660,26 +690,50 @@ inline Time FemtoSeconds (uint64_t fs)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \see Seconds(double)
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time Seconds (int64x64_t seconds)
|
||||
{
|
||||
return Time::From (seconds, Time::S);
|
||||
}
|
||||
/**
|
||||
* \see MilliSeconds(uint64_t)
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time MilliSeconds (int64x64_t ms)
|
||||
{
|
||||
return Time::From (ms, Time::MS);
|
||||
}
|
||||
/**
|
||||
* \see MicroSeconds(uint64_t)
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time MicroSeconds (int64x64_t us)
|
||||
{
|
||||
return Time::From (us, Time::US);
|
||||
}
|
||||
/**
|
||||
* \see NanoSeconds(uint64_t)
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time NanoSeconds (int64x64_t ns)
|
||||
{
|
||||
return Time::From (ns, Time::NS);
|
||||
}
|
||||
/**
|
||||
* \see PicoSeconds(uint64_t)
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time PicoSeconds (int64x64_t ps)
|
||||
{
|
||||
return Time::From (ps, Time::PS);
|
||||
}
|
||||
/**
|
||||
* \see FemtoSeconds(uint64_t)
|
||||
* \relates ns3::Time
|
||||
*/
|
||||
inline Time FemtoSeconds (int64x64_t fs)
|
||||
{
|
||||
return Time::From (fs, Time::FS);
|
||||
|
||||
@@ -21,22 +21,22 @@
|
||||
*/
|
||||
#include "nstime.h"
|
||||
#include "abort.h"
|
||||
#include "log.h"
|
||||
#include "global-value.h"
|
||||
#include "enum.h"
|
||||
#include "string.h"
|
||||
#include "object.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "simulator.h"
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("Time");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
Time::Time (const std::string& s)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << &s);
|
||||
std::string::size_type n = s.find_first_not_of ("+-0123456789.");
|
||||
if (n != std::string::npos)
|
||||
{ // Found non-numeric
|
||||
@@ -48,62 +48,82 @@ Time::Time (const std::string& s)
|
||||
if (trailer == std::string ("s"))
|
||||
{
|
||||
*this = Time::FromDouble (r, Time::S);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string ("ms"))
|
||||
else if (trailer == std::string ("ms"))
|
||||
{
|
||||
*this = Time::FromDouble (r, Time::MS);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string ("us"))
|
||||
else if (trailer == std::string ("us"))
|
||||
{
|
||||
*this = Time::FromDouble (r, Time::US);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string ("ns"))
|
||||
else if (trailer == std::string ("ns"))
|
||||
{
|
||||
*this = Time::FromDouble (r, Time::NS);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string ("ps"))
|
||||
else if (trailer == std::string ("ps"))
|
||||
{
|
||||
*this = Time::FromDouble (r, Time::PS);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string ("fs"))
|
||||
else if (trailer == std::string ("fs"))
|
||||
{
|
||||
*this = Time::FromDouble (r, Time::FS);
|
||||
return;
|
||||
}
|
||||
NS_ABORT_MSG ("Can't Parse Time " << s);
|
||||
else
|
||||
{
|
||||
NS_ABORT_MSG ("Can't Parse Time " << s);
|
||||
}
|
||||
}
|
||||
// else
|
||||
// they didn't provide units, assume seconds
|
||||
std::istringstream iss;
|
||||
iss.str (s);
|
||||
double v;
|
||||
iss >> v;
|
||||
*this = Time::FromDouble (v, Time::S);
|
||||
else
|
||||
{
|
||||
// they didn't provide units, assume seconds
|
||||
std::istringstream iss;
|
||||
iss.str (s);
|
||||
double v;
|
||||
iss >> v;
|
||||
*this = Time::FromDouble (v, Time::S);
|
||||
}
|
||||
|
||||
TimeSet (this);
|
||||
}
|
||||
|
||||
// static
|
||||
struct Time::Resolution
|
||||
Time::GetNsResolution (void)
|
||||
Time::SetDefaultNsResolution (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
struct Resolution resolution;
|
||||
SetResolution (Time::NS, &resolution);
|
||||
SetResolution (Time::NS, &resolution, false);
|
||||
return resolution;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
Time::SetResolution (enum Unit resolution)
|
||||
{
|
||||
NS_LOG_FUNCTION (resolution);
|
||||
SetResolution (resolution, PeekResolution ());
|
||||
}
|
||||
void
|
||||
Time::SetResolution (enum Unit unit, struct Resolution *resolution)
|
||||
|
||||
// static
|
||||
enum Time::Unit
|
||||
Time::GetResolution (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (unit << resolution);
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return PeekResolution ()->unit;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
Time::SetResolution (enum Unit unit, struct Resolution *resolution,
|
||||
const bool convert /* = true */)
|
||||
{
|
||||
NS_LOG_FUNCTION (unit << resolution << convert);
|
||||
if (convert)
|
||||
{ // We have to convert old values
|
||||
ConvertTimes (unit);
|
||||
}
|
||||
|
||||
int8_t power [LAST] = { 15, 12, 9, 6, 3, 0};
|
||||
for (int i = 0; i < Time::LAST; i++)
|
||||
{
|
||||
@@ -136,18 +156,115 @@ Time::SetResolution (enum Unit unit, struct Resolution *resolution)
|
||||
}
|
||||
resolution->unit = unit;
|
||||
}
|
||||
enum Time::Unit
|
||||
Time::GetResolution (void)
|
||||
|
||||
|
||||
// static
|
||||
Time::TimesSet *
|
||||
Time::GetTimesSet ( const bool deleteMe /* = false */ )
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return PeekResolution ()->unit;
|
||||
static TimesSet * times = new TimesSet;
|
||||
|
||||
if (deleteMe)
|
||||
{
|
||||
NS_LOG_LOGIC ("deleting TimesSet");
|
||||
if (times)
|
||||
{
|
||||
delete times;
|
||||
}
|
||||
times = 0;
|
||||
}
|
||||
|
||||
return times;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
Time::DeleteTimesSet ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
Time::GetTimesSet (true);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
Time::TimeSet (Time * const time)
|
||||
{
|
||||
NS_ASSERT (time != 0);
|
||||
|
||||
TimesSet * times = GetTimesSet();
|
||||
if (times)
|
||||
{
|
||||
std::pair< TimesSet::iterator, bool> ret;
|
||||
ret = times->insert ( time);
|
||||
NS_LOG_LOGIC ("\t[" << times->size () << "] recording " << time);
|
||||
|
||||
if (ret.second == false)
|
||||
{
|
||||
NS_LOG_WARN ("already recorded " << time << "!");
|
||||
}
|
||||
// If this is the first Time, schedule the cleanup.
|
||||
if (times->size () == 1)
|
||||
{
|
||||
// We schedule here, after the first event has been added,
|
||||
// rather than in GetTimesSet when the set is empty.
|
||||
// Scheduling there creates another Time, which
|
||||
// finds an empty set and schedules an event . . .
|
||||
// Doing it here, the schedule creates the second Time,
|
||||
// which doesn't recurse.
|
||||
NS_LOG_LOGIC ("scheduling DeleteTimesSet()");
|
||||
Simulator::Schedule ( Seconds (0), & DeleteTimesSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
Time::TimeUnset (Time * const time)
|
||||
{
|
||||
NS_ASSERT (time != 0);
|
||||
TimesSet * times = GetTimesSet ();
|
||||
if (times)
|
||||
{
|
||||
NS_ASSERT_MSG (times->count (time) == 1,
|
||||
"Time object " << time << " registered "
|
||||
<< times->count (time) << " times (should be 1)." );
|
||||
|
||||
TimesSet::size_type num = times->erase (time);
|
||||
if (num != 1)
|
||||
{
|
||||
NS_LOG_WARN ("unexpected result erasing " << time << "!");
|
||||
NS_LOG_WARN ("got " << num << ", expected 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_LOGIC ("\t[" << times->size () << "] removing " << time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
Time::ConvertTimes (const enum Unit unit)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
TimesSet * times = GetTimesSet ();
|
||||
NS_ASSERT_MSG (times != 0, "No Time registry. Time::SetResolution () called mare than once?");
|
||||
|
||||
for ( TimesSet::iterator it = times->begin();
|
||||
it != times->end();
|
||||
it++ )
|
||||
{
|
||||
Time * const tp = *it;
|
||||
(*tp) = tp->ToInteger (unit);
|
||||
}
|
||||
|
||||
NS_LOG_LOGIC ("logged " << GetTimesSet ()->size () << " Time objects.");
|
||||
GetTimesSet (true);
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<< (std::ostream& os, const Time & time)
|
||||
{
|
||||
NS_LOG_FUNCTION (&os << time);
|
||||
std::string unit;
|
||||
switch (Time::GetResolution ())
|
||||
{
|
||||
@@ -180,7 +297,6 @@ operator<< (std::ostream& os, const Time & time)
|
||||
}
|
||||
std::istream& operator>> (std::istream& is, Time & time)
|
||||
{
|
||||
NS_LOG_FUNCTION (&is << time);
|
||||
std::string value;
|
||||
is >> value;
|
||||
time = Time (value);
|
||||
|
||||
@@ -27,31 +27,26 @@ using namespace ns3;
|
||||
class TimeSimpleTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
TimeSimpleTestCase (enum Time::Unit resolution);
|
||||
TimeSimpleTestCase ();
|
||||
private:
|
||||
virtual void DoSetup (void);
|
||||
virtual void 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)
|
||||
TimeSimpleTestCase::TimeSimpleTestCase ()
|
||||
: TestCase ("Sanity check of common time operations")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TimeSimpleTestCase::DoSetup (void)
|
||||
{
|
||||
m_originalResolution = Time::GetResolution ();
|
||||
}
|
||||
|
||||
void
|
||||
TimeSimpleTestCase::DoRun (void)
|
||||
{
|
||||
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 (),
|
||||
@@ -70,12 +65,18 @@ TimeSimpleTestCase::DoRun (void)
|
||||
NS_TEST_ASSERT_MSG_EQ (FemtoSeconds (1).GetFemtoSeconds (), 1,
|
||||
"is 1fs really 1fs ?");
|
||||
#endif
|
||||
|
||||
Time ten = NanoSeconds (10);
|
||||
int64_t tenValue = ten.GetInteger ();
|
||||
Time::SetResolution (Time::PS);
|
||||
int64_t tenKValue = ten.GetInteger ();
|
||||
NS_TEST_ASSERT_MSG_EQ (tenValue * 1000, tenKValue,
|
||||
"change resolution to PS");
|
||||
}
|
||||
|
||||
void
|
||||
TimeSimpleTestCase::DoTeardown (void)
|
||||
{
|
||||
Time::SetResolution (m_originalResolution);
|
||||
}
|
||||
|
||||
class TimesWithSignsTestCase : public TestCase
|
||||
@@ -139,7 +140,7 @@ public:
|
||||
TimeTestSuite ()
|
||||
: TestSuite ("time", UNIT)
|
||||
{
|
||||
AddTestCase (new TimeSimpleTestCase (Time::US));
|
||||
AddTestCase (new TimeSimpleTestCase ());
|
||||
AddTestCase (new TimesWithSignsTestCase ());
|
||||
}
|
||||
} g_timeTestSuite;
|
||||
|
||||
Reference in New Issue
Block a user