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> // pow
27 #include <iomanip> // showpos
28 #include <sstream>
29 
37 namespace ns3 {
38 
40 
42 namespace {
43 
47  // Y, D, H, MIN, S, MS, US, NS, PS, FS
48  const int8_t UNIT_POWER[Time::LAST] = { 17, 17, 17, 16, 15, 12, 9, 6, 3, 0 };
50  const int32_t UNIT_COEFF[Time::LAST] = { 315360, 864, 36, 6, 1, 1, 1, 1, 1, 1 };
51 
52 
58  long double
60  {
61  return UNIT_COEFF[u] * std::pow (10L, UNIT_POWER[u]);
62  }
63 
65  long double *
67  {
68  static long double values[Time::LAST];
69  for (auto u = static_cast<int> (Time::Y); u != static_cast<int> (Time::LAST); ++u)
70  {
71  values [u] = Scale (static_cast<Time::Unit> (u));
72  }
73  return values;
74  }
75 
77  const long double * UNIT_VALUE = InitUnitValue ();
78 
81 } // unnamed namespace
82 
83 
84 // The set of marked times
85 // static
87 
98 {
99  static SystemMutex g_markingMutex;
100  return g_markingMutex;
101 }
102 
103 
104 // Function called to force static initialization
105 // static
107 {
108  static bool firstTime = true;
109 
110  CriticalSection critical (GetMarkingMutex ());
111 
112  if (firstTime)
113  {
114  if (!g_markingTimes)
115  {
116  static MarkedTimes markingTimes;
117  g_markingTimes = &markingTimes;
118  }
119  else
120  {
121  NS_LOG_ERROR ("firstTime but g_markingTimes != 0");
122  }
123 
124  // Schedule the cleanup.
125  // We'd really like:
126  // NS_LOG_LOGIC ("scheduling ClearMarkedTimes()");
127  // Simulator::Schedule ( Seconds (0), & ClearMarkedTimes);
128  // [or even better: Simulator::AtStart ( & ClearMarkedTimes ); ]
129  // But this triggers a static initialization order error,
130  // since the Simulator static initialization may not have occurred.
131  // Instead, we call ClearMarkedTimes directly from Simulator::Run ()
132  firstTime = false;
133  }
134 
135  return firstTime;
136 }
137 
138 
139 Time::Time (const std::string& s)
140 {
141  NS_LOG_FUNCTION (this << &s);
142  std::string::size_type n = s.find_first_not_of ("+-0123456789.eE");
143  if (n != std::string::npos)
144  { // Found non-numeric
145  std::istringstream iss;
146  iss.str (s.substr (0, n));
147  double r;
148  iss >> r;
149  std::string trailer = s.substr (n, std::string::npos);
150  if (trailer == std::string ("s"))
151  {
152  *this = Time::FromDouble (r, Time::S);
153  }
154  else if (trailer == std::string ("ms"))
155  {
156  *this = Time::FromDouble (r, Time::MS);
157  }
158  else if (trailer == std::string ("us"))
159  {
160  *this = Time::FromDouble (r, Time::US);
161  }
162  else if (trailer == std::string ("ns"))
163  {
164  *this = Time::FromDouble (r, Time::NS);
165  }
166  else if (trailer == std::string ("ps"))
167  {
168  *this = Time::FromDouble (r, Time::PS);
169  }
170  else if (trailer == std::string ("fs"))
171  {
172  *this = Time::FromDouble (r, Time::FS);
173  }
174  else if (trailer == std::string ("min"))
175  {
176  *this = Time::FromDouble (r, Time::MIN);
177  }
178  else if (trailer == std::string ("h"))
179  {
180  *this = Time::FromDouble (r, Time::H);
181  }
182  else if (trailer == std::string ("d"))
183  {
184  *this = Time::FromDouble (r, Time::D);
185  }
186  else if (trailer == std::string ("y"))
187  {
188  *this = Time::FromDouble (r, Time::Y);
189  }
190  else
191  {
192  NS_ABORT_MSG ("Can't Parse Time " << s);
193  }
194  }
195  else
196  {
197  // they didn't provide units, assume seconds
198  std::istringstream iss;
199  iss.str (s);
200  double v;
201  iss >> v;
202  *this = Time::FromDouble (v, Time::S);
203  }
204 
205  if (g_markingTimes)
206  {
207  Mark (this);
208  }
209 }
210 
211 // static
212 struct Time::Resolution
213 Time::SetDefaultNsResolution (void)
214 {
216  struct Resolution resolution;
217  SetResolution (Time::NS, &resolution, false);
218  return resolution;
219 }
220 
221 // static
222 void
223 Time::SetResolution (enum Unit resolution)
224 {
225  NS_LOG_FUNCTION (resolution);
226  SetResolution (resolution, PeekResolution ());
227 }
228 
229 
230 // static
231 void
232 Time::SetResolution (enum Unit unit, struct Resolution *resolution,
233  const bool convert /* = true */)
234 {
235  NS_LOG_FUNCTION (resolution);
236  if (convert)
237  {
238  // We have to convert existing Times with the old
239  // conversion values, so do it first
240  ConvertTimes (unit);
241  }
242 
243  for (int i = 0; i < Time::LAST; i++)
244  {
245  int shift = UNIT_POWER[i] - UNIT_POWER[(int)unit];
246  int quotient = 1;
247  if (UNIT_COEFF[i] > UNIT_COEFF[(int) unit])
248  {
249  quotient = UNIT_COEFF[i] / UNIT_COEFF[(int) unit];
250  NS_ASSERT (quotient * UNIT_COEFF[(int) unit] == UNIT_COEFF[i]);
251  }
252  else if (UNIT_COEFF[i] < UNIT_COEFF[(int) unit])
253  {
254  quotient = UNIT_COEFF[(int) unit] / UNIT_COEFF[i];
255  NS_ASSERT (quotient * UNIT_COEFF[i] == UNIT_COEFF[(int) unit]);
256  }
257  NS_LOG_DEBUG ("SetResolution for unit " << (int) unit <<
258  " loop iteration " << i <<
259  " has shift " << shift << " has quotient " << quotient);
260  int64_t factor = static_cast<int64_t> (std::pow (10, std::fabs (shift)) * quotient);
261  double realFactor = std::pow (10, (double) shift)
262  * static_cast<double> (UNIT_COEFF[i]) / UNIT_COEFF[(int) unit];
263  NS_LOG_DEBUG ("SetResolution factor " << factor << " real factor " << realFactor);
264  struct Information *info = &resolution->info[i];
265  info->factor = factor;
266  // here we could equivalently check for realFactor == 1.0 but it's better
267  // to avoid checking equality of doubles
268  if (shift == 0 && quotient == 1)
269  {
270  info->timeFrom = int64x64_t (1);
271  info->timeTo = int64x64_t (1);
272  info->toMul = true;
273  info->fromMul = true;
274  }
275  else if (realFactor > 1)
276  {
277  info->timeFrom = int64x64_t (factor);
278  info->timeTo = int64x64_t::Invert (factor);
279  info->toMul = false;
280  info->fromMul = true;
281  }
282  else
283  {
284  NS_ASSERT (realFactor < 1);
285  info->timeFrom = int64x64_t::Invert (factor);
286  info->timeTo = int64x64_t (factor);
287  info->toMul = true;
288  info->fromMul = false;
289  }
290  }
291  resolution->unit = unit;
292 }
293 
294 
295 // static
296 void
298 {
314  CriticalSection critical (GetMarkingMutex ());
315 
317  if (g_markingTimes)
318  {
319  NS_LOG_LOGIC ("clearing MarkedTimes");
320  g_markingTimes->erase (g_markingTimes->begin (), g_markingTimes->end ());
321  g_markingTimes = 0;
322  }
323 } // Time::ClearMarkedTimes
324 
325 
326 // static
327 void
328 Time::Mark (Time * const time)
329 {
330  CriticalSection critical (GetMarkingMutex ());
331 
332  NS_LOG_FUNCTION (time);
333  NS_ASSERT (time != 0);
334 
335  // Repeat the g_markingTimes test here inside the CriticalSection,
336  // since earlier test was outside and might be stale.
337  if (g_markingTimes)
338  {
339  std::pair< MarkedTimes::iterator, bool> ret;
340 
341  ret = g_markingTimes->insert ( time);
342  NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] recording " << time);
343 
344  if (ret.second == false)
345  {
346  NS_LOG_WARN ("already recorded " << time << "!");
347  }
348  }
349 } // Time::Mark ()
350 
351 
352 // static
353 void
354 Time::Clear (Time * const time)
355 {
356  CriticalSection critical (GetMarkingMutex ());
357 
358  NS_LOG_FUNCTION (time);
359  NS_ASSERT (time != 0);
360 
361  if (g_markingTimes)
362  {
363  NS_ASSERT_MSG (g_markingTimes->count (time) == 1,
364  "Time object " << time <<
365  " registered " << g_markingTimes->count (time) <<
366  " times (should be 1)." );
367 
368  MarkedTimes::size_type num = g_markingTimes->erase (time);
369  if (num != 1)
370  {
371  NS_LOG_WARN ("unexpected result erasing " << time << "!");
372  NS_LOG_WARN ("got " << num << ", expected 1");
373  }
374  else
375  {
376  NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] removing " << time);
377  }
378  }
379 } // Time::Clear ()
380 
381 
382 // static
383 void
384 Time::ConvertTimes (const enum Unit unit)
385 {
386  CriticalSection critical (GetMarkingMutex ());
387 
389 
391  "No MarkedTimes registry. "
392  "Time::SetResolution () called more than once?");
393 
394  for ( MarkedTimes::iterator it = g_markingTimes->begin ();
395  it != g_markingTimes->end ();
396  it++ )
397  {
398  Time * const tp = *it;
399  if ( !((tp->m_data == std::numeric_limits<int64_t>::min ())
401  )
402  )
403  {
404  tp->m_data = tp->ToInteger (unit);
405  }
406  }
407 
408  NS_LOG_LOGIC ("logged " << g_markingTimes->size () << " Time objects.");
409 
410  // Body of ClearMarkedTimes
411  // Assert above already guarantees g_markingTimes != 0
412  NS_LOG_LOGIC ("clearing MarkedTimes");
413  g_markingTimes->erase (g_markingTimes->begin (), g_markingTimes->end ());
414  g_markingTimes = 0;
415 
416 } // Time::ConvertTimes ()
417 
418 
419 // static
420 enum Time::Unit
422 {
423  // No function log b/c it interferes with operator<<
424  return PeekResolution ()->unit;
425 }
426 
427 
429 Time::As (const enum Unit unit /* = Time::AUTO */) const
430 {
431  return TimeWithUnit (*this, unit);
432 }
433 
434 
435 std::ostream &
436 operator << (std::ostream & os, const Time & time)
437 {
438  os << time.As (Time::GetResolution ());
439  return os;
440 }
441 
442 
443 std::ostream &
444 operator << (std::ostream & os, const TimeWithUnit & timeU)
445 {
446 
447  std::string label;
448  Time::Unit unit = timeU.m_unit;
449 
450  if (unit == Time::AUTO)
451  {
452  long double value = static_cast<long double> (timeU.m_time.GetTimeStep ());
453  // convert to finest scale (fs)
454  value *= Scale (Time::GetResolution ());
455  // find the best unit
456  int u = Time::Y;
457  while (u != Time::LAST && UNIT_VALUE[u] > value)
458  {
459  ++u;
460  }
461  if (u == Time::LAST)
462  {
463  --u;
464  }
465  unit = static_cast<Time::Unit> (u);
466  }
467 
468  switch (unit)
469  {
470  // *NS_CHECK_STYLE_OFF*
471  case Time::Y: label = "y"; break;
472  case Time::D: label = "d"; break;
473  case Time::H: label = "h"; break;
474  case Time::MIN: label = "min"; break;
475  case Time::S: label = "s"; break;
476  case Time::MS: label = "ms"; break;
477  case Time::US: label = "us"; break;
478  case Time::NS: label = "ns"; break;
479  case Time::PS: label = "ps"; break;
480  case Time::FS: label = "fs"; break;
481  // *NS_CHECK_STYLE_ON*
482 
483  case Time::LAST:
484  case Time::AUTO:
485  default:
486  NS_ABORT_MSG ("can't be reached");
487  label = "unreachable";
488  break;
489  }
490 
491  double v = timeU.m_time.ToDouble (unit);
492 
493  // Note: we must copy the "original" format flags because we have to modify them.
494  // std::ios_base::showpos is to print the "+" in front of the number for positive,
495  // std::ios_base::right is to add (eventual) extra space in front of the number.
496  // the eventual extra space might be due to a std::setw (_number_), and
497  // normally it would be printed after the number and before the time unit label.
498 
499  std::ios_base::fmtflags ff = os.flags ();
500 
501  os << std::showpos << std::right << v << label;
502 
503  // And here we have to restore what we changed.
504  if (!(ff & std::ios_base::showpos))
505  {
506  os << std::noshowpos;
507  }
508  if (ff & std::ios_base::left)
509  {
510  os << std::left;
511  }
512  else if (ff & std::ios_base::internal)
513  {
514  os << std::internal;
515  }
516 
517  return os;
518 }
519 
520 
521 std::istream &
522 operator >> (std::istream & is, Time & time)
523 {
524  std::string value;
525  is >> value;
526  time = Time (value);
527  return is;
528 }
529 
531 
534 {
535  NS_LOG_FUNCTION (min << max);
536 
537  struct Checker : public AttributeChecker
538  {
539  Checker (const Time minValue, const Time maxValue)
540  : m_minValue (minValue),
541  m_maxValue (maxValue)
542  {}
543  virtual bool Check (const AttributeValue &value) const
544  {
545  NS_LOG_FUNCTION (&value);
546  const TimeValue *v = dynamic_cast<const TimeValue *> (&value);
547  if (v == 0)
548  {
549  return false;
550  }
551  return v->Get () >= m_minValue && v->Get () <= m_maxValue;
552  }
553  virtual std::string GetValueTypeName (void) const
554  {
556  return "ns3::TimeValue";
557  }
558  virtual bool HasUnderlyingTypeInformation (void) const
559  {
561  return true;
562  }
563  virtual std::string GetUnderlyingTypeInformation (void) const
564  {
566  std::ostringstream oss;
567  oss << "Time" << " " << m_minValue << ":" << m_maxValue;
568  return oss.str ();
569  }
570  virtual Ptr<AttributeValue> Create (void) const
571  {
573  return ns3::Create<TimeValue> ();
574  }
575  virtual bool Copy (const AttributeValue &source, AttributeValue &destination) const
576  {
577  NS_LOG_FUNCTION (&source << &destination);
578  const TimeValue *src = dynamic_cast<const TimeValue *> (&source);
579  TimeValue *dst = dynamic_cast<TimeValue *> (&destination);
580  if (src == 0 || dst == 0)
581  {
582  return false;
583  }
584  *dst = *src;
585  return true;
586  }
587  Time m_minValue;
588  Time m_maxValue;
589  } *checker = new Checker (min, max);
590  return Ptr<const AttributeChecker> (checker, false);
591 }
592 
593 
594 } // namespace ns3
595 
static struct Resolution * PeekResolution(void)
Get the current Resolution.
Definition: nstime.h:604
TimeWithUnit As(const enum Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:429
nanosecond
Definition: nstime.h:118
Represent the type of an attribute.
Definition: attribute.h:166
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr...
Definition: ptr.h:405
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:590
A Time with attached unit, to facilitate output in that unit.
Definition: nstime.h:1396
#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:516
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:530
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:813
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
hour, 60 minutes
Definition: nstime.h:113
std::istream & operator>>(std::istream &is, Angles &a)
Definition: angles.cc:160
const int8_t UNIT_POWER[Time::LAST]
Scaling coefficients, exponents, and look up table for unit.
Definition: time.cc:48
auto-scale output when using Time::As()
Definition: nstime.h:122
struct Information info[LAST]
Conversion info from current unit.
Definition: nstime.h:595
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:137
#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:421
AttributeValue implementation for Time.
Definition: nstime.h:1353
const long double * UNIT_VALUE
Value of each unit, in terms of the smallest defined unit.
Definition: time.cc:77
Current time unit, and conversion info.
Definition: nstime.h:593
static bool StaticInit()
Function to force static initialization of Time.
Definition: time.cc:106
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:587
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:384
#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:588
const int32_t UNIT_COEFF[Time::LAST]
Scaling coefficient, relative to smallest unit.
Definition: time.cc:50
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
SystemMutex & GetMarkingMutex()
Definition: time.cc:97
Prefix all trace prints with simulation time.
Definition: log.h:119
long double Scale(Time::Unit u)
Scale a unit to the smallest unit.
Definition: time.cc:59
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Time()
Default constructor, with value 0.
Definition: nstime.h:136
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:481
static void Mark(Time *const time)
Record a Time instance with the MarkedTimes.
Definition: time.cc:328
#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:530
How to convert between other units and the current unit.
Definition: nstime.h:584
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
long double * InitUnitValue(void)
Initializer for UNIT_VALUE.
Definition: time.cc:66
enum Time::Unit unit
Current time unit.
Definition: nstime.h:596
Time::Unit m_unit
The unit to use in output.
Definition: nstime.h:1412
static void SetResolution(enum Unit resolution)
Definition: time.cc:223
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:533
static void Clear(Time *const time)
Remove a Time instance from the MarkedTimes, called by ~Time().
Definition: time.cc:354
#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:655
marker for last normal value
Definition: nstime.h:121
static MarkedTimes * g_markingTimes
Record of outstanding Time objects which will need conversion when the resolution is set...
Definition: nstime.h:670
static void ClearMarkedTimes()
Remove all MarkedTimes.
Definition: time.cc:297
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:1411
int64x64_t timeTo
Multiplier to convert to this unit.
Definition: nstime.h:589
int64_t m_data
Virtual time value, in the current unit.
Definition: nstime.h:801
bool toMul
Multiply when converting To, otherwise divide.
Definition: nstime.h:586
NS_ABORT_x macro definitions.
int64_t GetTimeStep(void) const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:416