A Discrete-Event Network Simulator
API
time.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2005,2006 INRIA
4  * Copyright (c) 2007 Emmanuelle Laprise
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation;
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
20  * TimeStep support by Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
21  */
22 #include "nstime.h"
23 #include "abort.h"
24 #include "system-mutex.h"
25 #include "log.h"
26 #include <cmath>
27 #include <iomanip> // showpos
28 #include <sstream>
29 
37 namespace ns3 {
38 
40 
41 // The set of marked times
42 // static
44 
53 SystemMutex &
55 {
56  static SystemMutex g_markingMutex;
57  return g_markingMutex;
58 }
59 
60 
61 // Function called to force static initialization
62 // static
64 {
65  static bool firstTime = true;
66 
67  CriticalSection critical (GetMarkingMutex ());
68 
69  if (firstTime)
70  {
71  if (!g_markingTimes)
72  {
73  static MarkedTimes markingTimes;
74  g_markingTimes = &markingTimes;
75  }
76  else
77  {
78  NS_LOG_ERROR ("firstTime but g_markingTimes != 0");
79  }
80 
81  // Schedule the cleanup.
82  // We'd really like:
83  // NS_LOG_LOGIC ("scheduling ClearMarkedTimes()");
84  // Simulator::Schedule ( Seconds (0), & ClearMarkedTimes);
85  // [or even better: Simulator::AtStart ( & ClearMarkedTimes ); ]
86  // But this triggers a static initialization order error,
87  // since the Simulator static initialization may not have occurred.
88  // Instead, we call ClearMarkedTimes directly from Simulator::Run ()
89  firstTime = false;
90  }
91 
92  return firstTime;
93 }
94 
95 
96 Time::Time (const std::string& s)
97 {
98  NS_LOG_FUNCTION (this << &s);
99  std::string::size_type n = s.find_first_not_of ("+-0123456789.eE");
100  if (n != std::string::npos)
101  { // Found non-numeric
102  std::istringstream iss;
103  iss.str (s.substr (0, n));
104  double r;
105  iss >> r;
106  std::string trailer = s.substr (n, std::string::npos);
107  if (trailer == std::string ("s"))
108  {
109  *this = Time::FromDouble (r, Time::S);
110  }
111  else if (trailer == std::string ("ms"))
112  {
113  *this = Time::FromDouble (r, Time::MS);
114  }
115  else if (trailer == std::string ("us"))
116  {
117  *this = Time::FromDouble (r, Time::US);
118  }
119  else if (trailer == std::string ("ns"))
120  {
121  *this = Time::FromDouble (r, Time::NS);
122  }
123  else if (trailer == std::string ("ps"))
124  {
125  *this = Time::FromDouble (r, Time::PS);
126  }
127  else if (trailer == std::string ("fs"))
128  {
129  *this = Time::FromDouble (r, Time::FS);
130  }
131  else if (trailer == std::string ("min"))
132  {
133  *this = Time::FromDouble (r, Time::MIN);
134  }
135  else if (trailer == std::string ("h"))
136  {
137  *this = Time::FromDouble (r, Time::H);
138  }
139  else if (trailer == std::string ("d"))
140  {
141  *this = Time::FromDouble (r, Time::D);
142  }
143  else if (trailer == std::string ("y"))
144  {
145  *this = Time::FromDouble (r, Time::Y);
146  }
147  else
148  {
149  NS_ABORT_MSG ("Can't Parse Time " << s);
150  }
151  }
152  else
153  {
154  // they didn't provide units, assume seconds
155  std::istringstream iss;
156  iss.str (s);
157  double v;
158  iss >> v;
159  *this = Time::FromDouble (v, Time::S);
160  }
161 
162  if (g_markingTimes)
163  {
164  Mark (this);
165  }
166 }
167 
168 // static
169 struct Time::Resolution
170 Time::SetDefaultNsResolution (void)
171 {
173  struct Resolution resolution;
174  SetResolution (Time::NS, &resolution, false);
175  return resolution;
176 }
177 
178 // static
179 void
180 Time::SetResolution (enum Unit resolution)
181 {
182  NS_LOG_FUNCTION (resolution);
183  SetResolution (resolution, PeekResolution ());
184 }
185 
186 
187 // static
188 void
189 Time::SetResolution (enum Unit unit, struct Resolution *resolution,
190  const bool convert /* = true */)
191 {
192  NS_LOG_FUNCTION (resolution);
193  if (convert)
194  {
195  // We have to convert existing Times with the old
196  // conversion values, so do it first
197  ConvertTimes (unit);
198  }
199 
200  // Y, D, H, MIN, S, MS, US, NS, PS, FS
201  const int8_t power[LAST] = { 17, 17, 17, 16, 15, 12, 9, 6, 3, 0 };
202  const int32_t coefficient[LAST] = { 315360, 864, 36, 6, 1, 1, 1, 1, 1, 1 };
203  for (int i = 0; i < Time::LAST; i++)
204  {
205  int shift = power[i] - power[(int)unit];
206  int quotient = 1;
207  if (coefficient[i] > coefficient[(int) unit])
208  {
209  quotient = coefficient[i] / coefficient[(int) unit];
210  NS_ASSERT (quotient * coefficient[(int) unit] == coefficient[i]);
211  }
212  else if (coefficient[i] < coefficient[(int) unit])
213  {
214  quotient = coefficient[(int) unit] / coefficient[i];
215  NS_ASSERT (quotient * coefficient[i] == coefficient[(int) unit]);
216  }
217  NS_LOG_DEBUG ("SetResolution for unit " << (int) unit <<
218  " loop iteration " << i <<
219  " has shift " << shift << " has quotient " << quotient);
220  int64_t factor = static_cast<int64_t> (std::pow (10, std::fabs (shift)) * quotient);
221  double realFactor = std::pow (10, (double) shift)
222  * static_cast<double> (coefficient[i]) / coefficient[(int) unit];
223  NS_LOG_DEBUG ("SetResolution factor " << factor << " real factor " << realFactor);
224  struct Information *info = &resolution->info[i];
225  info->factor = factor;
226  // here we could equivalently check for realFactor == 1.0 but it's better
227  // to avoid checking equality of doubles
228  if (shift == 0 && quotient == 1)
229  {
230  info->timeFrom = int64x64_t (1);
231  info->timeTo = int64x64_t (1);
232  info->toMul = true;
233  info->fromMul = true;
234  }
235  else if (realFactor > 1)
236  {
237  info->timeFrom = int64x64_t (factor);
238  info->timeTo = int64x64_t::Invert (factor);
239  info->toMul = false;
240  info->fromMul = true;
241  }
242  else
243  {
244  NS_ASSERT (realFactor < 1);
245  info->timeFrom = int64x64_t::Invert (factor);
246  info->timeTo = int64x64_t (factor);
247  info->toMul = true;
248  info->fromMul = false;
249  }
250  }
251  resolution->unit = unit;
252 }
253 
254 
255 // static
256 void
258 {
274  CriticalSection critical (GetMarkingMutex ());
275 
277  if (g_markingTimes)
278  {
279  NS_LOG_LOGIC ("clearing MarkedTimes");
280  g_markingTimes->erase (g_markingTimes->begin (), g_markingTimes->end ());
281  g_markingTimes = 0;
282  }
283 } // Time::ClearMarkedTimes
284 
285 
286 // static
287 void
288 Time::Mark (Time * const time)
289 {
290  CriticalSection critical (GetMarkingMutex ());
291 
292  NS_LOG_FUNCTION (time);
293  NS_ASSERT (time != 0);
294 
295  // Repeat the g_markingTimes test here inside the CriticalSection,
296  // since earlier test was outside and might be stale.
297  if (g_markingTimes)
298  {
299  std::pair< MarkedTimes::iterator, bool> ret;
300 
301  ret = g_markingTimes->insert ( time);
302  NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] recording " << time);
303 
304  if (ret.second == false)
305  {
306  NS_LOG_WARN ("already recorded " << time << "!");
307  }
308  }
309 } // Time::Mark ()
310 
311 
312 // static
313 void
314 Time::Clear (Time * const time)
315 {
316  CriticalSection critical (GetMarkingMutex ());
317 
318  NS_LOG_FUNCTION (time);
319  NS_ASSERT (time != 0);
320 
321  if (g_markingTimes)
322  {
323  NS_ASSERT_MSG (g_markingTimes->count (time) == 1,
324  "Time object " << time <<
325  " registered " << g_markingTimes->count (time) <<
326  " times (should be 1)." );
327 
328  MarkedTimes::size_type num = g_markingTimes->erase (time);
329  if (num != 1)
330  {
331  NS_LOG_WARN ("unexpected result erasing " << time << "!");
332  NS_LOG_WARN ("got " << num << ", expected 1");
333  }
334  else
335  {
336  NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] removing " << time);
337  }
338  }
339 } // Time::Clear ()
340 
341 
342 // static
343 void
344 Time::ConvertTimes (const enum Unit unit)
345 {
346  CriticalSection critical (GetMarkingMutex ());
347 
349 
351  "No MarkedTimes registry. "
352  "Time::SetResolution () called more than once?");
353 
354  for ( MarkedTimes::iterator it = g_markingTimes->begin ();
355  it != g_markingTimes->end ();
356  it++ )
357  {
358  Time * const tp = *it;
359  if ( !((tp->m_data == std::numeric_limits<int64_t>::min ())
361  )
362  )
363  {
364  tp->m_data = tp->ToInteger (unit);
365  }
366  }
367 
368  NS_LOG_LOGIC ("logged " << g_markingTimes->size () << " Time objects.");
369 
370  // Body of ClearMarkedTimes
371  // Assert above already guarantees g_markingTimes != 0
372  NS_LOG_LOGIC ("clearing MarkedTimes");
373  g_markingTimes->erase (g_markingTimes->begin (), g_markingTimes->end ());
374  g_markingTimes = 0;
375 
376 } // Time::ConvertTimes ()
377 
378 
379 // static
380 enum Time::Unit
382 {
383  // No function log b/c it interferes with operator<<
384  return PeekResolution ()->unit;
385 }
386 
387 
389 Time::As (const enum Unit unit) const
390 {
391  return TimeWithUnit (*this, unit);
392 }
393 
394 
395 std::ostream &
396 operator << (std::ostream & os, const Time & time)
397 {
398  os << time.As (Time::GetResolution ());
399  return os;
400 }
401 
402 
403 std::ostream &
404 operator << (std::ostream & os, const TimeWithUnit & timeU)
405 {
406  std::string unit;
407 
408  switch (timeU.m_unit)
409  {
410  // *NS_CHECK_STYLE_OFF*
411  case Time::Y: unit = "y"; break;
412  case Time::D: unit = "d"; break;
413  case Time::H: unit = "h"; break;
414  case Time::MIN: unit = "min"; break;
415  case Time::S: unit = "s"; break;
416  case Time::MS: unit = "ms"; break;
417  case Time::US: unit = "us"; break;
418  case Time::NS: unit = "ns"; break;
419  case Time::PS: unit = "ps"; break;
420  case Time::FS: unit = "fs"; break;
421  // *NS_CHECK_STYLE_ON*
422 
423  case Time::LAST:
424  default:
425  NS_ABORT_MSG ("can't be reached");
426  unit = "unreachable";
427  break;
428  }
429 
430  double v = timeU.m_time.ToDouble (timeU.m_unit);
431 
432  // Note: we must copy the "original" format flags because we have to modify them.
433  // std::ios_base::showpos is to print the "+" in front of the number for positive,
434  // std::ios_base::right is to add (eventual) extra space in front of the number.
435  // the eventual extra space might be due to a std::setw (_number_), and
436  // normally it would be printed after the number and before the time unit.
437 
438  std::ios_base::fmtflags ff = os.flags ();
439 
440  os << std::showpos << std::right << v << unit;
441 
442  // And here we have to restore what we changed.
443  if (!(ff & std::ios_base::showpos))
444  {
445  os << std::noshowpos;
446  }
447  if (ff & std::ios_base::left)
448  {
449  os << std::left;
450  }
451  else if (ff & std::ios_base::internal)
452  {
453  os << std::internal;
454  }
455 
456  return os;
457 }
458 
459 
460 std::istream &
461 operator >> (std::istream & is, Time & time)
462 {
463  std::string value;
464  is >> value;
465  time = Time (value);
466  return is;
467 }
468 
470 
473 {
474  NS_LOG_FUNCTION (min << max);
475 
476  struct Checker : public AttributeChecker
477  {
478  Checker (const Time minValue, const Time maxValue)
479  : m_minValue (minValue),
480  m_maxValue (maxValue)
481  {}
482  virtual bool Check (const AttributeValue &value) const
483  {
484  NS_LOG_FUNCTION (&value);
485  const TimeValue *v = dynamic_cast<const TimeValue *> (&value);
486  if (v == 0)
487  {
488  return false;
489  }
490  return v->Get () >= m_minValue && v->Get () <= m_maxValue;
491  }
492  virtual std::string GetValueTypeName (void) const
493  {
495  return "ns3::TimeValue";
496  }
497  virtual bool HasUnderlyingTypeInformation (void) const
498  {
500  return true;
501  }
502  virtual std::string GetUnderlyingTypeInformation (void) const
503  {
505  std::ostringstream oss;
506  oss << "Time" << " " << m_minValue << ":" << m_maxValue;
507  return oss.str ();
508  }
509  virtual Ptr<AttributeValue> Create (void) const
510  {
512  return ns3::Create<TimeValue> ();
513  }
514  virtual bool Copy (const AttributeValue &source, AttributeValue &destination) const
515  {
516  NS_LOG_FUNCTION (&source << &destination);
517  const TimeValue *src = dynamic_cast<const TimeValue *> (&source);
518  TimeValue *dst = dynamic_cast<TimeValue *> (&destination);
519  if (src == 0 || dst == 0)
520  {
521  return false;
522  }
523  *dst = *src;
524  return true;
525  }
526  Time m_minValue;
527  Time m_maxValue;
528  } *checker = new Checker (min, max);
529  return Ptr<const AttributeChecker> (checker, false);
530 }
531 
532 
533 } // namespace ns3
534 
static struct Resolution * PeekResolution(void)
Get the current Resolution.
Definition: nstime.h:593
std::istream & operator>>(std::istream &is, Angles &a)
initialize a struct Angles from input
Definition: angles.cc:48
nanosecond
Definition: nstime.h:118
Represent the type of an attribute.
Definition: attribute.h:166
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
microsecond
Definition: nstime.h:117
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
int64x64_t timeFrom
Multiplier to convert from this unit.
Definition: nstime.h:579
A Time with attached unit, to facilitate output in that unit.
Definition: nstime.h:1385
#define min(a, b)
Definition: 80211b.c:42
int64_t ToInteger(enum Unit unit) const
Get the Time value expressed in a particular unit.
Definition: nstime.h:515
Hold a value for an Attribute.
Definition: attribute.h:68
day, 24 hours
Definition: nstime.h:112
High precision numerical type, implementing Q64.64 fixed precision.
Definition: int64x64-128.h:45
minute, 60 seconds
Definition: nstime.h:114
static int64x64_t Invert(const uint64_t v)
Compute the inverse of an integer value.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
double ToDouble(enum Unit unit) const
Get the Time value expressed in a particular unit.
Definition: nstime.h:529
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:802
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
hour, 60 minutes
Definition: nstime.h:113
TimeWithUnit As(const enum Unit unit) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:389
struct Information info[LAST]
Conversion info from current unit.
Definition: nstime.h:584
#define ATTRIBUTE_VALUE_IMPLEMENT(type)
Define the class methods belonging to attribute value class typeValue for class type.
System-independent mutex primitive, ns3::SystemMutex, and ns3::CriticalSection.
picosecond
Definition: nstime.h:119
year, 365 days
Definition: nstime.h:111
#define max(a, b)
Definition: 80211b.c:43
static enum Unit GetResolution(void)
Definition: time.cc:381
AttributeValue implementation for Time.
Definition: nstime.h:1342
Current time unit, and conversion info.
Definition: nstime.h:582
static bool StaticInit()
Function to force static initialization of Time.
Definition: time.cc:63
A class which provides a simple way to implement a Critical Section.
Definition: system-mutex.h:118
bool fromMul
Multiple when converting From, otherwise divide.
Definition: nstime.h:576
Unit
The unit to use to interpret a number representing time.
Definition: nstime.h:109
static void ConvertTimes(const enum Unit unit)
Convert existing Times to the new unit.
Definition: time.cc:344
#define NS_LOG_COMPONENT_DEFINE_MASK(name, mask)
Define a logging component with a mask.
Definition: log.h:216
Declaration of classes ns3::Time and ns3::TimeWithUnit, and the TimeValue implementation classes...
int64_t factor
Ratio of this unit / current unit.
Definition: nstime.h:577
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
std::ostream & operator<<(std::ostream &os, const Angles &a)
print a struct Angles to output
Definition: angles.cc:42
Ptr< T > Create(Ts... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr...
Definition: ptr.h:405
SystemMutex & GetMarkingMutex()
Definition: time.cc:54
Prefix all trace prints with simulation time.
Definition: log.h:119
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Time()
Default constructor, with value 0.
Definition: nstime.h:135
A class which provides a relatively platform-independent Mutual Exclusion thread synchronization prim...
Definition: system-mutex.h:58
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:88
double max(double x, double y)
static Time FromDouble(double value, enum Unit unit)
Create a Time equal to value in unit unit.
Definition: nstime.h:480
static void Mark(Time *const time)
Record a Time instance with the MarkedTimes.
Definition: time.cc:288
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:265
Time Get(void) const
Definition: time.cc:469
How to convert between other units and the current unit.
Definition: nstime.h:573
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
enum Time::Unit unit
Current time unit.
Definition: nstime.h:585
Time::Unit m_unit
The unit to use in output.
Definition: nstime.h:1401
static void SetResolution(enum Unit resolution)
Definition: time.cc:180
double min(double x, double y)
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:472
static void Clear(Time *const time)
Remove a Time instance from the MarkedTimes, called by ~Time().
Definition: time.cc:314
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:257
second
Definition: nstime.h:115
std::set< Time *> MarkedTimes
Record all instances of Time, so we can rescale them when the resolution changes. ...
Definition: nstime.h:644
static MarkedTimes * g_markingTimes
Record of outstanding Time objects which will need conversion when the resolution is set...
Definition: nstime.h:659
static void ClearMarkedTimes()
Remove all MarkedTimes.
Definition: time.cc:257
Debug message logging.
femtosecond
Definition: nstime.h:120
millisecond
Definition: nstime.h:116
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition: ptr.h:536
Time m_time
The time.
Definition: nstime.h:1400
int64x64_t timeTo
Multiplier to convert to this unit.
Definition: nstime.h:578
int64_t m_data
Virtual time value, in the current unit.
Definition: nstime.h:790
bool toMul
Multiply when converting To, otherwise divide.
Definition: nstime.h:575
NS_ABORT_x macro definitions.