A Discrete-Event Network Simulator
API
bench-scheduler.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2006 INRIA
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 */
20
21#include <iomanip>
22#include <iostream>
23#include <fstream>
24#include <vector>
25#include <string.h>
26
27#include "ns3/core-module.h"
28
29using namespace ns3;
30
32bool g_debug = false;
33
35std::string g_me;
37#define LOG(x) std::cout << x << std::endl
39#define LOGME(x) LOG (g_me << x)
41#define DEB(x) if (g_debug) { LOGME (x); }
42
44int g_fwidth = 6;
45
54class Bench
55{
56public:
62 Bench (const uint32_t population, const uint32_t total)
63 : m_population (population),
64 m_total (total),
65 m_count (0)
66 {
67 }
68
76 {
77 m_rand = stream;
78 }
79
85 void SetPopulation (const uint32_t population)
86 {
87 m_population = population;
88 }
89
94 void SetTotal (const uint32_t total)
95 {
96 m_total = total;
97 }
98
100 void RunBench (void);
101
102private:
107 void Cb (void);
108
113};
114
115void
117{
119 double init, simu;
120
121 DEB ("initializing");
122 m_count = 0;
123
124
125 time.Start ();
126 for (uint32_t i = 0; i < m_population; ++i)
127 {
128 Time at = NanoSeconds (m_rand->GetValue ());
129 Simulator::Schedule (at, &Bench::Cb, this);
130 }
131 init = time.End ();
132 init /= 1000;
133 DEB ("initialization took " << init << "s");
134
135 DEB ("running");
136 time.Start ();
138 simu = time.End ();
139 simu /= 1000;
140 DEB ("run took " << simu << "s");
141
142 LOG (std::setw (g_fwidth) << init <<
143 std::setw (g_fwidth) << (m_population / init) <<
144 std::setw (g_fwidth) << (init / m_population) <<
145 std::setw (g_fwidth) << simu <<
146 std::setw (g_fwidth) << (m_count / simu)
147 << (simu / m_count)
148 );
149
150}
151
152void
154{
155 if (m_count >= m_total)
156 {
157 Simulator::Stop ();
158 return;
159 }
160 DEB ("event at " << Simulator::Now ().GetSeconds () << "s");
161
162 Time after = NanoSeconds (m_rand->GetValue ());
163 Simulator::Schedule (after, &Bench::Cb, this);
164 ++m_count;
165}
166
167
180GetRandomStream (std::string filename)
181{
182 Ptr<RandomVariableStream> stream = 0;
183
184 if (filename == "")
185 {
186 LOG (" Event time distribution: default exponential");
187 Ptr<ExponentialRandomVariable> erv = CreateObject<ExponentialRandomVariable> ();
188 erv->SetAttribute ("Mean", DoubleValue (100));
189 stream = erv;
190 }
191 else
192 {
193 std::istream *input;
194
195 if (filename == "-")
196 {
197 LOG (" Event time distribution: from stdin");
198 input = &std::cin;
199 }
200 else
201 {
202 LOG (" Event time distribution: from " << filename);
203 input = new std::ifstream (filename.c_str ());
204 }
205
206 double value;
207 std::vector<double> nsValues;
208
209 while (!input->eof ())
210 {
211 if (*input >> value)
212 {
213 uint64_t ns = (uint64_t) (value * 1000000000);
214 nsValues.push_back (ns);
215 }
216 else
217 {
218 input->clear ();
219 std::string line;
220 *input >> line;
221 }
222 }
223 LOG (" Found " << nsValues.size () << " entries");
224 auto drv = CreateObject<DeterministicRandomVariable> ();
225 drv->SetValueArray (&nsValues[0], nsValues.size ());
226 stream = drv;
227 }
228
229 return stream;
230}
231
247void
248Run (ObjectFactory & factory, uint32_t pop, uint32_t total, uint32_t runs,
249 Ptr<RandomVariableStream> eventStream, bool calRev)
250{
251 Simulator::SetScheduler (factory);
252
253 std::string schedType = factory.GetTypeId ().GetName ();
254 if (schedType == "ns3::CalendarScheduler")
255 {
256 schedType += ": insertion order: "
257 + std::string (calRev ? "reverse" : "normal");
258 }
259
260 DEB ("scheduler: " << schedType);
261 DEB ("population: " << pop);
262 DEB ("total events: " << total);
263 DEB ("runs: " << runs);
264
265 Bench *bench = new Bench (pop, total);
266 bench->SetRandomStream (eventStream);
267
268 // table header
269 LOG ("");
270 LOG (schedType);
271 LOG (std::left << std::setw (g_fwidth) << "Run #" <<
272 std::left << std::setw (3 * g_fwidth) << "Initialization:" <<
273 std::left << "Simulation:"
274 );
275 LOG (std::left << std::setw (g_fwidth) << "" <<
276 std::left << std::setw (g_fwidth) << "Time (s)" <<
277 std::left << std::setw (g_fwidth) << "Rate (ev/s)" <<
278 std::left << std::setw (g_fwidth) << "Per (s/ev)" <<
279 std::left << std::setw (g_fwidth) << "Time (s)" <<
280 std::left << std::setw (g_fwidth) << "Rate (ev/s)" <<
281 std::left << "Per (s/ev)"
282 );
283 LOG (std::setfill ('-') <<
284 std::right << std::setw (g_fwidth) << " " <<
285 std::right << std::setw (g_fwidth) << " " <<
286 std::right << std::setw (g_fwidth) << " " <<
287 std::right << std::setw (g_fwidth) << " " <<
288 std::right << std::setw (g_fwidth) << " " <<
289 std::right << std::setw (g_fwidth) << " " <<
290 std::right << std::setw (g_fwidth) << " " <<
291 std::setfill (' ')
292 );
293
294 // prime
295 DEB ("priming");
296 std::cout << std::left << std::setw (g_fwidth) << "(prime)";
297 bench->RunBench ();
298
299 bench->SetPopulation (pop);
300 bench->SetTotal (total);
301 for (uint32_t i = 0; i < runs; i++)
302 {
303 std::cout << std::setw (g_fwidth) << i;
304
305 bench->RunBench ();
306 }
307
308 LOG ("");
309 Simulator::Destroy ();
310 delete bench;
311}
312
313
314int main (int argc, char *argv[])
315{
316
317 bool allSched = false;
318 bool schedCal = false;
319 bool schedHeap = false;
320 bool schedList = false;
321 bool schedMap = false; // default scheduler
322 bool schedPQ = false;
323
324 uint32_t pop = 100000;
325 uint32_t total = 1000000;
326 uint32_t runs = 1;
327 std::string filename = "";
328 bool calRev = false;
329
330 CommandLine cmd (__FILE__);
331 cmd.Usage ("Benchmark the simulator scheduler.\n"
332 "\n"
333 "Event intervals are taken from one of:\n"
334 " an exponential distribution, with mean 100 ns,\n"
335 " an ascii file, given by the --file=\"<filename>\" argument,\n"
336 " or standard input, by the argument --file=\"-\"\n"
337 "In the case of either --file form, the input is expected\n"
338 "to be ascii, giving the relative event times in ns.");
339 cmd.AddValue ("all", "use all schedulers", allSched);
340 cmd.AddValue ("cal", "use CalendarSheduler", schedCal);
341 cmd.AddValue ("calrev", "reverse ordering in the CalendarScheduler", calRev);
342 cmd.AddValue ("heap", "use HeapScheduler", schedHeap);
343 cmd.AddValue ("list", "use ListSheduler", schedList);
344 cmd.AddValue ("map", "use MapScheduler (default)", schedMap);
345 cmd.AddValue ("pri", "use PriorityQueue", schedPQ);
346 cmd.AddValue ("debug", "enable debugging output", g_debug);
347 cmd.AddValue ("pop", "event population size (default 1E5)", pop);
348 cmd.AddValue ("total", "total number of events to run (default 1E6)", total);
349 cmd.AddValue ("runs", "number of runs (default 1)", runs);
350 cmd.AddValue ("file", "file of relative event times", filename);
351 cmd.AddValue ("prec", "printed output precision", g_fwidth);
352 cmd.Parse (argc, argv);
353
354 g_me = cmd.GetName () + ": ";
355 g_fwidth += 6; // 5 extra chars in '2.000002e+07 ': . e+0 _
356
357 LOG (std::setprecision (g_fwidth - 6)); // prints blank line
358 LOGME (" Benchmark the simulator scheduler");
359 LOG (" Event population size: " << pop);
360 LOG (" Total events per run: " << total);
361 LOG (" Number of runs per scheduler: " << runs);
362 DEB ("debugging is ON");
363
364 if (allSched)
365 {
366 schedCal = schedHeap = schedList = schedMap = schedPQ = true;
367 }
368 // Set the default case if nothing else is set
369 if (! (schedCal || schedHeap || schedList || schedMap || schedPQ))
370 {
371 schedMap = true;
372 }
373
374 Ptr<RandomVariableStream> eventStream = GetRandomStream (filename);
375
376
377 ObjectFactory factory ("ns3::MapScheduler");
378 if (schedCal)
379 {
380 factory.SetTypeId ("ns3::CalendarScheduler");
381 factory.Set ("Reverse", BooleanValue (calRev));
382 Run (factory, pop, total, runs, eventStream, calRev);
383 if (allSched)
384 {
385 factory.Set ("Reverse", BooleanValue (!calRev));
386 Run (factory, pop, total, runs, eventStream, !calRev);
387 }
388 }
389 if (schedHeap)
390 {
391 factory.SetTypeId ("ns3::HeapScheduler");
392 Run (factory, pop, total, runs, eventStream, calRev);
393 }
394 if (schedList)
395 {
396 factory.SetTypeId ("ns3::ListScheduler");
397 Run (factory, pop, total, runs, eventStream, calRev);
398 }
399 if (schedMap)
400 {
401 factory.SetTypeId ("ns3::MapScheduler");
402 Run (factory, pop, total, runs, eventStream, calRev);
403 }
404 if (schedPQ)
405 {
406 factory.SetTypeId ("ns3::PriorityQueueScheduler");
407 Run (factory, pop, total, runs, eventStream, calRev);
408 }
409
410 return 0;
411}
Ptr< RandomVariableStream > GetRandomStream(std::string filename)
Create a RandomVariableStream to generate next event delays.
bool g_debug
Flag to write debugging output.
#define LOGME(x)
Log with program name prefix.
int g_fwidth
Output field width for numeric data.
std::string g_me
Name of this program.
void Run(ObjectFactory &factory, uint32_t pop, uint32_t total, uint32_t runs, Ptr< RandomVariableStream > eventStream, bool calRev)
Perform the runs for a single scheduler type.
#define LOG(x)
Log to std::cout.
#define DEB(x)
Log debugging output.
Benchmark instance which can do a single run.
void SetRandomStream(Ptr< RandomVariableStream > stream)
Set the event delay interval random stream.
void RunBench(void)
Run the benchmark as configure.
uint32_t m_count
Count of events executed so far.
void Cb(void)
Event function.
void SetTotal(const uint32_t total)
Set the total number of events to execute.
Ptr< RandomVariableStream > m_rand
Stream for event delays.
Bench(const uint32_t population, const uint32_t total)
Constructor.
uint32_t m_total
Total number of events to execute.
uint32_t m_population
Event population size.
void SetPopulation(const uint32_t population)
Set the number of events to populate the scheduler with.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Parse command-line arguments.
Definition: command-line.h:229
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:41
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:256
Instantiate subclasses of ns3::Object.
TypeId GetTypeId(void) const
Get the TypeId which will be created by this ObjectFactory.
virtual double GetValue(void)=0
Get the next random value as a double drawn from the distribution.
Measure elapsed wall clock time in milliseconds.
void Start(void)
Start a measure.
int64_t End(void)
Stop measuring the time since Start() was called.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:104
std::string GetName(void) const
Get the name.
Definition: type-id.cc:976
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:287
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1269
Every class exported by the ns3 library is enclosed in the ns3 namespace.
cmd
Definition: second.py:43
ns3::StringValue attribute value declarations.