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 == "s")
141  {
142  *this = Time::FromDouble(r, Time::S);
143  }
144  else if (trailer == "ms")
145  {
146  *this = Time::FromDouble(r, Time::MS);
147  }
148  else if (trailer == "us")
149  {
150  *this = Time::FromDouble(r, Time::US);
151  }
152  else if (trailer == "ns")
153  {
154  *this = Time::FromDouble(r, Time::NS);
155  }
156  else if (trailer == "ps")
157  {
158  *this = Time::FromDouble(r, Time::PS);
159  }
160  else if (trailer == "fs")
161  {
162  *this = Time::FromDouble(r, Time::FS);
163  }
164  else if (trailer == "min")
165  {
166  *this = Time::FromDouble(r, Time::MIN);
167  }
168  else if (trailer == "h")
169  {
170  *this = Time::FromDouble(r, Time::H);
171  }
172  else if (trailer == "d")
173  {
174  *this = Time::FromDouble(r, Time::D);
175  }
176  else if (trailer == "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
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  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  auto 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  auto ret = g_markingTimes->insert(time);
337  NS_LOG_LOGIC("\t[" << g_markingTimes->size() << "] recording " << time);
338 
339  if (!ret.second)
340  {
341  NS_LOG_WARN("already recorded " << time << "!");
342  }
343  }
344 } // Time::Mark ()
345 
346 // static
347 void
348 Time::Clear(Time* const time)
349 {
350  std::unique_lock lock{g_markingMutex};
351 
352  NS_LOG_FUNCTION(time);
353  NS_ASSERT(time != nullptr);
354 
355  if (g_markingTimes)
356  {
357  NS_ASSERT_MSG(g_markingTimes->count(time) == 1,
358  "Time object " << time << " registered " << g_markingTimes->count(time)
359  << " times (should be 1).");
360 
361  MarkedTimes::size_type num = g_markingTimes->erase(time);
362  if (num != 1)
363  {
364  NS_LOG_WARN("unexpected result erasing " << time << "!");
365  NS_LOG_WARN("got " << num << ", expected 1");
366  }
367  else
368  {
369  NS_LOG_LOGIC("\t[" << g_markingTimes->size() << "] removing " << time);
370  }
371  }
372 } // Time::Clear ()
373 
374 // static
375 void
377 {
378  std::unique_lock lock{g_markingMutex};
379 
381 
382  NS_ASSERT_MSG(g_markingTimes != nullptr,
383  "No MarkedTimes registry. "
384  "Time::SetResolution () called more than once?");
385 
386  for (auto it = g_markingTimes->begin(); it != g_markingTimes->end(); it++)
387  {
388  Time* const tp = *it;
389  if (!(tp->m_data == std::numeric_limits<int64_t>::min() ||
391  {
392  tp->m_data = tp->ToInteger(unit);
393  }
394  }
395 
396  NS_LOG_LOGIC("logged " << g_markingTimes->size() << " Time objects.");
397 
398  // Body of ClearMarkedTimes
399  // Assert above already guarantees g_markingTimes != 0
400  NS_LOG_LOGIC("clearing MarkedTimes");
401  g_markingTimes->erase(g_markingTimes->begin(), g_markingTimes->end());
402  g_markingTimes = nullptr;
403 
404 } // Time::ConvertTimes ()
405 
406 // static
409 {
410  // No function log b/c it interferes with operator<<
411  return PeekResolution()->unit;
412 }
413 
415 Time::As(const Unit unit /* = Time::AUTO */) const
416 {
417  return TimeWithUnit(*this, unit);
418 }
419 
420 std::ostream&
421 operator<<(std::ostream& os, const Time& time)
422 {
423  os << time.As(Time::GetResolution());
424  return os;
425 }
426 
427 std::ostream&
428 operator<<(std::ostream& os, const TimeWithUnit& timeU)
429 {
430  std::string label;
431  Time::Unit unit = timeU.m_unit;
432 
433  if (unit == Time::AUTO)
434  {
435  auto value = static_cast<long double>(timeU.m_time.GetTimeStep());
436  // convert to finest scale (fs)
437  value *= Scale(Time::GetResolution());
438  // find the best unit
439  int u = Time::Y;
440  while (u != Time::LAST && UNIT_VALUE[u] > value)
441  {
442  ++u;
443  }
444  if (u == Time::LAST)
445  {
446  --u;
447  }
448  unit = static_cast<Time::Unit>(u);
449  }
450 
451  switch (unit)
452  {
453  case Time::Y:
454  label = "y";
455  break;
456  case Time::D:
457  label = "d";
458  break;
459  case Time::H:
460  label = "h";
461  break;
462  case Time::MIN:
463  label = "min";
464  break;
465  case Time::S:
466  label = "s";
467  break;
468  case Time::MS:
469  label = "ms";
470  break;
471  case Time::US:
472  label = "us";
473  break;
474  case Time::NS:
475  label = "ns";
476  break;
477  case Time::PS:
478  label = "ps";
479  break;
480  case Time::FS:
481  label = "fs";
482  break;
483 
484  case Time::LAST:
485  case Time::AUTO:
486  default:
487  NS_ABORT_MSG("can't be reached");
488  label = "unreachable";
489  break;
490  }
491 
492  double v = timeU.m_time.ToDouble(unit);
493 
494  // Note: we must copy the "original" format flags because we have to modify them.
495  // std::ios_base::showpos is to print the "+" in front of the number for positive,
496  // std::ios_base::right is to add (eventual) extra space in front of the number.
497  // the eventual extra space might be due to a std::setw (_number_), and
498  // normally it would be printed after the number and before the time unit label.
499 
500  std::ios_base::fmtflags ff = os.flags();
501 
502  os << std::showpos << std::right << v << label;
503 
504  // And here we have to restore what we changed.
505  if (!(ff & std::ios_base::showpos))
506  {
507  os << std::noshowpos;
508  }
509  if (ff & std::ios_base::left)
510  {
511  os << std::left;
512  }
513  else if (ff & std::ios_base::internal)
514  {
515  os << std::internal;
516  }
517 
518  return os;
519 }
520 
521 std::istream&
522 operator>>(std::istream& is, Time& time)
523 {
524  std::string value;
525  is >> value;
526  time = Time(value);
527  return is;
528 }
529 
531 
534 {
535  NS_LOG_FUNCTION(min << max);
536 
537  struct Checker : public AttributeChecker
538  {
539  Checker(const Time minValue, const Time maxValue)
540  : m_minValue(minValue),
541  m_maxValue(maxValue)
542  {
543  }
544 
545  bool Check(const AttributeValue& value) const override
546  {
547  NS_LOG_FUNCTION(&value);
548  const auto v = dynamic_cast<const TimeValue*>(&value);
549  if (v == nullptr)
550  {
551  return false;
552  }
553  return v->Get() >= m_minValue && v->Get() <= m_maxValue;
554  }
555 
556  std::string GetValueTypeName() const override
557  {
559  return "ns3::TimeValue";
560  }
561 
562  bool HasUnderlyingTypeInformation() const override
563  {
565  return true;
566  }
567 
568  std::string GetUnderlyingTypeInformation() const override
569  {
571  std::ostringstream oss;
572  oss << "Time"
573  << " " << m_minValue << ":" << m_maxValue;
574  return oss.str();
575  }
576 
577  Ptr<AttributeValue> Create() const override
578  {
580  return ns3::Create<TimeValue>();
581  }
582 
583  bool Copy(const AttributeValue& source, AttributeValue& destination) const override
584  {
585  NS_LOG_FUNCTION(&source << &destination);
586  const auto src = dynamic_cast<const TimeValue*>(&source);
587  auto dst = dynamic_cast<TimeValue*>(&destination);
588  if (src == nullptr || dst == nullptr)
589  {
590  return false;
591  }
592  *dst = *src;
593  return true;
594  }
595 
596  Time m_minValue;
597  Time m_maxValue;
598  }* checker = new Checker(min, max);
599 
600  return Ptr<const AttributeChecker>(checker, false);
601 }
602 
603 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
#define max(a, b)
Definition: 80211b.c:42
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:77
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
static void ClearMarkedTimes()
Remove all MarkedTimes.
Definition: time.cc:296
static Resolution & SetDefaultNsResolution()
Set the default resolution.
Definition: time.cc:203
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:415
static void ConvertTimes(const Unit unit)
Convert existing Times to the new unit.
Definition: time.cc:376
static Resolution * PeekResolution()
Get the current Resolution.
Definition: nstime.h:655
static Unit GetResolution()
Definition: time.cc:408
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:348
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:722
int64_t m_data
Virtual time value, in the current unit.
Definition: nstime.h:826
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:555
static Time FromDouble(double value, Unit unit)
Create a Time equal to value in unit unit.
Definition: nstime.h:516
double ToDouble(Unit unit) const
Get the Time value expressed in a particular unit.
Definition: nstime.h:573
int64_t GetTimeStep() const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:445
std::set< Time * > MarkedTimes
Record all instances of Time, so we can rescale them when the resolution changes.
Definition: nstime.h:707
Time Get() const
Definition: time.cc:530
A Time with attached unit, to facilitate output in that unit.
Definition: nstime.h:1457
Time m_time
The time.
Definition: nstime.h:1472
Time::Unit m_unit
The unit to use in output.
Definition: nstime.h:1473
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:442
Debug message logging.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:839
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:533
@ 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:183
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:159
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition: ptr.h:610
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:634
int64_t factor
Ratio of this unit / current unit.
Definition: nstime.h:637
bool toMul
Multiply when converting To, otherwise divide.
Definition: nstime.h:635
int64x64_t timeFrom
Multiplier to convert from this unit.
Definition: nstime.h:639
bool isValid
True if the current unit can be used.
Definition: nstime.h:640
bool fromMul
Multiple when converting From, otherwise divide.
Definition: nstime.h:636
int64x64_t timeTo
Multiplier to convert to this unit.
Definition: nstime.h:638
Current time unit, and conversion info.
Definition: nstime.h:645
Time::Unit unit
Current time unit.
Definition: nstime.h:647
Information info[LAST]
Conversion info from current unit.
Definition: nstime.h:646