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