A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
show-progress.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017 Lawrence Livermore National Laboratory
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Gustavo Carneiro <gjc@inescporto.pt>
7 * Author: Peter D. Barnes, Jr. <pdbarnes@llnl.gov>
8 */
9
10/**
11 * \file
12 * \ingroup core
13 * ns3::ShowProgress implementation.
14 */
15
16#include "show-progress.h"
17
18#include "event-id.h"
19#include "log.h"
20#include "nstime.h"
21#include "simulator.h"
22
23#include <iomanip>
24
25namespace ns3
26{
27
28NS_LOG_COMPONENT_DEFINE("ShowProgress");
29
30/* static */
31const int64x64_t ShowProgress::HYSTERESIS = 1.414;
32/* static */
33const int64x64_t ShowProgress::MAXGAIN = 2.0;
34
35ShowProgress::ShowProgress(const Time interval /* = Seconds (1.0) */,
36 std::ostream& os /* = std::cout */)
37 : m_timer(),
38 m_stamp(),
39 m_elapsed(),
40 m_interval(interval),
41 m_vtime(Time(1)),
42 m_event(),
43 m_eventCount(0),
44 m_printer(DefaultTimePrinter),
45 m_os(&os),
46 m_verbose(false),
47 m_repCount(0)
48{
49 NS_LOG_FUNCTION(this << interval);
51 Start();
52}
53
58
59void
61{
62 NS_LOG_FUNCTION(this << interval);
63 const int64x64_t ratio = interval / m_interval;
64 m_interval = interval;
65 // If we aren't at the initial value assume we have a reasonable
66 // update time m_vtime, so we should rescale it
67 if (m_vtime > Time(1))
68 {
69 m_vtime = m_vtime * ratio;
70 }
72 Start();
73
74} // ShowProgress::SetInterval
75
76void
82
83void
89
90void
91ShowProgress::SetStream(std::ostream& os)
92{
93 m_os = &os;
94}
95
96void
98{
99 NS_LOG_FUNCTION(this);
101 m_timer.Start();
102
103} // ShowProgress::ScheduleCheckProgress
104
105void
106ShowProgress::GiveFeedback(uint64_t nEvents, int64x64_t ratio, int64x64_t speed)
107{
108 // Save stream state
109 auto precision = m_os->precision();
110 auto flags = m_os->flags();
111
112 m_os->setf(std::ios::fixed, std::ios::floatfield);
113
114 if (m_verbose)
115 {
116 (*m_os) << std::right << std::setw(5) << m_repCount << std::left
117 << (ratio > (1.0 / HYSTERESIS) ? "-->" : " ") << std::setprecision(9)
118 << " [del: " << m_elapsed.As(Time::S) << "/ int: " << m_interval.As(Time::S)
119 << " = rat: " << ratio
120 << (ratio > HYSTERESIS ? " dn" : (ratio < 1.0 / HYSTERESIS ? " up" : " --"))
121 << ", vt: " << m_vtime.As(Time::S) << "] ";
122 }
123
124 // Print the current time
125 (*m_printer)(*m_os);
126
127 (*m_os) << " (" << std::setprecision(3) << std::setw(8) << speed.GetDouble() << "x real time) "
128 << nEvents << " events processed" << std::endl
129 << std::flush;
130
131 // Restore stream state
132 m_os->precision(precision);
133 m_os->flags(flags);
134
135} // ShowProgress::GiveFeedback
136
137void
139{
140 // Get elapsed wall clock time
142 NS_LOG_FUNCTION(this << m_elapsed);
143
144 // Don't do anything unless the elapsed time is positive.
145 if (m_elapsed <= Time(0))
146 {
148 ++m_repCount;
150 return;
151 }
152
153 // Speed: how fast are we compared to real time
154 const int64x64_t speed = m_vtime / m_elapsed;
155
156 // Ratio: how much real time did we use,
157 // compared to reporting interval target
158 const int64x64_t ratio = m_elapsed / m_interval;
159
160 // Elapsed event count
161 uint64_t events = Simulator::GetEventCount();
162 uint64_t nEvents = events - m_eventCount;
163 /**
164 * \internal Update algorithm
165 *
166 * We steer \c m_vtime to obtain updates approximately every
167 * \c m_interval in wall clock time. To smooth things out a little
168 * we impose a hysteresis band around \c m_interval where we
169 * don't change \c m_vtime. To avoid too rapid movements
170 * chasing spikes or dips in execution rate, we bound the
171 * change in \c m_vtime to a maximum factor.
172 *
173 * In mathematical terms, we compute the ratio of elapsed wall clock time
174 * compared to the target reporting interval:
175 * \f[ ratio = \frac{elapsed}{target interval)} \f]
176 *
177 * Graphically, the windows in ratio value and the corresponding
178 * updates to \c m_vtime are sketched in this figure:
179 * \verbatim
180 ^
181 |
182 ratio | vtime update
183 |
184 |
185 | /= MAXGAIN
186 |
187 MAXGAIN -|-------------- /= min (ratio, MAXGAIN)
188 |
189 | /= ratio
190 |
191 HYSTERESIS -|=============================================
192 |
193 |
194 |
195 1 -| No change
196 |
197 |
198 |
199 1/ HYSTERESIS -|==============================================
200 |
201 | *= 1 / ratio
202 |
203 1/ MAXGAIN -|--------------- *= min (1 / ratio, MAXGAIN)
204 |
205 | *= MAXGAIN
206 |
207 \endverbatim
208 *
209 * As indicated, when ratio is outside the hysteresis band
210 * it amounts to multiplying \c m_vtime by the min/max of the ratio
211 * with the appropriate MAXGAIN factor.
212 *
213 * Finally, some experimentation suggests we further dampen
214 * movement between HYSTERESIS and MAXGAIN, so we only apply
215 * half the ratio. This reduces "hunting" for a stable update
216 * period.
217 *
218 * \todo Evaluate if simple exponential averaging would be
219 * more effective, simpler.
220 */
221 if (ratio > HYSTERESIS)
222 {
223 int64x64_t f = 1 + (ratio - 1) / 2;
224 if (ratio > MAXGAIN)
225 {
226 f = MAXGAIN;
227 }
228
229 m_vtime = m_vtime / f;
230 }
231 else if (ratio < 1.0 / HYSTERESIS)
232 {
233 int64x64_t f = 1 + (1 / ratio - 1) / 2;
234 if (1 / ratio > MAXGAIN)
235 {
236 f = MAXGAIN;
237 }
238 m_vtime = m_vtime * f;
239 }
240
241 // Only give feedback if ratio is at least as big as 1/HYSTERESIS
242 if (ratio > (1.0 / HYSTERESIS))
243 {
244 GiveFeedback(nEvents, ratio, speed);
245 m_elapsed = Time(0);
246 m_eventCount = events;
247 }
248 else
249 {
250 NS_LOG_LOGIC("skipping update: " << ratio);
251 // enable this line for debugging, with --verbose
252 // GiveFeedback (nEvents, ratio, speed);
253 }
254 ++m_repCount;
255
256 // And do it again
258
259} // ShowProgress::CheckProgress
260
261void
263{
264 m_stamp.Stamp();
265 (*m_os) << "Start wall clock: " << m_stamp.ToString() << std::endl;
266} // ShowProgress::Start
267
268void
270{
271 m_stamp.Stamp();
272 (*m_os) << "End wall clock: " << m_stamp.ToString()
273 << "\nElapsed wall clock: " << m_stamp.GetInterval() << "s" << std::endl;
274} // ShowProgress::Stop
275
276} // namespace ns3
bool m_verbose
Verbose mode flag.
void SetVerbose(bool verbose)
Set verbose mode to print real and virtual time intervals.
std::ostream * m_os
The output stream to use.
void Start()
Start the elapsed wallclock timestamp and print the start time.
void SetTimePrinter(TimePrinter lp)
Set the TimePrinter function to be used to prepend progress messages with the simulation time.
void Stop()
Stop the elapsed wallclock timestamp and print the total elapsed time.
ShowProgress(const Time interval=Seconds(1.0), std::ostream &os=std::cout)
Constructor.
Time m_interval
The target update interval, in wallclock time.
uint64_t m_repCount
Number of CheckProgress events.
~ShowProgress()
Destructor.
void GiveFeedback(uint64_t nEvents, int64x64_t ratio, int64x64_t speed)
Show execution progress.
void SetStream(std::ostream &os)
Set the output stream to show progress on.
static const int64x64_t MAXGAIN
Maximum growth factor.
SystemWallClockTimestamp m_stamp
Elapsed wallclock time.
Time m_elapsed
Total elapsed wallclock time since last update.
Time m_vtime
The virtual time interval.
void ScheduleCheckProgress()
Schedule the next CheckProgress.
EventId m_event
The next progress event.
void CheckProgress()
Check on execution progress.
TimePrinter m_printer
The TimePrinter to use.
SystemWallClockMs m_timer
Wallclock timer.
void SetInterval(const Time interval)
Set the target update interval, in wallclock time.
static const int64x64_t HYSTERESIS
Hysteresis factor.
uint64_t m_eventCount
Simulator event count.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Cancel(const EventId &id)
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
Definition simulator.cc:274
static uint64_t GetEventCount()
Get the number of events executed.
Definition simulator.cc:313
int64_t End()
Stop measuring the time since Start() was called.
void Start()
Start a measure.
std::time_t GetInterval() const
Get the last recorded interval.
std::string ToString() const
Get the last time stamp as a string.
void Stamp()
Record the current wall-clock time and delta since the last stamp().
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
@ S
second
Definition nstime.h:105
High precision numerical type, implementing Q64.64 fixed precision.
double GetDouble() const
Get this value as a double.
ns3::EventId declarations.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void(* TimePrinter)(std::ostream &os)
Function signature for features requiring a time formatter, such as logging or ShowProgress.
void DefaultTimePrinter(std::ostream &os)
Default Time printer.
Declaration of classes ns3::Time and ns3::TimeWithUnit, and the TimeValue implementation classes.
bool verbose
ns3::ShowProgress declaration.
ns3::Simulator declaration.