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