A Discrete-Event Network Simulator
API
time.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005,2006 INRIA
3  * Copyright (c) 2007 Emmanuelle Laprise
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  * TimeStep support by Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
20  */
21 #include "abort.h"
22 #include "log.h"
23 #include "nstime.h"
24 
25 #include <cmath> // pow
26 #include <iomanip> // showpos
27 #include <mutex>
28 #include <sstream>
29 
37 namespace ns3
38 {
39 
41 
43 namespace
44 {
45 
49 // Y, D, H, MIN, S, MS, US, NS, PS, FS
50 const int8_t UNIT_POWER[Time::LAST] = {17, 17, 17, 16, 15, 12, 9, 6, 3, 0};
52 const int32_t UNIT_COEFF[Time::LAST] = {315360, 864, 36, 6, 1, 1, 1, 1, 1, 1};
53 
59 long double
61 {
62  return UNIT_COEFF[u] * std::pow(10L, UNIT_POWER[u]);
63 }
64 
69 long double*
71 {
72  static long double values[Time::LAST];
73  for (auto u = static_cast<int>(Time::Y); u != static_cast<int>(Time::LAST); ++u)
74  {
75  values[u] = Scale(static_cast<Time::Unit>(u));
76  }
77  return values;
78 }
79 
81 const long double* UNIT_VALUE = InitUnitValue();
82 
85 } // unnamed namespace
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
96 bool
98 {
99  static bool firstTime = true;
100 
101  std::unique_lock lock{g_markingMutex};
102 
103  if (firstTime)
104  {
105  if (!g_markingTimes)
106  {
107  static MarkedTimes markingTimes;
108  g_markingTimes = &markingTimes;
109  }
110  else
111  {
112  NS_LOG_ERROR("firstTime but g_markingTimes != 0");
113  }
114 
115  // Schedule the cleanup.
116  // We'd really like:
117  // NS_LOG_LOGIC ("scheduling ClearMarkedTimes()");
118  // Simulator::Schedule ( Seconds (0), & ClearMarkedTimes);
119  // [or even better: Simulator::AtStart ( & ClearMarkedTimes ); ]
120  // But this triggers a static initialization order error,
121  // since the Simulator static initialization may not have occurred.
122  // Instead, we call ClearMarkedTimes directly from Simulator::Run ()
123  firstTime = false;
124  }
125 
126  return firstTime;
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&
204 {
206  static Resolution resolution;
207  SetResolution(Time::NS, &resolution, false);
208  return resolution;
209 }
210 
211 // static
212 void
214 {
215  NS_LOG_FUNCTION(resolution);
216  SetResolution(resolution, PeekResolution());
217 }
218 
219 // static
220 void
221 Time::SetResolution(Unit unit, Resolution* resolution, const bool convert /* = true */)
222 {
223  NS_LOG_FUNCTION(resolution);
224  if (convert)
225  {
226  // We have to convert existing Times with the old
227  // conversion values, so do it first
228  ConvertTimes(unit);
229  }
230 
231  for (int i = 0; i < Time::LAST; i++)
232  {
233  int shift = UNIT_POWER[i] - UNIT_POWER[(int)unit];
234  int quotient = 1;
235  if (UNIT_COEFF[i] > UNIT_COEFF[(int)unit])
236  {
237  quotient = UNIT_COEFF[i] / UNIT_COEFF[(int)unit];
238  NS_ASSERT(quotient * UNIT_COEFF[(int)unit] == UNIT_COEFF[i]);
239  }
240  else if (UNIT_COEFF[i] < UNIT_COEFF[(int)unit])
241  {
242  quotient = UNIT_COEFF[(int)unit] / UNIT_COEFF[i];
243  NS_ASSERT(quotient * UNIT_COEFF[i] == UNIT_COEFF[(int)unit]);
244  }
245  NS_LOG_DEBUG("SetResolution for unit " << (int)unit << " loop iteration " << i
246  << " has shift " << shift << " has quotient "
247  << quotient);
248 
249  struct Information* info = &resolution->info[i];
250  if ((std::pow(10, std::fabs(shift)) * quotient) >
251  static_cast<double>(std::numeric_limits<int64_t>::max()))
252  {
253  NS_LOG_DEBUG("SetResolution for unit " << (int)unit << " loop iteration " << i
254  << " marked as INVALID");
255  info->isValid = false;
256  continue;
257  }
258  int64_t factor = static_cast<int64_t>(std::pow(10, std::fabs(shift)) * quotient);
259  double realFactor = std::pow(10, (double)shift) * static_cast<double>(UNIT_COEFF[i]) /
260  UNIT_COEFF[(int)unit];
261  NS_LOG_DEBUG("SetResolution factor " << factor << " real factor " << realFactor);
262  info->factor = factor;
263  // here we could equivalently check for realFactor == 1.0 but it's better
264  // to avoid checking equality of doubles
265  if (shift == 0 && quotient == 1)
266  {
267  info->timeFrom = int64x64_t(1);
268  info->timeTo = int64x64_t(1);
269  info->toMul = true;
270  info->fromMul = true;
271  info->isValid = true;
272  }
273  else if (realFactor > 1)
274  {
275  info->timeFrom = int64x64_t(factor);
276  info->timeTo = int64x64_t::Invert(factor);
277  info->toMul = false;
278  info->fromMul = true;
279  info->isValid = true;
280  }
281  else
282  {
283  NS_ASSERT(realFactor < 1);
284  info->timeFrom = int64x64_t::Invert(factor);
285  info->timeTo = int64x64_t(factor);
286  info->toMul = true;
287  info->fromMul = false;
288  info->isValid = true;
289  }
290  }
291  resolution->unit = unit;
292 }
293 
294 // static
295 void
297 {
312  std::unique_lock lock{g_markingMutex};
313 
315  if (g_markingTimes)
316  {
317  NS_LOG_LOGIC("clearing MarkedTimes");
318  g_markingTimes->erase(g_markingTimes->begin(), g_markingTimes->end());
319  g_markingTimes = nullptr;
320  }
321 } // Time::ClearMarkedTimes
322 
323 // static
324 void
325 Time::Mark(Time* const time)
326 {
327  std::unique_lock lock{g_markingMutex};
328 
329  NS_LOG_FUNCTION(time);
330  NS_ASSERT(time != nullptr);
331 
332  // Repeat the g_markingTimes test here inside the CriticalSection,
333  // since earlier test was outside and might be stale.
334  if (g_markingTimes)
335  {
336  std::pair<MarkedTimes::iterator, bool> ret;
337 
338  ret = g_markingTimes->insert(time);
339  NS_LOG_LOGIC("\t[" << g_markingTimes->size() << "] recording " << time);
340 
341  if (ret.second == false)
342  {
343  NS_LOG_WARN("already recorded " << time << "!");
344  }
345  }
346 } // Time::Mark ()
347 
348 // static
349 void
350 Time::Clear(Time* const time)
351 {
352  std::unique_lock lock{g_markingMutex};
353 
354  NS_LOG_FUNCTION(time);
355  NS_ASSERT(time != nullptr);
356 
357  if (g_markingTimes)
358  {
359  NS_ASSERT_MSG(g_markingTimes->count(time) == 1,
360  "Time object " << time << " registered " << g_markingTimes->count(time)
361  << " times (should be 1).");
362 
363  MarkedTimes::size_type num = g_markingTimes->erase(time);
364  if (num != 1)
365  {
366  NS_LOG_WARN("unexpected result erasing " << time << "!");
367  NS_LOG_WARN("got " << num << ", expected 1");
368  }
369  else
370  {
371  NS_LOG_LOGIC("\t[" << g_markingTimes->size() << "] removing " << time);
372  }
373  }
374 } // Time::Clear ()
375 
376 // static
377 void
379 {
380  std::unique_lock lock{g_markingMutex};
381 
383 
384  NS_ASSERT_MSG(g_markingTimes != nullptr,
385  "No MarkedTimes registry. "
386  "Time::SetResolution () called more than once?");
387 
388  for (MarkedTimes::iterator it = g_markingTimes->begin(); it != g_markingTimes->end(); it++)
389  {
390  Time* const tp = *it;
391  if (!((tp->m_data == std::numeric_limits<int64_t>::min()) ||
393  {
394  tp->m_data = tp->ToInteger(unit);
395  }
396  }
397 
398  NS_LOG_LOGIC("logged " << g_markingTimes->size() << " Time objects.");
399 
400  // Body of ClearMarkedTimes
401  // Assert above already guarantees g_markingTimes != 0
402  NS_LOG_LOGIC("clearing MarkedTimes");
403  g_markingTimes->erase(g_markingTimes->begin(), g_markingTimes->end());
404  g_markingTimes = nullptr;
405 
406 } // Time::ConvertTimes ()
407 
408 // static
409 enum Time::Unit
411 {
412  // No function log b/c it interferes with operator<<
413  return PeekResolution()->unit;
414 }
415 
416 TimeWithUnit
417 Time::As(const Unit unit /* = Time::AUTO */) const
418 {
419  return TimeWithUnit(*this, unit);
420 }
421 
422 std::ostream&
423 operator<<(std::ostream& os, const Time& time)
424 {
425  os << time.As(Time::GetResolution());
426  return os;
427 }
428 
429 std::ostream&
430 operator<<(std::ostream& os, const TimeWithUnit& timeU)
431 {
432  std::string label;
433  Time::Unit unit = timeU.m_unit;
434 
435  if (unit == Time::AUTO)
436  {
437  long double value = static_cast<long double>(timeU.m_time.GetTimeStep());
438  // convert to finest scale (fs)
440  // find the best unit
441  int u = Time::Y;
442  while (u != Time::LAST && UNIT_VALUE[u] > value)
443  {
444  ++u;
445  }
446  if (u == Time::LAST)
447  {
448  --u;
449  }
450  unit = static_cast<Time::Unit>(u);
451  }
452 
453  switch (unit)
454  {
455  case Time::Y:
456  label = "y";
457  break;
458  case Time::D:
459  label = "d";
460  break;
461  case Time::H:
462  label = "h";
463  break;
464  case Time::MIN:
465  label = "min";
466  break;
467  case Time::S:
468  label = "s";
469  break;
470  case Time::MS:
471  label = "ms";
472  break;
473  case Time::US:
474  label = "us";
475  break;
476  case Time::NS:
477  label = "ns";
478  break;
479  case Time::PS:
480  label = "ps";
481  break;
482  case Time::FS:
483  label = "fs";
484  break;
485 
486  case Time::LAST:
487  case Time::AUTO:
488  default:
489  NS_ABORT_MSG("can't be reached");
490  label = "unreachable";
491  break;
492  }
493 
494  double v = timeU.m_time.ToDouble(unit);
495 
496  // Note: we must copy the "original" format flags because we have to modify them.
497  // std::ios_base::showpos is to print the "+" in front of the number for positive,
498  // std::ios_base::right is to add (eventual) extra space in front of the number.
499  // the eventual extra space might be due to a std::setw (_number_), and
500  // normally it would be printed after the number and before the time unit label.
501 
502  std::ios_base::fmtflags ff = os.flags();
503 
504  os << std::showpos << std::right << v << label;
505 
506  // And here we have to restore what we changed.
507  if (!(ff & std::ios_base::showpos))
508  {
509  os << std::noshowpos;
510  }
511  if (ff & std::ios_base::left)
512  {
513  os << std::left;
514  }
515  else if (ff & std::ios_base::internal)
516  {
517  os << std::internal;
518  }
519 
520  return os;
521 }
522 
523 std::istream&
524 operator>>(std::istream& is, Time& time)
525 {
526  std::string value;
527  is >> value;
528  time = Time(value);
529  return is;
530 }
531 
533 
536 {
537  NS_LOG_FUNCTION(min << max);
538 
539  struct Checker : public AttributeChecker
540  {
541  Checker(const Time minValue, const Time maxValue)
542  : m_minValue(minValue),
543  m_maxValue(maxValue)
544  {
545  }
546 
547  bool Check(const AttributeValue& value) const override
548  {
550  const TimeValue* v = dynamic_cast<const TimeValue*>(&value);
551  if (v == nullptr)
552  {
553  return false;
554  }
555  return v->Get() >= m_minValue && v->Get() <= m_maxValue;
556  }
557 
558  std::string GetValueTypeName() const override
559  {
561  return "ns3::TimeValue";
562  }
563 
564  bool HasUnderlyingTypeInformation() const override
565  {
567  return true;
568  }
569 
570  std::string GetUnderlyingTypeInformation() const override
571  {
573  std::ostringstream oss;
574  oss << "Time"
575  << " " << m_minValue << ":" << m_maxValue;
576  return oss.str();
577  }
578 
579  Ptr<AttributeValue> Create() const override
580  {
582  return ns3::Create<TimeValue>();
583  }
584 
585  bool Copy(const AttributeValue& source, AttributeValue& destination) const override
586  {
587  NS_LOG_FUNCTION(&source << &destination);
588  const TimeValue* src = dynamic_cast<const TimeValue*>(&source);
589  TimeValue* dst = dynamic_cast<TimeValue*>(&destination);
590  if (src == nullptr || dst == nullptr)
591  {
592  return false;
593  }
594  *dst = *src;
595  return true;
596  }
597 
598  Time m_minValue;
599  Time m_maxValue;
600  }* checker = new Checker(min, max);
601 
602  return Ptr<const AttributeChecker>(checker, false);
603 }
604 
605 } // namespace ns3
#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:168
Hold a value for an Attribute.
Definition: attribute.h:70
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
static Unit GetResolution()
Definition: time.cc:410
static void ClearMarkedTimes()
Remove all MarkedTimes.
Definition: time.cc:296
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:417
static void ConvertTimes(const Unit unit)
Convert existing Times to the new unit.
Definition: time.cc:378
static bool StaticInit()
Function to force static initialization of Time.
Definition: time.cc:97
static void Clear(Time *const time)
Remove a Time instance from the MarkedTimes, called by ~Time().
Definition: time.cc:350
Unit
The unit to use to interpret a number representing time.
Definition: nstime.h:111
@ AUTO
auto-scale output when using Time::As()
Definition: nstime.h:123
@ D
day, 24 hours
Definition: nstime.h:113
@ US
microsecond
Definition: nstime.h:118
@ PS
picosecond
Definition: nstime.h:120
@ LAST
marker for last normal value
Definition: nstime.h:122
@ Y
year, 365 days
Definition: nstime.h:112
@ FS
femtosecond
Definition: nstime.h:121
@ H
hour, 60 minutes
Definition: nstime.h:114
@ MIN
minute, 60 seconds
Definition: nstime.h:115
@ MS
millisecond
Definition: nstime.h:117
@ S
second
Definition: nstime.h:116
@ NS
nanosecond
Definition: nstime.h:119
Time()
Default constructor, with value 0.
Definition: nstime.h:138
static MarkedTimes * g_markingTimes
Record of outstanding Time objects which will need conversion when the resolution is set.
Definition: nstime.h:721
int64_t m_data
Virtual time value, in the current unit.
Definition: nstime.h:835
static void Mark(Time *const time)
Record a Time instance with the MarkedTimes.
Definition: time.cc:325
static void SetResolution(Unit resolution)
Definition: time.cc:213
int64_t ToInteger(Unit unit) const
Get the Time value expressed in a particular unit.
Definition: nstime.h:554
static struct Resolution & SetDefaultNsResolution()
Set the default resolution.
Definition: time.cc:203
static Time FromDouble(double value, Unit unit)
Create a Time equal to value in unit unit.
Definition: nstime.h:515
double ToDouble(Unit unit) const
Get the Time value expressed in a particular unit.
Definition: nstime.h:572
int64_t GetTimeStep() const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:444
static struct Resolution * PeekResolution()
Get the current Resolution.
Definition: nstime.h:654
std::set< Time * > MarkedTimes
Record all instances of Time, so we can rescale them when the resolution changes.
Definition: nstime.h:706
AttributeValue implementation for Time.
Definition: nstime.h:1423
Time Get() const
Definition: time.cc:532
A Time with attached unit, to facilitate output in that unit.
Definition: nstime.h:1467
Time m_time
The time.
Definition: nstime.h:1482
Time::Unit m_unit
The unit to use in output.
Definition: nstime.h:1483
High precision numerical type, implementing Q64.64 fixed precision.
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:66
#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:86
#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:49
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:254
#define NS_LOG_COMPONENT_DEFINE_MASK(name, mask)
Define a logging component with a mask.
Definition: log.h:213
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#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:261
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition: ptr.h:481
Debug message logging.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:848
const long double * UNIT_VALUE
Value of each unit, in terms of the smallest defined unit.
Definition: time.cc:81
const int32_t UNIT_COEFF[Time::LAST]
Scaling coefficient, relative to smallest unit.
Definition: time.cc:52
const int8_t UNIT_POWER[Time::LAST]
Scaling coefficients, exponents, and look up table for unit.
Definition: time.cc:50
long double Scale(Time::Unit u)
Scale a unit to the smallest unit.
Definition: time.cc:60
long double * InitUnitValue()
Initializer for UNIT_VALUE.
Definition: time.cc:70
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:535
@ 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:153
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:129
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition: ptr.h:649
value
Definition: second.py:41
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:633
int64_t factor
Ratio of this unit / current unit.
Definition: nstime.h:636
bool toMul
Multiply when converting To, otherwise divide.
Definition: nstime.h:634
int64x64_t timeFrom
Multiplier to convert from this unit.
Definition: nstime.h:638
bool isValid
True if the current unit can be used.
Definition: nstime.h:639
bool fromMul
Multiple when converting From, otherwise divide.
Definition: nstime.h:635
int64x64_t timeTo
Multiplier to convert to this unit.
Definition: nstime.h:637
Current time unit, and conversion info.
Definition: nstime.h:644
Time::Unit unit
Current time unit.
Definition: nstime.h:646
Information info[LAST]
Conversion info from current unit.
Definition: nstime.h:645