16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
17 * |
17 * |
18 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr> |
18 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr> |
19 */ |
19 */ |
20 |
20 |
21 #include "ns3/core-module.h" |
21 #include <iomanip> |
22 #include <iostream> |
22 #include <iostream> |
23 #include <fstream> |
23 #include <fstream> |
24 #include <vector> |
24 #include <vector> |
25 #include <string.h> |
25 #include <string.h> |
26 |
26 |
|
27 #include "ns3/core-module.h" |
|
28 |
27 using namespace ns3; |
29 using namespace ns3; |
28 |
30 |
29 |
31 |
30 bool g_debug = false; |
32 bool g_debug = false; |
31 |
33 |
|
34 std::string g_me; |
|
35 #define LOG(x) std::cout << x << std::endl |
|
36 #define LOGME(x) LOG (g_me << x) |
|
37 #define DEB(x) if (g_debug) { LOGME (x) ; } |
|
38 |
|
39 // Output field width |
|
40 int g_fwidth = 6; |
|
41 |
32 class Bench |
42 class Bench |
33 { |
43 { |
34 public: |
44 public: |
35 Bench (); |
45 Bench (const uint32_t population, const uint32_t total) |
36 void ReadDistribution (std::istream &istream); |
46 : m_population (population), |
37 void SetTotal (uint32_t total); |
47 m_total (total), |
|
48 m_count (0) |
|
49 { }; |
|
50 |
|
51 void SetRandomStream (Ptr<RandomVariableStream> stream) |
|
52 { |
|
53 m_rand = stream; |
|
54 } |
|
55 |
|
56 void SetPopulation (const uint32_t population) |
|
57 { |
|
58 m_population = population; |
|
59 } |
|
60 |
|
61 void SetTotal (const uint32_t total) |
|
62 { |
|
63 m_total = total; |
|
64 } |
|
65 |
38 void RunBench (void); |
66 void RunBench (void); |
39 private: |
67 private: |
40 void Cb (void); |
68 void Cb (void); |
41 std::vector<uint64_t> m_distribution; |
69 |
42 std::vector<uint64_t>::const_iterator m_current; |
70 Ptr<RandomVariableStream> m_rand; |
43 uint32_t m_n; |
71 uint32_t m_population; |
44 uint32_t m_total; |
72 uint32_t m_total; |
|
73 uint32_t m_count; |
45 }; |
74 }; |
46 |
|
47 Bench::Bench () |
|
48 : m_n (0), |
|
49 m_total (0) |
|
50 {} |
|
51 |
|
52 void |
|
53 Bench::SetTotal (uint32_t total) |
|
54 { |
|
55 m_total = total; |
|
56 } |
|
57 |
|
58 void |
|
59 Bench::ReadDistribution (std::istream &input) |
|
60 { |
|
61 double data; |
|
62 while (!input.eof ()) |
|
63 { |
|
64 if (input >> data) |
|
65 { |
|
66 uint64_t ns = (uint64_t) (data * 1000000000); |
|
67 m_distribution.push_back (ns); |
|
68 } |
|
69 else |
|
70 { |
|
71 input.clear (); |
|
72 std::string line; |
|
73 input >> line; |
|
74 } |
|
75 } |
|
76 } |
|
77 |
75 |
78 void |
76 void |
79 Bench::RunBench (void) |
77 Bench::RunBench (void) |
80 { |
78 { |
81 SystemWallClockMs time; |
79 SystemWallClockMs time; |
82 double init, simu; |
80 double init, simu; |
|
81 |
|
82 DEB ("initializing"); |
|
83 |
83 time.Start (); |
84 time.Start (); |
84 for (std::vector<uint64_t>::const_iterator i = m_distribution.begin (); |
85 for (uint32_t i = 0; i < m_population; ++i) |
85 i != m_distribution.end (); i++) |
86 { |
86 { |
87 Time at = NanoSeconds (m_rand->GetValue ()); |
87 Simulator::Schedule (NanoSeconds (*i), &Bench::Cb, this); |
88 Simulator::Schedule (at, &Bench::Cb, this); |
88 } |
89 } |
89 init = time.End (); |
90 init = time.End (); |
90 init /= 1000; |
91 init /= 1000; |
91 |
92 DEB ("initialization took " << init << "s"); |
92 m_current = m_distribution.begin (); |
93 |
93 |
94 DEB ("running"); |
94 time.Start (); |
95 time.Start (); |
95 Simulator::Run (); |
96 Simulator::Run (); |
96 simu = time.End (); |
97 simu = time.End (); |
97 simu /= 1000; |
98 simu /= 1000; |
98 |
99 DEB ("run took " << simu << "s"); |
99 std::cout << |
100 |
100 "init n=" << m_distribution.size () << ", time=" << init << "s" << std::endl << |
101 LOG (std::setw (g_fwidth) << init << |
101 "simu n=" << m_n << ", time=" <<simu << "s" << std::endl << |
102 std::setw (g_fwidth) << (m_population / init) << |
102 "init " << ((double)m_distribution.size ()) / init << " insert/s, avg insert=" << |
103 std::setw (g_fwidth) << (init / m_population) << |
103 init / ((double)m_distribution.size ())<< "s" << std::endl << |
104 std::setw (g_fwidth) << simu << |
104 "simu " << ((double)m_n) / simu<< " hold/s, avg hold=" << |
105 std::setw (g_fwidth) << (m_count / simu) << |
105 simu / ((double)m_n) << "s" << std::endl |
106 std::setw (g_fwidth) << (simu / m_count)); |
106 ; |
107 |
|
108 // Clean up scheduler |
|
109 Simulator::Destroy (); |
107 } |
110 } |
108 |
111 |
109 void |
112 void |
110 Bench::Cb (void) |
113 Bench::Cb (void) |
111 { |
114 { |
112 if (m_n > m_total) |
115 if (m_count > m_total) |
113 { |
116 { |
114 return; |
117 return; |
115 } |
118 } |
116 if (m_current == m_distribution.end ()) |
119 DEB ("event at " << Simulator::Now ().GetSeconds () << "s"); |
117 { |
120 |
118 m_current = m_distribution.begin (); |
121 Time after = NanoSeconds (m_rand->GetValue ()); |
119 } |
122 Simulator::Schedule (after, &Bench::Cb, this); |
120 if (g_debug) |
123 ++m_count; |
121 { |
124 } |
122 std::cerr << "event at " << Simulator::Now ().GetSeconds () << "s" << std::endl; |
125 |
123 } |
126 |
124 Simulator::Schedule (NanoSeconds (*m_current), &Bench::Cb, this); |
127 Ptr<RandomVariableStream> |
125 m_current++; |
128 GetRandomStream (std::string filename) |
126 m_n++; |
129 { |
127 } |
130 Ptr<RandomVariableStream> stream = 0; |
128 |
131 |
129 void |
132 if (filename == "") |
130 PrintHelp (void) |
133 { |
131 { |
134 LOGME ("using default exponential distribution"); |
132 std::cout << "bench-simulator filename [options]"<<std::endl; |
135 Ptr<ExponentialRandomVariable> erv = CreateObject<ExponentialRandomVariable> (); |
133 std::cout << " filename: a string which identifies the input distribution. \"-\" represents stdin." << std::endl; |
136 erv->SetAttribute ("Mean", DoubleValue (100)); |
134 std::cout << " Options:"<<std::endl; |
137 stream = erv; |
135 std::cout << " --list: use std::list scheduler"<<std::endl; |
138 } |
136 std::cout << " --map: use std::map cheduler"<<std::endl; |
139 else |
137 std::cout << " --heap: use Binary Heap scheduler"<<std::endl; |
140 { |
138 std::cout << " --debug: enable some debugging"<<std::endl; |
141 std::istream *input; |
139 } |
142 |
|
143 if (filename == "-") |
|
144 { |
|
145 LOGME ("using event distribution from stdin"); |
|
146 input = &std::cin; |
|
147 } |
|
148 else |
|
149 { |
|
150 LOGME ("using event distribution from " << filename); |
|
151 input = new std::ifstream (filename.c_str ()); |
|
152 } |
|
153 |
|
154 double value; |
|
155 std::vector<double> nsValues; |
|
156 |
|
157 while (!input->eof ()) |
|
158 { |
|
159 if (*input >> value) |
|
160 { |
|
161 uint64_t ns = (uint64_t) (value * 1000000000); |
|
162 nsValues.push_back (ns); |
|
163 } |
|
164 else |
|
165 { |
|
166 input->clear (); |
|
167 std::string line; |
|
168 *input >> line; |
|
169 } |
|
170 } |
|
171 LOGME ("found " << nsValues.size () << " entries"); |
|
172 Ptr<DeterministicRandomVariable> drv = CreateObject<DeterministicRandomVariable> (); |
|
173 drv->SetValueArray (&nsValues[0], nsValues.size ()); |
|
174 stream = drv; |
|
175 } |
|
176 |
|
177 return stream; |
|
178 } |
|
179 |
|
180 |
140 |
181 |
141 int main (int argc, char *argv[]) |
182 int main (int argc, char *argv[]) |
142 { |
183 { |
143 char const *filename = argv[1]; |
184 |
144 std::istream *input; |
185 bool schedCal = false; |
145 uint32_t n = 1; |
186 bool schedHeap = false; |
146 uint32_t total = 20000; |
187 bool schedList = false; |
147 if (argc == 1) |
188 bool schedMap = true; |
148 { |
189 |
149 PrintHelp (); |
190 uint32_t pop = 100000; |
150 return 0; |
191 uint32_t total = 1000000; |
151 } |
192 uint32_t runs = 1; |
152 argc-=2; |
193 std::string filename = ""; |
153 argv+= 2; |
194 |
154 if (strcmp (filename, "-") == 0) |
195 CommandLine cmd; |
155 { |
196 cmd.Usage ("Benchmark the simulator scheduler.\n" |
156 input = &std::cin; |
197 "\n" |
157 } |
198 "Event intervals are taken from one of:\n" |
158 else |
199 " an exponential distribution, with mean 100 ns,\n" |
159 { |
200 " an ascii file, given by the --file=\"<filename>\" argument,\n" |
160 input = new std::ifstream (filename); |
201 " or standard input, by the argument --file=\"-\"\n" |
161 } |
202 "In the case of either --file form, the input is expected\n" |
162 while (argc > 0) |
203 "to be ascii, giving the relative event times in ns."); |
163 { |
204 cmd.AddValue ("cal", "use CalendarSheduler", schedCal); |
164 ObjectFactory factory; |
205 cmd.AddValue ("heap", "use HeapScheduler", schedHeap); |
165 if (strcmp ("--list", argv[0]) == 0) |
206 cmd.AddValue ("list", "use ListSheduler", schedList); |
166 { |
207 cmd.AddValue ("map", "use MapScheduler (default)", schedMap); |
167 factory.SetTypeId ("ns3::ListScheduler"); |
208 cmd.AddValue ("debug", "enable debugging output", g_debug); |
168 Simulator::SetScheduler (factory); |
209 cmd.AddValue ("pop", "event population size (default 1E5)", pop); |
169 } |
210 cmd.AddValue ("total", "total number of events to run (default 1E6)", total); |
170 else if (strcmp ("--heap", argv[0]) == 0) |
211 cmd.AddValue ("runs", "number of runs (default 1)", runs); |
171 { |
212 cmd.AddValue ("file", "file of relative event times", filename); |
172 factory.SetTypeId ("ns3::HeapScheduler"); |
213 cmd.AddValue ("prec", "printed output precision", g_fwidth); |
173 Simulator::SetScheduler (factory); |
214 cmd.Parse (argc, argv); |
174 } |
215 g_me = cmd.GetName () + ": "; |
175 else if (strcmp ("--map", argv[0]) == 0) |
216 g_fwidth += 6; // 5 extra chars in '2.000002e+07 ': . e+0 _ |
176 { |
217 |
177 factory.SetTypeId ("ns3::HeapScheduler"); |
218 ObjectFactory factory ("ns3::MapScheduler"); |
178 Simulator::SetScheduler (factory); |
219 if (schedCal) { factory.SetTypeId ("ns3::CalendarScheduler"); } |
179 } |
220 if (schedHeap) { factory.SetTypeId ("ns3::HeapScheduler"); } |
180 else if (strcmp ("--calendar", argv[0]) == 0) |
221 if (schedList) { factory.SetTypeId ("ns3::ListScheduler"); } |
181 { |
222 Simulator::SetScheduler (factory); |
182 factory.SetTypeId ("ns3::CalendarScheduler"); |
223 |
183 Simulator::SetScheduler (factory); |
224 LOGME (std::setprecision (g_fwidth - 6)); |
184 } |
225 DEB ("debugging is ON"); |
185 else if (strcmp ("--debug", argv[0]) == 0) |
226 |
186 { |
227 LOGME ("scheduler: " << factory.GetTypeId ().GetName ()); |
187 g_debug = true; |
228 LOGME ("population: " << pop); |
188 } |
229 LOGME ("total events: " << total); |
189 else if (strncmp ("--total=", argv[0], strlen("--total=")) == 0) |
230 LOGME ("runs: " << runs); |
190 { |
231 |
191 total = atoi (argv[0]+strlen ("--total=")); |
232 Bench *bench = new Bench (pop, total); |
192 } |
233 bench->SetRandomStream (GetRandomStream (filename)); |
193 else if (strncmp ("--n=", argv[0], strlen("--n=")) == 0) |
234 |
194 { |
235 // table header |
195 n = atoi (argv[0]+strlen ("--n=")); |
236 LOG (""); |
196 } |
237 LOG (std::left << std::setw (g_fwidth) << "Run #" << |
197 |
238 std::left << std::setw (3 * g_fwidth) << "Inititialization:" << |
198 argc--; |
239 std::left << std::setw (3 * g_fwidth) << "Simulation:"); |
199 argv++; |
240 LOG (std::left << std::setw (g_fwidth) << "" << |
200 } |
241 std::left << std::setw (g_fwidth) << "Time (s)" << |
201 Bench *bench = new Bench (); |
242 std::left << std::setw (g_fwidth) << "Rate (ev/s)" << |
202 bench->ReadDistribution (*input); |
243 std::left << std::setw (g_fwidth) << "Per (s/ev)" << |
|
244 std::left << std::setw (g_fwidth) << "Time (s)" << |
|
245 std::left << std::setw (g_fwidth) << "Rate (ev/s)" << |
|
246 std::left << std::setw (g_fwidth) << "Per (s/ev)" ); |
|
247 LOG (std::setfill ('-') << |
|
248 std::right << std::setw (g_fwidth) << " " << |
|
249 std::right << std::setw (g_fwidth) << " " << |
|
250 std::right << std::setw (g_fwidth) << " " << |
|
251 std::right << std::setw (g_fwidth) << " " << |
|
252 std::right << std::setw (g_fwidth) << " " << |
|
253 std::right << std::setw (g_fwidth) << " " << |
|
254 std::right << std::setw (g_fwidth) << " " << |
|
255 std::setfill (' ') |
|
256 ); |
|
257 |
|
258 // prime |
|
259 DEB ("priming"); |
|
260 std::cout << std::left << std::setw (g_fwidth) << "(prime)"; |
|
261 bench->RunBench (); |
|
262 |
|
263 bench->SetPopulation (pop); |
203 bench->SetTotal (total); |
264 bench->SetTotal (total); |
204 for (uint32_t i = 0; i < n; i++) |
265 for (uint32_t i = 0; i < runs; i++) |
205 { |
266 { |
|
267 std::cout << std::setw (g_fwidth) << i; |
|
268 |
206 bench->RunBench (); |
269 bench->RunBench (); |
207 } |
270 } |
208 |
271 |
|
272 LOG (""); |
209 return 0; |
273 return 0; |
210 } |
274 } |