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 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Gustavo Carneiro <gjc@inescporto.pt>
18 * Author: Peter D. Barnes, Jr. <pdbarnes@llnl.gov>
19 */
20
21/**
22 * \file
23 * \ingroup core
24 * ns3::ShowProgress implementation.
25 */
26
27#include "show-progress.h"
28
29#include "event-id.h"
30#include "log.h"
31#include "nstime.h"
32#include "simulator.h"
33
34#include <iomanip>
35
36namespace ns3
37{
38
39NS_LOG_COMPONENT_DEFINE("ShowProgress");
40
41/* static */
42const int64x64_t ShowProgress::HYSTERESIS = 1.414;
43/* static */
44const int64x64_t ShowProgress::MAXGAIN = 2.0;
45
46ShowProgress::ShowProgress(const Time interval /* = Seconds (1.0) */,
47 std::ostream& os /* = std::cout */)
48 : m_timer(),
49 m_stamp(),
50 m_elapsed(),
51 m_interval(interval),
52 m_vtime(Time(1)),
53 m_event(),
54 m_eventCount(0),
55 m_printer(DefaultTimePrinter),
56 m_os(&os),
57 m_verbose(false),
58 m_repCount(0)
59{
60 NS_LOG_FUNCTION(this << interval);
62 Start();
63}
64
66{
67 Stop();
68}
69
70void
72{
73 NS_LOG_FUNCTION(this << interval);
74 const int64x64_t ratio = interval / m_interval;
75 m_interval = interval;
76 // If we aren't at the initial value assume we have a reasonable
77 // update time m_vtime, so we should rescale it
78 if (m_vtime > Time(1))
79 {
80 m_vtime = m_vtime * ratio;
81 }
83 Start();
84
85} // ShowProgress::SetInterval
86
87void
89{
90 NS_LOG_FUNCTION(this << lp);
91 m_printer = lp;
92}
93
94void
96{
97 NS_LOG_FUNCTION(this << verbose);
99}
100
101void
102ShowProgress::SetStream(std::ostream& os)
103{
104 m_os = &os;
105}
106
107void
109{
110 NS_LOG_FUNCTION(this);
112 m_timer.Start();
113
114} // ShowProgress::ScheduleCheckProgress
115
116void
117ShowProgress::GiveFeedback(uint64_t nEvents, int64x64_t ratio, int64x64_t speed)
118{
119 // Save stream state
120 auto precision = m_os->precision();
121 auto flags = m_os->flags();
122
123 m_os->setf(std::ios::fixed, std::ios::floatfield);
124
125 if (m_verbose)
126 {
127 (*m_os) << std::right << std::setw(5) << m_repCount << std::left
128 << (ratio > (1.0 / HYSTERESIS) ? "-->" : " ") << std::setprecision(9)
129 << " [del: " << m_elapsed.As(Time::S) << "/ int: " << m_interval.As(Time::S)
130 << " = rat: " << ratio
131 << (ratio > HYSTERESIS ? " dn" : (ratio < 1.0 / HYSTERESIS ? " up" : " --"))
132 << ", vt: " << m_vtime.As(Time::S) << "] ";
133 }
134
135 // Print the current time
136 (*m_printer)(*m_os);
137
138 (*m_os) << " (" << std::setprecision(3) << std::setw(8) << speed.GetDouble() << "x real time) "
139 << nEvents << " events processed" << std::endl
140 << std::flush;
141
142 // Restore stream state
143 m_os->precision(precision);
144 m_os->flags(flags);
145
146} // ShowProgress::GiveFeedback
147
148void
150{
151 // Get elapsed wall clock time
153 NS_LOG_FUNCTION(this << m_elapsed);
154
155 // Don't do anything unless the elapsed time is positive.
156 if (m_elapsed <= Time(0))
157 {
159 ++m_repCount;
161 return;
162 }
163
164 // Speed: how fast are we compared to real time
165 const int64x64_t speed = m_vtime / m_elapsed;
166
167 // Ratio: how much real time did we use,
168 // compared to reporting interval target
169 const int64x64_t ratio = m_elapsed / m_interval;
170
171 // Elapsed event count
172 uint64_t events = Simulator::GetEventCount();
173 uint64_t nEvents = events - m_eventCount;
174 /**
175 * \internal Update algorithm
176 *
177 * We steer \c m_vtime to obtain updates approximately every
178 * \c m_interval in wall clock time. To smooth things out a little
179 * we impose a hysteresis band around \c m_interval where we
180 * don't change \c m_vtime. To avoid too rapid movements
181 * chasing spikes or dips in execution rate, we bound the
182 * change in \c m_vtime to a maximum factor.
183 *
184 * In mathematical terms, we compute the ratio of elapsed wall clock time
185 * compared to the target reporting interval:
186 * \f[ ratio = \frac{elapsed}{target interval)} \f]
187 *
188 * Graphically, the windows in ratio value and the corresponding
189 * updates to \c m_vtime are sketched in this figure:
190 * \verbatim
191 ^
192 |
193 ratio | vtime update
194 |
195 |
196 | /= MAXGAIN
197 |
198 MAXGAIN -|-------------- /= min (ratio, MAXGAIN)
199 |
200 | /= ratio
201 |
202 HYSTERESIS -|=============================================
203 |
204 |
205 |
206 1 -| No change
207 |
208 |
209 |
210 1/ HYSTERESIS -|==============================================
211 |
212 | *= 1 / ratio
213 |
214 1/ MAXGAIN -|--------------- *= min (1 / ratio, MAXGAIN)
215 |
216 | *= MAXGAIN
217 |
218 \endverbatim
219 *
220 * As indicated, when ratio is outside the hysteresis band
221 * it amounts to multiplying \c m_vtime by the min/max of the ratio
222 * with the appropriate MAXGAIN factor.
223 *
224 * Finally, some experimentation suggests we further dampen
225 * movement between HYSTERESIS and MAXGAIN, so we only apply
226 * half the ratio. This reduces "hunting" for a stable update
227 * period.
228 *
229 * \todo Evaluate if simple exponential averaging would be
230 * more effective, simpler.
231 */
232 if (ratio > HYSTERESIS)
233 {
234 int64x64_t f = 1 + (ratio - 1) / 2;
235 if (ratio > MAXGAIN)
236 {
237 f = MAXGAIN;
238 }
239
240 m_vtime = m_vtime / f;
241 }
242 else if (ratio < 1.0 / HYSTERESIS)
243 {
244 int64x64_t f = 1 + (1 / ratio - 1) / 2;
245 if (1 / ratio > MAXGAIN)
246 {
247 f = MAXGAIN;
248 }
249 m_vtime = m_vtime * f;
250 }
251
252 // Only give feedback if ratio is at least as big as 1/HYSTERESIS
253 if (ratio > (1.0 / HYSTERESIS))
254 {
255 GiveFeedback(nEvents, ratio, speed);
256 m_elapsed = Time(0);
257 m_eventCount = events;
258 }
259 else
260 {
261 NS_LOG_LOGIC("skipping update: " << ratio);
262 // enable this line for debugging, with --verbose
263 // GiveFeedback (nEvents, ratio, speed);
264 }
265 ++m_repCount;
266
267 // And do it again
269
270} // ShowProgress::CheckProgress
271
272void
274{
275 m_stamp.Stamp();
276 (*m_os) << "Start wall clock: " << m_stamp.ToString() << std::endl;
277} // ShowProgress::Start
278
279void
281{
282 m_stamp.Stamp();
283 (*m_os) << "End wall clock: " << m_stamp.ToString()
284 << "\nElapsed wall clock: " << m_stamp.GetInterval() << "s" << std::endl;
285} // ShowProgress::Stop
286
287} // 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:571
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:285
static uint64_t GetEventCount()
Get the number of events executed.
Definition: simulator.cc:324
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:105
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
@ S
second
Definition: nstime.h:116
High precision numerical type, implementing Q64.64 fixed precision.
Definition: int64x64-128.h:56
double GetDouble() const
Get this value as a double.
Definition: int64x64-128.h:240
ns3::EventId declarations.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#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:1331
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.
Definition: time-printer.h:43
void DefaultTimePrinter(std::ostream &os)
Default Time printer.
Definition: time-printer.cc:40
Declaration of classes ns3::Time and ns3::TimeWithUnit, and the TimeValue implementation classes.
bool verbose
ns3::ShowProgress declaration.
ns3::Simulator declaration.