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 
30 namespace ns3 {
31 
33 
34 // The set of marked times
35 // static
37 
46 SystemMutex &
48 {
49  static SystemMutex g_markingMutex;
50  return g_markingMutex;
51 }
52 
53 
54 // Function called to force static initialization
55 // static
57 {
58  static bool firstTime = true;
59 
60  CriticalSection critical (GetMarkingMutex ());
61 
62  if (firstTime)
63  {
64  if (! g_markingTimes)
65  {
66  static MarkedTimes markingTimes;
67  g_markingTimes = & markingTimes;
68  }
69  else
70  {
71  NS_LOG_ERROR ("firstTime but g_markingTimes != 0");
72  }
73 
74  // Schedule the cleanup.
75  // We'd really like:
76  // NS_LOG_LOGIC ("scheduling ClearMarkedTimes()");
77  // Simulator::Schedule ( Seconds (0), & ClearMarkedTimes);
78  // [or even better: Simulator::AtStart ( & ClearMarkedTimes ); ]
79  // But this triggers a static initialization order error,
80  // since the Simulator static initialization may not have occurred.
81  // Instead, we call ClearMarkedTimes directly from Simulator::Run ()
82  firstTime = false;
83  }
84 
85  return firstTime;
86 }
87 
88 
89 Time::Time (const std::string& s)
90 {
91  NS_LOG_FUNCTION (this << &s);
92  std::string::size_type n = s.find_first_not_of ("+-0123456789.");
93  if (n != std::string::npos)
94  { // Found non-numeric
95  std::istringstream iss;
96  iss.str (s.substr (0, n));
97  double r;
98  iss >> r;
99  std::string trailer = s.substr (n, std::string::npos);
100  if (trailer == std::string ("s"))
101  {
102  *this = Time::FromDouble (r, Time::S);
103  }
104  else if (trailer == std::string ("ms"))
105  {
106  *this = Time::FromDouble (r, Time::MS);
107  }
108  else if (trailer == std::string ("us"))
109  {
110  *this = Time::FromDouble (r, Time::US);
111  }
112  else if (trailer == std::string ("ns"))
113  {
114  *this = Time::FromDouble (r, Time::NS);
115  }
116  else if (trailer == std::string ("ps"))
117  {
118  *this = Time::FromDouble (r, Time::PS);
119  }
120  else if (trailer == std::string ("fs"))
121  {
122  *this = Time::FromDouble (r, Time::FS);
123  }
124  else if (trailer == std::string ("min"))
125  {
126  *this = Time::FromDouble (r, Time::MIN);
127  }
128  else if (trailer == std::string ("h"))
129  {
130  *this = Time::FromDouble (r, Time::H);
131  }
132  else if (trailer == std::string ("d"))
133  {
134  *this = Time::FromDouble (r, Time::D);
135  }
136  else if (trailer == std::string ("y"))
137  {
138  *this = Time::FromDouble (r, Time::Y);
139  }
140  else
141  {
142  NS_ABORT_MSG ("Can't Parse Time " << s);
143  }
144  }
145  else
146  {
147  // they didn't provide units, assume seconds
148  std::istringstream iss;
149  iss.str (s);
150  double v;
151  iss >> v;
152  *this = Time::FromDouble (v, Time::S);
153  }
154 
155  if (g_markingTimes)
156  {
157  Mark (this);
158  }
159 }
160 
161 // static
162 struct Time::Resolution
163 Time::SetDefaultNsResolution (void)
164 {
166  struct Resolution resolution;
167  SetResolution (Time::NS, &resolution, false);
168  return resolution;
169 }
170 
171 // static
172 void
173 Time::SetResolution (enum Unit resolution)
174 {
175  NS_LOG_FUNCTION (resolution);
176  SetResolution (resolution, PeekResolution ());
177 }
178 
179 
180 // static
181 void
182 Time::SetResolution (enum Unit unit, struct Resolution *resolution,
183  const bool convert /* = true */)
184 {
185  NS_LOG_FUNCTION (resolution);
186  if (convert)
187  {
188  // We have to convert existing Times with the old
189  // conversion values, so do it first
190  ConvertTimes (unit);
191  }
192 
193  // Y, D, H, MIN, S, MS, US, NS, PS, FS
194  const int8_t power [LAST] = { 17, 17, 17, 16, 15, 12, 9, 6, 3, 0 };
195  const int32_t coefficient [LAST] = { 315360, 864, 36, 6, 1, 1, 1, 1, 1, 1 };
196  for (int i = 0; i < Time::LAST; i++)
197  {
198  int shift = power[i] - power[(int)unit];
199  int quotient = 1;
200  if (coefficient[i] > coefficient[(int) unit])
201  {
202  quotient = coefficient[i] / coefficient[(int) unit];
203  NS_ASSERT (quotient * coefficient[(int) unit] == coefficient[i]);
204  }
205  else if (coefficient[i] < coefficient[(int) unit])
206  {
207  quotient = coefficient[(int) unit] / coefficient[i];
208  NS_ASSERT (quotient * coefficient[i] == coefficient[(int) unit]);
209  }
210  NS_LOG_DEBUG ("SetResolution for unit " << (int) unit << " loop iteration " << i
211  << " has shift " << shift << " has quotient " << quotient);
212  int64_t factor = static_cast<int64_t> (std::pow (10, std::fabs (shift)) * quotient);
213  double realFactor = std::pow (10, (double) shift)
214  * static_cast<double> (coefficient[i]) / coefficient[(int) unit];
215  NS_LOG_DEBUG ("SetResolution factor " << factor << " real factor " << realFactor);
216  struct Information *info = &resolution->info[i];
217  info->factor = factor;
218  // here we could equivalently check for realFactor == 1.0 but it's better
219  // to avoid checking equality of doubles
220  if (shift == 0 && quotient == 1)
221  {
222  info->timeFrom = int64x64_t (1);
223  info->timeTo = int64x64_t (1);
224  info->toMul = true;
225  info->fromMul = true;
226  }
227  else if (realFactor > 1)
228  {
229  info->timeFrom = int64x64_t (factor);
230  info->timeTo = int64x64_t::Invert (factor);
231  info->toMul = false;
232  info->fromMul = true;
233  }
234  else
235  {
236  NS_ASSERT (realFactor < 1);
237  info->timeFrom = int64x64_t::Invert (factor);
238  info->timeTo = int64x64_t (factor);
239  info->toMul = true;
240  info->fromMul = false;
241  }
242  }
243  resolution->unit = unit;
244 }
245 
246 
247 // static
248 void
250 {
266  CriticalSection critical (GetMarkingMutex ());
267 
269  if (g_markingTimes)
270  {
271  NS_LOG_LOGIC ("clearing MarkedTimes");
272  g_markingTimes->erase (g_markingTimes->begin(), g_markingTimes->end ());
273  g_markingTimes = 0;
274  }
275 } // Time::ClearMarkedTimes
276 
277 
278 // static
279 void
280 Time::Mark (Time * const time)
281 {
282  CriticalSection critical (GetMarkingMutex ());
283 
284  NS_LOG_FUNCTION (time);
285  NS_ASSERT (time != 0);
286 
287  // Repeat the g_markingTimes test here inside the CriticalSection,
288  // since earlier test was outside and might be stale.
289  if (g_markingTimes)
290  {
291  std::pair< MarkedTimes::iterator, bool> ret;
292 
293  ret = g_markingTimes->insert ( time);
294  NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] recording " << time);
295 
296  if (ret.second == false)
297  {
298  NS_LOG_WARN ("already recorded " << time << "!");
299  }
300  }
301 } // Time::Mark ()
302 
303 
304 // static
305 void
306 Time::Clear (Time * const time)
307 {
308  CriticalSection critical (GetMarkingMutex ());
309 
310  NS_LOG_FUNCTION (time);
311  NS_ASSERT (time != 0);
312 
313  if (g_markingTimes)
314  {
315  NS_ASSERT_MSG (g_markingTimes->count (time) == 1,
316  "Time object " << time <<
317  " registered " << g_markingTimes->count (time) <<
318  " times (should be 1)." );
319 
320  MarkedTimes::size_type num = g_markingTimes->erase (time);
321  if (num != 1)
322  {
323  NS_LOG_WARN ("unexpected result erasing " << time << "!");
324  NS_LOG_WARN ("got " << num << ", expected 1");
325  }
326  else
327  {
328  NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] removing " << time);
329  }
330  }
331 } // Time::Clear ()
332 
333 
334 // static
335 void
336 Time::ConvertTimes (const enum Unit unit)
337 {
338  CriticalSection critical (GetMarkingMutex ());
339 
341 
343  "No MarkedTimes registry. "
344  "Time::SetResolution () called more than once?");
345 
346  for ( MarkedTimes::iterator it = g_markingTimes->begin();
347  it != g_markingTimes->end();
348  it++ )
349  {
350  Time * const tp = *it;
351  if ( ! ( (tp->m_data == std::numeric_limits<int64_t>::min ())
352  || (tp->m_data == std::numeric_limits<int64_t>::max ())
353  )
354  )
355  {
356  tp->m_data = tp->ToInteger (unit);
357  }
358  }
359 
360  NS_LOG_LOGIC ("logged " << g_markingTimes->size () << " Time objects.");
361 
362  // Body of ClearMarkedTimes
363  // Assert above already guarantees g_markingTimes != 0
364  NS_LOG_LOGIC ("clearing MarkedTimes");
365  g_markingTimes->erase (g_markingTimes->begin(), g_markingTimes->end ());
366  g_markingTimes = 0;
367 
368 } // Time::ConvertTimes ()
369 
370 
371 // static
372 enum Time::Unit
374 {
375  // No function log b/c it interferes with operator<<
376  return PeekResolution ()->unit;
377 }
378 
379 
381 Time::As (const enum Unit unit) const
382 {
383  return TimeWithUnit (*this, unit);
384 }
385 
386 
387 std::ostream &
388 operator << (std::ostream & os, const Time & time)
389 {
390  os << time.As (Time::GetResolution ());
391  return os;
392 }
393 
394 
395 std::ostream &
396 operator << (std::ostream & os, const TimeWithUnit & timeU)
397 {
398  std::string unit;
399 
400  switch (timeU.m_unit)
401  {
402  case Time::Y: unit = "y"; break;
403  case Time::D: unit = "d"; break;
404  case Time::H: unit = "h"; break;
405  case Time::MIN: unit = "min"; break;
406  case Time::S: unit = "s"; break;
407  case Time::MS: unit = "ms"; break;
408  case Time::US: unit = "us"; break;
409  case Time::NS: unit = "ns"; break;
410  case Time::PS: unit = "ps"; break;
411  case Time::FS: unit = "fs"; break;
412 
413  case Time::LAST:
414  default:
415  NS_ABORT_MSG ("can't be reached");
416  unit = "unreachable";
417  break;
418  }
419 
420  int64x64_t v = timeU.m_time.To (timeU.m_unit);
421  os << v << unit;
422 
423  return os;
424 }
425 
426 
427 std::istream &
428 operator >> (std::istream & is, Time & time)
429 {
430  std::string value;
431  is >> value;
432  time = Time (value);
433  return is;
434 }
435 
437 
439 MakeTimeChecker (const Time min, const Time max)
440 {
441  NS_LOG_FUNCTION (min << max);
442 
443  struct Checker : public AttributeChecker
444  {
445  Checker (const Time minValue, const Time maxValue)
446  : m_minValue (minValue),
447  m_maxValue (maxValue) {}
448  virtual bool Check (const AttributeValue &value) const {
449  NS_LOG_FUNCTION (&value);
450  const TimeValue *v = dynamic_cast<const TimeValue *> (&value);
451  if (v == 0)
452  {
453  return false;
454  }
455  return v->Get () >= m_minValue && v->Get () <= m_maxValue;
456  }
457  virtual std::string GetValueTypeName (void) const {
459  return "ns3::TimeValue";
460  }
461  virtual bool HasUnderlyingTypeInformation (void) const {
463  return true;
464  }
465  virtual std::string GetUnderlyingTypeInformation (void) const {
467  std::ostringstream oss;
468  oss << "Time" << " " << m_minValue << ":" << m_maxValue;
469  return oss.str ();
470  }
471  virtual Ptr<AttributeValue> Create (void) const {
473  return ns3::Create<TimeValue> ();
474  }
475  virtual bool Copy (const AttributeValue &source, AttributeValue &destination) const {
476  NS_LOG_FUNCTION (&source << &destination);
477  const TimeValue *src = dynamic_cast<const TimeValue *> (&source);
478  TimeValue *dst = dynamic_cast<TimeValue *> (&destination);
479  if (src == 0 || dst == 0)
480  {
481  return false;
482  }
483  *dst = *src;
484  return true;
485  }
486  Time m_minValue;
487  Time m_maxValue;
488  } *checker = new Checker (min, max);
489  return Ptr<const AttributeChecker> (checker, false);
490 }
491 
492 
493 } // namespace ns3
494 
static struct Resolution * PeekResolution(void)
Get the current Resolution.
Definition: nstime.h:535
Unit
The unit to use to interpret a number representing time.
Definition: nstime.h:101
std::istream & operator>>(std::istream &is, Angles &a)
initialize a struct Angles from input
Definition: angles.cc:48
Time Get(void) const
Definition: time.cc:436
Represent the type of an attribute.
Definition: attribute.h:166
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:95
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 "...
#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:521
A Time with attached unit, to facilitate output in that unit.
Definition: nstime.h:964
int64_t ToInteger(enum Unit unit) const
Get the Time value expressed in a particular unit.
Definition: nstime.h:447
Hold a value for an Attribute.
Definition: attribute.h:68
High precision numerical type, implementing Q64.64 fixed precision.
Definition: int64x64-128.h:39
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:61
second
Definition: nstime.h:107
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
millisecond
Definition: nstime.h:108
hour, 60 minutes
Definition: nstime.h:105
int64x64_t To(enum Unit unit) const
Get the Time value expressed in a particular unit.
Definition: nstime.h:465
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:439
struct Information info[LAST]
Conversion info from current unit.
Definition: nstime.h:526
day, 24 hours
Definition: nstime.h:104
#define ATTRIBUTE_VALUE_IMPLEMENT(type)
Define the class methods belonging to attribute value class Value for class type...
System-independent mutex primitive, ns3::SystemMutex, and ns3::CriticalSection.
static enum Unit GetResolution(void)
Definition: time.cc:373
AttributeValue implementation for Time.
Definition: nstime.h:921
Current time unit, and conversion info.
Definition: nstime.h:524
static bool StaticInit()
Function to force static initialization of Time.
Definition: time.cc:56
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:518
Ptr< SampleEmitter > s
year, 365 days
Definition: nstime.h:103
static void ConvertTimes(const enum Unit unit)
Convert existing Times to the new unit.
Definition: time.cc:336
minute, 60 seconds
Definition: nstime.h:106
#define NS_LOG_COMPONENT_DEFINE_MASK(name, mask)
Define a logging component with a mask.
Definition: log.h:212
femtosecond
Definition: nstime.h:112
int64_t factor
Ratio of this unit / current unit.
Definition: nstime.h:519
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:252
std::ostream & operator<<(std::ostream &os, const Angles &a)
print a struct Angles to output
Definition: angles.cc:42
SystemMutex & GetMarkingMutex()
Definition: time.cc:47
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Prefix all trace prints with simulation time.
Definition: log.h:115
Ptr< T > Create(void)
Create class instances by constructors with varying numbers of arguments and return them by Ptr...
Definition: ptr.h:514
Time()
Default constructor, with value 0.
Definition: nstime.h:127
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:84
static Time FromDouble(double value, enum Unit unit)
Create a Time equal to value in unit unit.
Definition: nstime.h:417
static void Mark(Time *const time)
Record a Time instance with the MarkedTimes.
Definition: time.cc:280
microsecond
Definition: nstime.h:109
TimeWithUnit As(const enum Unit unit) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:381
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:228
How to convert between other units and the current unit.
Definition: nstime.h:515
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:236
enum Time::Unit unit
Current time unit.
Definition: nstime.h:527
Time::Unit m_unit
The unit to use in output.
Definition: nstime.h:980
static void SetResolution(enum Unit resolution)
Definition: time.cc:173
static void Clear(Time *const time)
Remove a Time instance from the MarkedTimes, called by ~Time().
Definition: time.cc:306
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:220
picosecond
Definition: nstime.h:111
nanosecond
Definition: nstime.h:110
std::set< Time * > MarkedTimes
Record all instances of Time, so we can rescale them when the resolution changes. ...
Definition: nstime.h:586
static MarkedTimes * g_markingTimes
Record of outstanding Time objects which will need conversion when the resolution is set...
Definition: nstime.h:601
static void ClearMarkedTimes()
Remove all MarkedTimes.
Definition: time.cc:249
Debug message logging.
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition: ptr.h:686
Time m_time
The time.
Definition: nstime.h:976
int64x64_t timeTo
Multiplier to convert to this unit.
Definition: nstime.h:520
int64_t m_data
Virtual time value, in the current unit.
Definition: nstime.h:682
bool toMul
Multiply when converting To, otherwise divide.
Definition: nstime.h:517
NS_ABORT_x macro definitions.