A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
37namespace ns3
38{
39
41
43namespace
44{
45
49// Y, D, H, MIN, S, MS, US, NS, PS, FS
50const int8_t UNIT_POWER[Time::LAST] = {17, 17, 17, 16, 15, 12, 9, 6, 3, 0};
52const int32_t UNIT_COEFF[Time::LAST] = {315360, 864, 36, 6, 1, 1, 1, 1, 1, 1};
53
59long double
61{
62 return UNIT_COEFF[u] * std::pow(10L, UNIT_POWER[u]);
63}
64
69long 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
81const long double* UNIT_VALUE = InitUnitValue();
82
85} // unnamed namespace
86
87// The set of marked times
88// static
90
92static std::mutex g_markingMutex;
93
94// Function called to force static initialization
95// static
96bool
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
129Time::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
212void
214{
215 NS_LOG_FUNCTION(resolution);
216 SetResolution(resolution, PeekResolution());
217}
218
219// static
220void
221Time::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 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
295void
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
324void
325Time::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)
342 {
343 NS_LOG_WARN("already recorded " << time << "!");
344 }
345 }
346} // Time::Mark ()
347
348// static
349void
350Time::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
377void
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() ||
392 tp->m_data == std::numeric_limits<int64_t>::max()))
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
411{
412 // No function log b/c it interferes with operator<<
413 return PeekResolution()->unit;
414}
415
417Time::As(const Unit unit /* = Time::AUTO */) const
418{
419 return TimeWithUnit(*this, unit);
420}
421
422std::ostream&
423operator<<(std::ostream& os, const Time& time)
424{
425 os << time.As(Time::GetResolution());
426 return os;
427}
428
429std::ostream&
430operator<<(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)
439 value *= Scale(Time::GetResolution());
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
523std::istream&
524operator>>(std::istream& is, Time& time)
525{
526 std::string value;
527 is >> value;
528 time = Time(value);
529 return is;
530}
531
533
536{
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 {
549 NS_LOG_FUNCTION(&value);
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: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:78
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:417
static void ConvertTimes(const Unit unit)
Convert existing Times to the new unit.
Definition: time.cc:378
static Unit GetResolution()
Definition: time.cc:410
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 Resolution * PeekResolution()
Get the current Resolution.
Definition: nstime.h:654
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 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
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
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1444
#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.
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 * InitUnitValue()
Initializer for UNIT_VALUE.
Definition: time.cc:70
long double Scale(Time::Unit u)
Scale a unit to the smallest unit.
Definition: time.cc:60
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:129
std::istream & operator>>(std::istream &is, Angles &a)
Definition: angles.cc:153
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition: ptr.h:649
@ LOG_PREFIX_TIME
Prefix all trace prints with simulation time.
Definition: log.h:119
static std::mutex g_markingMutex
The static mutex for critical sections around modification of Time::g_markingTimes.
Definition: time.cc:92
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