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