A Discrete-Event Network Simulator
API
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 "system-mutex.h"
25#include "log.h"
26#include <cmath> // pow
27#include <iomanip> // showpos
28#include <sstream>
29
37namespace ns3 {
38
40
42namespace {
43
47 // Y, D, H, MIN, S, MS, US, NS, PS, FS
48 const int8_t UNIT_POWER[Time::LAST] = { 17, 17, 17, 16, 15, 12, 9, 6, 3, 0 };
50 const int32_t UNIT_COEFF[Time::LAST] = { 315360, 864, 36, 6, 1, 1, 1, 1, 1, 1 };
51
52
58 long double
60 {
61 return UNIT_COEFF[u] * std::pow (10L, UNIT_POWER[u]);
62 }
63
68 long double *
70 {
71 static long double values[Time::LAST];
72 for (auto u = static_cast<int> (Time::Y); u != static_cast<int> (Time::LAST); ++u)
73 {
74 values [u] = Scale (static_cast<Time::Unit> (u));
75 }
76 return values;
77 }
78
80 const long double * UNIT_VALUE = InitUnitValue ();
81
84} // unnamed namespace
85
86
87// The set of marked times
88// static
90
101{
102 static SystemMutex g_markingMutex;
103 return g_markingMutex;
104}
105
106
107// Function called to force static initialization
108// static
110{
111 static bool firstTime = true;
112
113 CriticalSection critical (GetMarkingMutex ());
114
115 if (firstTime)
116 {
117 if (!g_markingTimes)
118 {
119 static MarkedTimes markingTimes;
120 g_markingTimes = &markingTimes;
121 }
122 else
123 {
124 NS_LOG_ERROR ("firstTime but g_markingTimes != 0");
125 }
126
127 // Schedule the cleanup.
128 // We'd really like:
129 // NS_LOG_LOGIC ("scheduling ClearMarkedTimes()");
130 // Simulator::Schedule ( Seconds (0), & ClearMarkedTimes);
131 // [or even better: Simulator::AtStart ( & ClearMarkedTimes ); ]
132 // But this triggers a static initialization order error,
133 // since the Simulator static initialization may not have occurred.
134 // Instead, we call ClearMarkedTimes directly from Simulator::Run ()
135 firstTime = false;
136 }
137
138 return firstTime;
139}
140
141
142Time::Time (const std::string& s)
143{
144 NS_LOG_FUNCTION (this << &s);
145 std::string::size_type n = s.find_first_not_of ("+-0123456789.eE");
146 if (n != std::string::npos)
147 { // Found non-numeric
148 std::istringstream iss;
149 iss.str (s.substr (0, n));
150 double r;
151 iss >> r;
152 std::string trailer = s.substr (n, std::string::npos);
153 if (trailer == std::string ("s"))
154 {
155 *this = Time::FromDouble (r, Time::S);
156 }
157 else if (trailer == std::string ("ms"))
158 {
159 *this = Time::FromDouble (r, Time::MS);
160 }
161 else if (trailer == std::string ("us"))
162 {
163 *this = Time::FromDouble (r, Time::US);
164 }
165 else if (trailer == std::string ("ns"))
166 {
167 *this = Time::FromDouble (r, Time::NS);
168 }
169 else if (trailer == std::string ("ps"))
170 {
171 *this = Time::FromDouble (r, Time::PS);
172 }
173 else if (trailer == std::string ("fs"))
174 {
175 *this = Time::FromDouble (r, Time::FS);
176 }
177 else if (trailer == std::string ("min"))
178 {
179 *this = Time::FromDouble (r, Time::MIN);
180 }
181 else if (trailer == std::string ("h"))
182 {
183 *this = Time::FromDouble (r, Time::H);
184 }
185 else if (trailer == std::string ("d"))
186 {
187 *this = Time::FromDouble (r, Time::D);
188 }
189 else if (trailer == std::string ("y"))
190 {
191 *this = Time::FromDouble (r, Time::Y);
192 }
193 else
194 {
195 NS_ABORT_MSG ("Can't Parse Time " << s);
196 }
197 }
198 else
199 {
200 // they didn't provide units, assume seconds
201 std::istringstream iss;
202 iss.str (s);
203 double v;
204 iss >> v;
205 *this = Time::FromDouble (v, Time::S);
206 }
207
208 if (g_markingTimes)
209 {
210 Mark (this);
211 }
212}
213
214// static
215struct Time::Resolution
216Time::SetDefaultNsResolution (void)
217{
219 struct Resolution resolution;
220 SetResolution (Time::NS, &resolution, false);
221 return resolution;
222}
223
224// static
225void
226Time::SetResolution (enum Unit resolution)
227{
228 NS_LOG_FUNCTION (resolution);
229 SetResolution (resolution, PeekResolution ());
230}
231
232
233// static
234void
235Time::SetResolution (enum Unit unit, struct Resolution *resolution,
236 const bool convert /* = true */)
237{
238 NS_LOG_FUNCTION (resolution);
239 if (convert)
240 {
241 // We have to convert existing Times with the old
242 // conversion values, so do it first
243 ConvertTimes (unit);
244 }
245
246 for (int i = 0; i < Time::LAST; i++)
247 {
248 int shift = UNIT_POWER[i] - UNIT_POWER[(int)unit];
249 int quotient = 1;
250 if (UNIT_COEFF[i] > UNIT_COEFF[(int) unit])
251 {
252 quotient = UNIT_COEFF[i] / UNIT_COEFF[(int) unit];
253 NS_ASSERT (quotient * UNIT_COEFF[(int) unit] == UNIT_COEFF[i]);
254 }
255 else if (UNIT_COEFF[i] < UNIT_COEFF[(int) unit])
256 {
257 quotient = UNIT_COEFF[(int) unit] / UNIT_COEFF[i];
258 NS_ASSERT (quotient * UNIT_COEFF[i] == UNIT_COEFF[(int) unit]);
259 }
260 NS_LOG_DEBUG ("SetResolution for unit " << (int) unit <<
261 " loop iteration " << i <<
262 " has shift " << shift << " has quotient " << quotient);
263 int64_t factor = static_cast<int64_t> (std::pow (10, std::fabs (shift)) * quotient);
264 double realFactor = std::pow (10, (double) shift)
265 * static_cast<double> (UNIT_COEFF[i]) / UNIT_COEFF[(int) unit];
266 NS_LOG_DEBUG ("SetResolution factor " << factor << " real factor " << realFactor);
267 struct Information *info = &resolution->info[i];
268 info->factor = factor;
269 // here we could equivalently check for realFactor == 1.0 but it's better
270 // to avoid checking equality of doubles
271 if (shift == 0 && quotient == 1)
272 {
273 info->timeFrom = int64x64_t (1);
274 info->timeTo = int64x64_t (1);
275 info->toMul = true;
276 info->fromMul = true;
277 }
278 else if (realFactor > 1)
279 {
280 info->timeFrom = int64x64_t (factor);
281 info->timeTo = int64x64_t::Invert (factor);
282 info->toMul = false;
283 info->fromMul = true;
284 }
285 else
286 {
287 NS_ASSERT (realFactor < 1);
288 info->timeFrom = int64x64_t::Invert (factor);
289 info->timeTo = int64x64_t (factor);
290 info->toMul = true;
291 info->fromMul = false;
292 }
293 }
294 resolution->unit = unit;
295}
296
297
298// static
299void
301{
317 CriticalSection critical (GetMarkingMutex ());
318
320 if (g_markingTimes)
321 {
322 NS_LOG_LOGIC ("clearing MarkedTimes");
323 g_markingTimes->erase (g_markingTimes->begin (), g_markingTimes->end ());
324 g_markingTimes = 0;
325 }
326} // Time::ClearMarkedTimes
327
328
329// static
330void
331Time::Mark (Time * const time)
332{
333 CriticalSection critical (GetMarkingMutex ());
334
335 NS_LOG_FUNCTION (time);
336 NS_ASSERT (time != 0);
337
338 // Repeat the g_markingTimes test here inside the CriticalSection,
339 // since earlier test was outside and might be stale.
340 if (g_markingTimes)
341 {
342 std::pair< MarkedTimes::iterator, bool> ret;
343
344 ret = g_markingTimes->insert ( time);
345 NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] recording " << time);
346
347 if (ret.second == false)
348 {
349 NS_LOG_WARN ("already recorded " << time << "!");
350 }
351 }
352} // Time::Mark ()
353
354
355// static
356void
357Time::Clear (Time * const time)
358{
359 CriticalSection critical (GetMarkingMutex ());
360
361 NS_LOG_FUNCTION (time);
362 NS_ASSERT (time != 0);
363
364 if (g_markingTimes)
365 {
366 NS_ASSERT_MSG (g_markingTimes->count (time) == 1,
367 "Time object " << time <<
368 " registered " << g_markingTimes->count (time) <<
369 " times (should be 1)." );
370
371 MarkedTimes::size_type num = g_markingTimes->erase (time);
372 if (num != 1)
373 {
374 NS_LOG_WARN ("unexpected result erasing " << time << "!");
375 NS_LOG_WARN ("got " << num << ", expected 1");
376 }
377 else
378 {
379 NS_LOG_LOGIC ("\t[" << g_markingTimes->size () << "] removing " << time);
380 }
381 }
382} // Time::Clear ()
383
384
385// static
386void
387Time::ConvertTimes (const enum Unit unit)
388{
389 CriticalSection critical (GetMarkingMutex ());
390
392
394 "No MarkedTimes registry. "
395 "Time::SetResolution () called more than once?");
396
397 for ( MarkedTimes::iterator it = g_markingTimes->begin ();
398 it != g_markingTimes->end ();
399 it++ )
400 {
401 Time * const tp = *it;
404 )
405 )
406 {
407 tp->m_data = tp->ToInteger (unit);
408 }
409 }
410
411 NS_LOG_LOGIC ("logged " << g_markingTimes->size () << " Time objects.");
412
413 // Body of ClearMarkedTimes
414 // Assert above already guarantees g_markingTimes != 0
415 NS_LOG_LOGIC ("clearing MarkedTimes");
416 g_markingTimes->erase (g_markingTimes->begin (), g_markingTimes->end ());
417 g_markingTimes = 0;
418
419} // Time::ConvertTimes ()
420
421
422// static
423enum Time::Unit
425{
426 // No function log b/c it interferes with operator<<
427 return PeekResolution ()->unit;
428}
429
430
432Time::As (const enum Unit unit /* = Time::AUTO */) const
433{
434 return TimeWithUnit (*this, unit);
435}
436
437
438std::ostream &
439operator << (std::ostream & os, const Time & time)
440{
441 os << time.As (Time::GetResolution ());
442 return os;
443}
444
445
446std::ostream &
447operator << (std::ostream & os, const TimeWithUnit & timeU)
448{
449
450 std::string label;
451 Time::Unit unit = timeU.m_unit;
452
453 if (unit == Time::AUTO)
454 {
455 long double value = static_cast<long double> (timeU.m_time.GetTimeStep ());
456 // convert to finest scale (fs)
457 value *= Scale (Time::GetResolution ());
458 // find the best unit
459 int u = Time::Y;
460 while (u != Time::LAST && UNIT_VALUE[u] > value)
461 {
462 ++u;
463 }
464 if (u == Time::LAST)
465 {
466 --u;
467 }
468 unit = static_cast<Time::Unit> (u);
469 }
470
471 switch (unit)
472 {
473 // *NS_CHECK_STYLE_OFF*
474 case Time::Y: label = "y"; break;
475 case Time::D: label = "d"; break;
476 case Time::H: label = "h"; break;
477 case Time::MIN: label = "min"; break;
478 case Time::S: label = "s"; break;
479 case Time::MS: label = "ms"; break;
480 case Time::US: label = "us"; break;
481 case Time::NS: label = "ns"; break;
482 case Time::PS: label = "ps"; break;
483 case Time::FS: label = "fs"; break;
484 // *NS_CHECK_STYLE_ON*
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
524std::istream &
525operator >> (std::istream & is, Time & time)
526{
527 std::string value;
528 is >> value;
529 time = Time (value);
530 return is;
531}
532
534
537{
539
540 struct Checker : public AttributeChecker
541 {
542 Checker (const Time minValue, const Time maxValue)
543 : m_minValue (minValue),
544 m_maxValue (maxValue)
545 {}
546 virtual bool Check (const AttributeValue &value) const
547 {
548 NS_LOG_FUNCTION (&value);
549 const TimeValue *v = dynamic_cast<const TimeValue *> (&value);
550 if (v == 0)
551 {
552 return false;
553 }
554 return v->Get () >= m_minValue && v->Get () <= m_maxValue;
555 }
556 virtual std::string GetValueTypeName (void) const
557 {
559 return "ns3::TimeValue";
560 }
561 virtual bool HasUnderlyingTypeInformation (void) const
562 {
564 return true;
565 }
566 virtual std::string GetUnderlyingTypeInformation (void) const
567 {
569 std::ostringstream oss;
570 oss << "Time" << " " << m_minValue << ":" << m_maxValue;
571 return oss.str ();
572 }
573 virtual Ptr<AttributeValue> Create (void) const
574 {
576 return ns3::Create<TimeValue> ();
577 }
578 virtual bool Copy (const AttributeValue &source, AttributeValue &destination) const
579 {
580 NS_LOG_FUNCTION (&source << &destination);
581 const TimeValue *src = dynamic_cast<const TimeValue *> (&source);
582 TimeValue *dst = dynamic_cast<TimeValue *> (&destination);
583 if (src == 0 || dst == 0)
584 {
585 return false;
586 }
587 *dst = *src;
588 return true;
589 }
590 Time m_minValue;
591 Time m_maxValue;
592 } *checker = new Checker (min, max);
593 return Ptr<const AttributeChecker> (checker, false);
594}
595
596
597} // namespace ns3
598
#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:167
Hold a value for an Attribute.
Definition: attribute.h:69
A class which provides a simple way to implement a Critical Section.
Definition: system-mutex.h:119
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
A class which provides a relatively platform-independent Mutual Exclusion thread synchronization prim...
Definition: system-mutex.h:59
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
static enum Unit GetResolution(void)
Definition: time.cc:424
double ToDouble(enum Unit unit) const
Get the Time value expressed in a particular unit.
Definition: nstime.h:529
static void ClearMarkedTimes()
Remove all MarkedTimes.
Definition: time.cc:300
int64_t GetTimeStep(void) const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:415
int64_t ToInteger(enum Unit unit) const
Get the Time value expressed in a particular unit.
Definition: nstime.h:515
static Time FromDouble(double value, enum Unit unit)
Create a Time equal to value in unit unit.
Definition: nstime.h:480
static bool StaticInit()
Function to force static initialization of Time.
Definition: time.cc:109
static void Clear(Time *const time)
Remove a Time instance from the MarkedTimes, called by ~Time().
Definition: time.cc:357
Unit
The unit to use to interpret a number representing time.
Definition: nstime.h:109
@ AUTO
auto-scale output when using Time::As()
Definition: nstime.h:121
@ D
day, 24 hours
Definition: nstime.h:111
@ US
microsecond
Definition: nstime.h:116
@ PS
picosecond
Definition: nstime.h:118
@ LAST
marker for last normal value
Definition: nstime.h:120
@ Y
year, 365 days
Definition: nstime.h:110
@ FS
femtosecond
Definition: nstime.h:119
@ H
hour, 60 minutes
Definition: nstime.h:112
@ MIN
minute, 60 seconds
Definition: nstime.h:113
@ MS
millisecond
Definition: nstime.h:115
@ S
second
Definition: nstime.h:114
@ NS
nanosecond
Definition: nstime.h:117
Time()
Default constructor, with value 0.
Definition: nstime.h:135
static MarkedTimes * g_markingTimes
Record of outstanding Time objects which will need conversion when the resolution is set.
Definition: nstime.h:670
int64_t m_data
Virtual time value, in the current unit.
Definition: nstime.h:781
static void Mark(Time *const time)
Record a Time instance with the MarkedTimes.
Definition: time.cc:331
static void ConvertTimes(const enum Unit unit)
Convert existing Times to the new unit.
Definition: time.cc:387
static void SetResolution(enum Unit resolution)
Definition: time.cc:226
static struct Resolution * PeekResolution(void)
Get the current Resolution.
Definition: nstime.h:604
TimeWithUnit As(const enum Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:432
std::set< Time * > MarkedTimes
Record all instances of Time, so we can rescale them when the resolution changes.
Definition: nstime.h:655
SystemMutex & GetMarkingMutex()
Definition: time.cc:100
AttributeValue implementation for Time.
Definition: nstime.h:1308
Time Get(void) const
Definition: time.cc:533
A Time with attached unit, to facilitate output in that unit.
Definition: nstime.h:1352
Time m_time
The time.
Definition: nstime.h:1366
Time::Unit m_unit
The unit to use in output.
Definition: nstime.h:1367
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:67
#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:88
#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:50
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:257
#define NS_LOG_COMPONENT_DEFINE_MASK(name, mask)
Define a logging component with a mask.
Definition: log.h:216
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
#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:265
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition: ptr.h:409
Debug message logging.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:793
const long double * UNIT_VALUE
Value of each unit, in terms of the smallest defined unit.
Definition: time.cc:80
long double * InitUnitValue(void)
Initializer for UNIT_VALUE.
Definition: time.cc:69
const int32_t UNIT_COEFF[Time::LAST]
Scaling coefficient, relative to smallest unit.
Definition: time.cc:50
const int8_t UNIT_POWER[Time::LAST]
Scaling coefficients, exponents, and look up table for unit.
Definition: time.cc:48
long double Scale(Time::Unit u)
Scale a unit to the smallest unit.
Definition: time.cc:59
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:139
std::istream & operator>>(std::istream &is, Angles &a)
Definition: angles.cc:162
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:536
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition: ptr.h:555
@ LOG_PREFIX_TIME
Prefix all trace prints with simulation time.
Definition: log.h:119
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:585
int64_t factor
Ratio of this unit / current unit.
Definition: nstime.h:588
bool toMul
Multiply when converting To, otherwise divide.
Definition: nstime.h:586
int64x64_t timeFrom
Multiplier to convert from this unit.
Definition: nstime.h:590
bool fromMul
Multiple when converting From, otherwise divide.
Definition: nstime.h:587
int64x64_t timeTo
Multiplier to convert to this unit.
Definition: nstime.h:589
Current time unit, and conversion info.
Definition: nstime.h:594
struct Information info[LAST]
Conversion info from current unit.
Definition: nstime.h:595
enum Time::Unit unit
Current time unit.
Definition: nstime.h:596
System-independent mutex primitive, ns3::SystemMutex, and ns3::CriticalSection.