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
75void
81
82void
88
89void
90ShowProgress::SetStream(std::ostream& os)
91{
92 m_os = &os;
93}
94
95void
102
103void
104ShowProgress::GiveFeedback(uint64_t nEvents, int64x64_t ratio, int64x64_t speed)
105{
106 // Save stream state
107 auto precision = m_os->precision();
108 auto flags = m_os->flags();
109
110 m_os->setf(std::ios::fixed, std::ios::floatfield);
111
112 if (m_verbose)
113 {
114 (*m_os) << std::right << std::setw(5) << m_repCount << std::left
115 << (ratio > (1.0 / HYSTERESIS) ? "-->" : " ") << std::setprecision(9)
116 << " [del: " << m_elapsed.As(Time::S) << "/ int: " << m_interval.As(Time::S)
117 << " = rat: " << ratio
118 << (ratio > HYSTERESIS ? " dn" : (ratio < 1.0 / HYSTERESIS ? " up" : " --"))
119 << ", vt: " << m_vtime.As(Time::S) << "] ";
120 }
121
122 // Print the current time
123 (*m_printer)(*m_os);
124
125 (*m_os) << " (" << std::setprecision(3) << std::setw(8) << speed.GetDouble() << "x real time) "
126 << nEvents << " events processed" << std::endl
127 << std::flush;
128
129 // Restore stream state
130 m_os->precision(precision);
131 m_os->flags(flags);
132}
133
134void
136{
137 // Get elapsed wall clock time
139 NS_LOG_FUNCTION(this << m_elapsed);
140
141 // Don't do anything unless the elapsed time is positive.
142 if (m_elapsed.IsNegative())
143 {
145 ++m_repCount;
147 return;
148 }
149
150 // Speed: how fast are we compared to real time
151 const int64x64_t speed = m_vtime / m_elapsed;
152
153 // Ratio: how much real time did we use,
154 // compared to reporting interval target
155 const int64x64_t ratio = m_elapsed / m_interval;
156
157 // Elapsed event count
158 uint64_t events = Simulator::GetEventCount();
159 uint64_t nEvents = events - m_eventCount;
160 /**
161 * @internal Update algorithm
162 *
163 * We steer \c m_vtime to obtain updates approximately every
164 * \c m_interval in wall clock time. To smooth things out a little
165 * we impose a hysteresis band around \c m_interval where we
166 * don't change \c m_vtime. To avoid too rapid movements
167 * chasing spikes or dips in execution rate, we bound the
168 * change in \c m_vtime to a maximum factor.
169 *
170 * In mathematical terms, we compute the ratio of elapsed wall clock time
171 * compared to the target reporting interval:
172 * \f[ ratio = \frac{elapsed}{target interval)} \f]
173 *
174 * Graphically, the windows in ratio value and the corresponding
175 * updates to \c m_vtime are sketched in this figure:
176 * @verbatim
177 ^
178 |
179 ratio | vtime update
180 |
181 |
182 | /= MAXGAIN
183 |
184 MAXGAIN -|-------------- /= min (ratio, MAXGAIN)
185 |
186 | /= ratio
187 |
188 HYSTERESIS -|=============================================
189 |
190 |
191 |
192 1 -| No change
193 |
194 |
195 |
196 1/ HYSTERESIS -|==============================================
197 |
198 | *= 1 / ratio
199 |
200 1/ MAXGAIN -|--------------- *= min (1 / ratio, MAXGAIN)
201 |
202 | *= MAXGAIN
203 |
204 \endverbatim
205 *
206 * As indicated, when ratio is outside the hysteresis band
207 * it amounts to multiplying \c m_vtime by the min/max of the ratio
208 * with the appropriate MAXGAIN factor.
209 *
210 * Finally, some experimentation suggests we further dampen
211 * movement between HYSTERESIS and MAXGAIN, so we only apply
212 * half the ratio. This reduces "hunting" for a stable update
213 * period.
214 *
215 * @todo Evaluate if simple exponential averaging would be
216 * more effective, simpler.
217 */
218 if (ratio > HYSTERESIS)
219 {
220 int64x64_t f = 1 + (ratio - 1) / 2;
221 if (ratio > MAXGAIN)
222 {
223 f = MAXGAIN;
224 }
225
226 m_vtime = m_vtime / f;
227 }
228 else if (ratio < 1.0 / HYSTERESIS)
229 {
230 int64x64_t f = 1 + (1 / ratio - 1) / 2;
231 if (1 / ratio > MAXGAIN)
232 {
233 f = MAXGAIN;
234 }
235 m_vtime = m_vtime * f;
236 }
237
238 // Only give feedback if ratio is at least as big as 1/HYSTERESIS
239 if (ratio > (1.0 / HYSTERESIS))
240 {
241 GiveFeedback(nEvents, ratio, speed);
242 m_elapsed = Time(0);
243 m_eventCount = events;
244 }
245 else
246 {
247 NS_LOG_LOGIC("skipping update: " << ratio);
248 // enable this line for debugging, with --verbose
249 // GiveFeedback (nEvents, ratio, speed);
250 }
251 ++m_repCount;
252
253 // And do it again
255}
256
257void
259{
260 m_stamp.Stamp();
261 (*m_os) << "Start wall clock: " << m_stamp.ToString() << std::endl;
262}
263
264void
266{
267 m_stamp.Stamp();
268 (*m_os) << "End wall clock: " << m_stamp.ToString()
269 << "\nElapsed wall clock: " << m_stamp.GetInterval() << "s" << std::endl;
270}
271
272} // 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.
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.
ShowProgress(const Time interval=Seconds(1), std::ostream &os=std::cout)
Constructor.
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:561
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:403
bool IsNegative() const
Exactly equivalent to t <= 0.
Definition nstime.h:313
@ 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:1357
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.