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