From f1734920c94263472cb6dfee52f1459ab239040b Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sat, 15 Dec 2012 23:02:03 -0800 Subject: [PATCH] bug 954: back out changesets 1a2abe07b53d, 8934b7c0c1cb, and 8ef8d8bae350 --- doc/tutorial/source/conceptual-overview.rst | 14 - examples/tutorial/first.cc | 1 - src/core/bindings/callbacks_list.py | 2 +- src/core/bindings/modulegen__gcc_ILP32.py | 13 +- src/core/bindings/modulegen__gcc_LP64.py | 13 +- src/core/model/nstime.h | 329 ++++++++------------ src/core/model/simulator.cc | 4 +- src/core/model/time.cc | 157 ++-------- src/core/test/time-test-suite.cc | 21 +- 9 files changed, 192 insertions(+), 362 deletions(-) diff --git a/doc/tutorial/source/conceptual-overview.rst b/doc/tutorial/source/conceptual-overview.rst index ef73d38c7..d0538a33b 100644 --- a/doc/tutorial/source/conceptual-overview.rst +++ b/doc/tutorial/source/conceptual-overview.rst @@ -340,20 +340,6 @@ 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: diff --git a/examples/tutorial/first.cc b/examples/tutorial/first.cc index 747d5bc7e..f01f88b87 100644 --- a/examples/tutorial/first.cc +++ b/examples/tutorial/first.cc @@ -27,7 +27,6 @@ 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); diff --git a/src/core/bindings/callbacks_list.py b/src/core/bindings/callbacks_list.py index 06db4d3ee..75ca68043 100644 --- a/src/core/bindings/callbacks_list.py +++ b/src/core/bindings/callbacks_list.py @@ -1,5 +1,5 @@ callback_classes = [ - ['void', 'unsigned char*', 'long', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'], + ['void', 'unsigned char*', 'int', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'], ['void', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'], ['bool', 'std::string', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'], ] diff --git a/src/core/bindings/modulegen__gcc_ILP32.py b/src/core/bindings/modulegen__gcc_ILP32.py index 61d966820..2d14c2e68 100644 --- a/src/core/bindings/modulegen__gcc_ILP32.py +++ b/src/core/bindings/modulegen__gcc_ILP32.py @@ -310,10 +310,6 @@ def register_types(module): module.add_class('Vector3DChecker', parent=root_module['ns3::AttributeChecker']) ## vector.h (module 'core'): ns3::Vector3DValue [class] module.add_class('Vector3DValue', parent=root_module['ns3::AttributeValue']) - typehandlers.add_type_alias('ns3::Vector3D', 'ns3::Vector') - typehandlers.add_type_alias('ns3::Vector3D*', 'ns3::Vector*') - typehandlers.add_type_alias('ns3::Vector3D&', 'ns3::Vector&') - module.add_typedef(root_module['ns3::Vector3D'], 'Vector') typehandlers.add_type_alias('ns3::ObjectPtrContainerValue', 'ns3::ObjectVectorValue') typehandlers.add_type_alias('ns3::ObjectPtrContainerValue*', 'ns3::ObjectVectorValue*') typehandlers.add_type_alias('ns3::ObjectPtrContainerValue&', 'ns3::ObjectVectorValue&') @@ -328,6 +324,10 @@ def register_types(module): typehandlers.add_type_alias('void ( * ) ( std::ostream & ) *', 'ns3::LogNodePrinter') typehandlers.add_type_alias('void ( * ) ( std::ostream & ) **', 'ns3::LogNodePrinter*') typehandlers.add_type_alias('void ( * ) ( std::ostream & ) *&', 'ns3::LogNodePrinter&') + typehandlers.add_type_alias('ns3::Vector3D', 'ns3::Vector') + typehandlers.add_type_alias('ns3::Vector3D*', 'ns3::Vector*') + typehandlers.add_type_alias('ns3::Vector3D&', 'ns3::Vector&') + module.add_typedef(root_module['ns3::Vector3D'], 'Vector') typehandlers.add_type_alias('ns3::Vector3DValue', 'ns3::VectorValue') typehandlers.add_type_alias('ns3::Vector3DValue*', 'ns3::VectorValue*') typehandlers.add_type_alias('ns3::Vector3DValue&', 'ns3::VectorValue&') @@ -2382,11 +2382,6 @@ def register_Ns3Time_methods(root_module, cls): 'int', [param('ns3::Time const &', 'o')], is_const=True) - ## nstime.h (module 'core'): static void ns3::Time::FreezeResolution() [member function] - cls.add_method('FreezeResolution', - 'void', - [], - is_static=True) ## nstime.h (module 'core'): static ns3::Time ns3::Time::From(ns3::int64x64_t const & from, ns3::Time::Unit timeUnit) [member function] cls.add_method('From', 'ns3::Time', diff --git a/src/core/bindings/modulegen__gcc_LP64.py b/src/core/bindings/modulegen__gcc_LP64.py index a943a6961..b97693457 100644 --- a/src/core/bindings/modulegen__gcc_LP64.py +++ b/src/core/bindings/modulegen__gcc_LP64.py @@ -310,10 +310,6 @@ def register_types(module): module.add_class('Vector3DChecker', parent=root_module['ns3::AttributeChecker']) ## vector.h (module 'core'): ns3::Vector3DValue [class] module.add_class('Vector3DValue', parent=root_module['ns3::AttributeValue']) - typehandlers.add_type_alias('ns3::Vector3D', 'ns3::Vector') - typehandlers.add_type_alias('ns3::Vector3D*', 'ns3::Vector*') - typehandlers.add_type_alias('ns3::Vector3D&', 'ns3::Vector&') - module.add_typedef(root_module['ns3::Vector3D'], 'Vector') typehandlers.add_type_alias('ns3::ObjectPtrContainerValue', 'ns3::ObjectVectorValue') typehandlers.add_type_alias('ns3::ObjectPtrContainerValue*', 'ns3::ObjectVectorValue*') typehandlers.add_type_alias('ns3::ObjectPtrContainerValue&', 'ns3::ObjectVectorValue&') @@ -328,6 +324,10 @@ def register_types(module): typehandlers.add_type_alias('void ( * ) ( std::ostream & ) *', 'ns3::LogNodePrinter') typehandlers.add_type_alias('void ( * ) ( std::ostream & ) **', 'ns3::LogNodePrinter*') typehandlers.add_type_alias('void ( * ) ( std::ostream & ) *&', 'ns3::LogNodePrinter&') + typehandlers.add_type_alias('ns3::Vector3D', 'ns3::Vector') + typehandlers.add_type_alias('ns3::Vector3D*', 'ns3::Vector*') + typehandlers.add_type_alias('ns3::Vector3D&', 'ns3::Vector&') + module.add_typedef(root_module['ns3::Vector3D'], 'Vector') typehandlers.add_type_alias('ns3::Vector3DValue', 'ns3::VectorValue') typehandlers.add_type_alias('ns3::Vector3DValue*', 'ns3::VectorValue*') typehandlers.add_type_alias('ns3::Vector3DValue&', 'ns3::VectorValue&') @@ -2382,11 +2382,6 @@ def register_Ns3Time_methods(root_module, cls): 'int', [param('ns3::Time const &', 'o')], is_const=True) - ## nstime.h (module 'core'): static void ns3::Time::FreezeResolution() [member function] - cls.add_method('FreezeResolution', - 'void', - [], - is_static=True) ## nstime.h (module 'core'): static ns3::Time ns3::Time::From(ns3::int64x64_t const & from, ns3::Time::Unit timeUnit) [member function] cls.add_method('From', 'ns3::Time', diff --git a/src/core/model/nstime.h b/src/core/model/nstime.h index bfe41b91a..5102700d5 100644 --- a/src/core/model/nstime.h +++ b/src/core/model/nstime.h @@ -26,7 +26,6 @@ #include "int64x64.h" #include #include -#include #include namespace ns3 { @@ -37,48 +36,115 @@ namespace ns3 { */ /** * \ingroup time - * \brief Keep track of time values and allow control of global simulation resolution. + * \brief keep track of time unit. * - * This class defines the classic addition/subtraction C++ arithmetic - * operators +, -, +=, -=, and all the classic comparison operators: + * 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: * ==, !=, <, >, <=, >=. It is thus easy to add, substract, or - * compare Time objects. + * 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. * * For example: * \code * Time t1 = Seconds (10.0); * Time t2 = Seconds (10.0); - * Time t3 = t1; - * t3 += t2; + * Time t3 = t1 * t2; + * Time t4 = t1 / t2; + * Time t5 = t3 * t1; + * Time t6 = t1 / t5; + * Time t7 = t3; * \endcode * * You can also use the following non-member functions to manipulate * any of these ns3::Time object: - * - \ref Abs() - * - \ref Max() - * - \ref Min() + * - \ref ns3-Time-Abs ns3::Abs + * - \ref ns3-Time-Max ns3::Max + * - \ref ns3-Time-Min ns3::Min * - * This class also controls the resolution of the underlying time value. - * The resolution is the smallest representable time interval. - * The default resolution is nanoseconds. + * 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. * - * 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.) + * 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. * - * Because of the memory (and modest construction cost) of tracking Time - * objects, simulations should explicitly choose a resolution before - * calling Simulator::Run (). + * 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. * - * 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. + * Finally, don't even think about ever changing the global resolution after + * creating Time objects: all Time objects created before the call to SetResolution + * will contain values which are not updated to the new resolution. In practice, + * the default value for the attributes of many models is indeed calculated + * before the main function of the main program enters. Because of this, if you + * use one of these models (and it's likely), it's going to be hard to change + * the global simulation resolution in a way which gives reasonable results. This + * issue has been filed as bug 954 in the ns-3 bugzilla installation. */ class Time { @@ -88,12 +154,12 @@ public: */ enum Unit { - S = 0, //!< second - MS = 1, //!< millisecond - US = 2, //!< microsecond - NS = 3, //!< nanosecond - PS = 4, //!< picosecond - FS = 5, //!< femtosecond + S = 0, + MS = 1, + US = 2, + NS = 3, + PS = 4, + FS = 5, LAST = 6 }; @@ -102,66 +168,44 @@ public: m_data = o.m_data; return *this; } - inline Time &operator = (const int64_t &value) - { - m_data = value; - return *this; - } inline Time () : m_data () - { - Time::Track (this); - } + {} inline Time(const Time &o) : m_data (o.m_data) - { - Time::Track (this); - } + {} explicit inline Time (double v) : m_data (lround (v)) - { - Time::Track (this); - } + {} explicit inline Time (int v) : m_data (v) - { - Time::Track (this); - } + {} explicit inline Time (long int v) : m_data (v) - { - Time::Track (this); - } + {} explicit inline Time (long long int v) : m_data (v) - { - Time::Track (this); - } + {} explicit inline Time (unsigned int v) : m_data (v) - { - Time::Track (this); - } + {} explicit inline Time (unsigned long int v) : m_data (v) - { - Time::Track (this); - } + {} explicit inline Time (unsigned long long int v) : m_data (v) - { - Time::Track (this); - } + {} + /** - * \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) + * \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) * * There can be no white space between the numerical portion * and the units. Any otherwise malformed string causes a fatal error to @@ -170,14 +214,6 @@ public: */ explicit Time (const std::string & s); - /** - * Destructor - */ - ~Time () - { - Time::UnTrack (this); - } - /** * \return true if the time is zero, false otherwise. */ @@ -213,9 +249,7 @@ 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; @@ -271,7 +305,8 @@ public: return ToInteger (Time::FS); } /** - * \returns the raw time value, in the current units + * \returns an approximation of the time stored in this + * instance in the units specified in m_tsPrecision. */ inline int64_t GetTimeStep (void) const { @@ -293,18 +328,8 @@ public: * Change the global resolution used to convert all * user-provided time values in Time objects and Time objects * in user-expected time units. - * - * This function can be called only once. Further calls - * will trigger a forced crash. */ static void SetResolution (enum Unit resolution); - /** - * Freeze the current time resolution. This function is called - * internally from the Simulator::Run function. After this - * function is called, calls to SetResolution will trigger - * an assert. - */ - static void FreezeResolution(void); /** * \returns the current global resolution. */ @@ -411,38 +436,30 @@ public: } explicit inline Time (const int64x64_t &value) : m_data (value.GetHigh ()) - { - Time::Track (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; //!< 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 + bool toMul; + bool fromMul; + uint64_t factor; + int64x64_t timeTo; + int64x64_t timeFrom; }; - /** - * Current time unit, and conversion info. - */ struct Resolution { - struct Information info[LAST]; //!< Conversion info from current unit - enum Time::Unit unit; //!< Current time unit + struct Information info[LAST]; + enum Time::Unit unit; }; static inline struct Resolution *PeekResolution (void) { - static struct Time::Resolution resolution = SetDefaultNsResolution (); + static struct Time::Resolution resolution = GetNsResolution (); return &resolution; } static inline struct Information *PeekInformation (enum Unit timeUnit) @@ -450,40 +467,8 @@ private: return &(PeekResolution ()->info[timeUnit]); } - static struct Resolution SetDefaultNsResolution (void); + static struct Resolution GetNsResolution (void); static void SetResolution (enum Unit unit, struct Resolution *resolution); - static void DoSetResolution (enum Unit unit, struct Resolution *resolution); - static void FreezeResolution(enum Unit unit); - - /** - * 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