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
30/**
31 * \file
32 * \ingroup time
33 * ns3::Time, ns3::TimeWithUnit
34 * and ns3::TimeValue attribute value implementations.
35 */
36
37namespace ns3
38{
39
41
42/** Unnamed namespace */
43namespace
44{
45
46/** Scaling coefficients, exponents, and look up table for unit. */
47/** @{ */
48/** Scaling exponent, relative to smallest unit. */
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};
51/** Scaling coefficient, relative to smallest unit. */
52const int32_t UNIT_COEFF[Time::LAST] = {315360, 864, 36, 6, 1, 1, 1, 1, 1, 1};
53
54/**
55 * Scale a unit to the smallest unit.
56 * \param u The unit to scale
57 * \returns The value of \pname{u} in terms of the smallest defined unit.
58 */
59long double
61{
62 return UNIT_COEFF[u] * std::pow(10L, UNIT_POWER[u]);
63}
64
65/**
66 * Initializer for \c UNIT_VALUE
67 * \returns The array of scale factors between units.
68 */
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
80/** Value of each unit, in terms of the smallest defined unit. */
81const long double* UNIT_VALUE = InitUnitValue();
82
83/** @} */
84
85} // unnamed namespace
86
87// The set of marked times
88// static
90
91/// The static mutex for critical sections around modification of Time::g_markingTimes.
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 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
295void
297{
298 /**
299 * \internal
300 *
301 * We're called by Simulator::Run, which knows nothing about the mutex,
302 * so we need a critical section here.
303 *
304 * It would seem natural to use this function at the end of
305 * ConvertTimes, but that function already has the mutex.
306 * The mutex can not be locked more than once in the same thread,
307 * so calling this function from ConvertTimes is a bad idea.
308 *
309 * Instead, we copy this body into ConvertTimes.
310 */
311
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 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
347void
348Time::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
375void
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() ||
390 tp->m_data == std::numeric_limits<int64_t>::max()))
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
415Time::As(const Unit unit /* = Time::AUTO */) const
416{
417 return TimeWithUnit(*this, unit);
418}
419
420std::ostream&
421operator<<(std::ostream& os, const Time& time)
422{
423 os << time.As(Time::GetResolution());
424 return os;
425}
426
427std::ostream&
428operator<<(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
521std::istream&
522operator>>(std::istream& is, Time& time)
523{
524 std::string value;
525 is >> value;
526 time = Time(value);
527 return is;
528}
529
531
533MakeTimeChecker(const Time min, const Time max)
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
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 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 Resolution * PeekResolution()
Get the current Resolution.
Definition: nstime.h:655
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
AttributeValue implementation for Time.
Definition: nstime.h:1413
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.
Definition: int64x64-128.h:56
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:1434
#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:447
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:159
std::istream & operator>>(std::istream &is, Angles &a)
Definition: angles.cc:183
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Definition: ptr.h:615
@ 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: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