A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
file-helper.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013 University of Washington
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: Mitch Watrous (watrous@u.washington.edu)
19  */
20 
21 #include <iostream>
22 #include <fstream>
23 #include <string>
24 
25 #include "file-helper.h"
26 #include "ns3/abort.h"
27 #include "ns3/log.h"
28 #include "ns3/config.h"
29 #include "ns3/get-wildcard-matches.h"
30 
31 namespace ns3 {
32 
33 NS_LOG_COMPONENT_DEFINE ("FileHelper");
34 
36  : m_aggregator (0),
37  m_fileProbeCount (0),
38  m_fileType (FileAggregator::SPACE_SEPARATED),
39  m_outputFileNameWithoutExtension ("file-helper"),
40  m_hasHeadingBeenSet (false)
41 {
42  NS_LOG_FUNCTION (this);
43 
44  // Note that this does not construct an aggregator. It will be
45  // constructed later when needed.
46 }
47 
48 FileHelper::FileHelper (const std::string &outputFileNameWithoutExtension,
49  enum FileAggregator::FileType fileType)
50  : m_aggregator (0),
51  m_fileProbeCount (0),
52  m_fileType (fileType),
53  m_outputFileNameWithoutExtension (outputFileNameWithoutExtension),
54  m_hasHeadingBeenSet (false)
55 {
56  NS_LOG_FUNCTION (this);
57 
58  // Note that this does not construct an aggregator. It will be
59  // constructed later when needed.
60 }
61 
63 {
64  NS_LOG_FUNCTION (this);
65 }
66 
67 void
68 FileHelper::ConfigureFile (const std::string &outputFileNameWithoutExtension,
69  enum FileAggregator::FileType fileType)
70 {
71  NS_LOG_FUNCTION (this << outputFileNameWithoutExtension << fileType);
72 
73  // See if an aggregator has already been constructed.
74  if (m_aggregator != 0)
75  {
76  NS_LOG_WARN ("An existing aggregator object " << m_aggregator <<
77  " may be destroyed if no references remain.");
78  }
79 
80  // Store these so that they can be used to construct the aggregator.
81  m_fileType = fileType;
82  m_outputFileNameWithoutExtension = outputFileNameWithoutExtension;
83  m_hasHeadingBeenSet = false;
84 
85  // Note that this does not construct an aggregator. It will be
86  // constructed later when needed.
87 }
88 
89 void
90 FileHelper::WriteProbe (const std::string &typeId,
91  const std::string &path,
92  const std::string &probeTraceSource)
93 {
94  NS_LOG_FUNCTION (this << typeId << path << probeTraceSource);
95 
96  std::string pathWithoutLastToken;
97  std::string lastToken;
98 
99  // See if the path has any wildcards.
100  bool pathHasNoWildcards = path.find ("*") == std::string::npos;
101 
102  // Remove the last token from the path.
103  size_t lastSlash = path.find_last_of ("/");
104  if (lastSlash == std::string::npos)
105  {
106  pathWithoutLastToken = path;
107  lastToken = "";
108  }
109  else
110  {
111  // Chop off up to last token.
112  pathWithoutLastToken = path.substr (0, lastSlash);
113 
114  // Save the last token without the last slash.
115  lastToken = path.substr (lastSlash + 1, std::string::npos);
116  }
117 
118  // See if there are any matches for the probe's path with the last
119  // token removed.
120  Config::MatchContainer matches = Config::LookupMatches (pathWithoutLastToken);
121  uint32_t matchCount = matches.GetN ();
122 
123  // This is used to make the probe's context be unique.
124  std::string matchIdentifier;
125 
127  bool onlyOneAggregator;
128 
129  // Hook one or more probes and one or more aggregators together.
130  if (matchCount == 1 && pathHasNoWildcards)
131  {
132  // Connect the probe to the aggregator only once because there
133  // is only one matching config path. There is no need to find
134  // the wildcard matches because the passed in path has none.
135  matchIdentifier = "0";
136  onlyOneAggregator = true;
137  ConnectProbeToAggregator (typeId,
138  matchIdentifier,
139  path,
140  probeTraceSource,
142  onlyOneAggregator);
143  }
144  else if (matchCount > 0)
145  {
146  // Handle all of the matches if there are more than one.
147  for (uint32_t i = 0; i < matchCount; i++)
148  {
149  // Set the match identifier.
150  std::ostringstream matchIdentifierStream;
151  matchIdentifierStream << i;
152  matchIdentifier = matchIdentifierStream.str ();
153  onlyOneAggregator = false;
154 
155  // Construct the matched path and get the matches for each
156  // of the wildcards.
157  std::string wildcardSeparator = "-";
158  std::string matchedPath = matches.GetMatchedPath (i) + lastToken;
159  std::string wildcardMatches = GetWildcardMatches (path,
160  matchedPath,
161  wildcardSeparator);
162 
163  // Connect the probe to the aggregator for this match.
164  ConnectProbeToAggregator (typeId,
165  matchIdentifier,
166  matchedPath,
167  probeTraceSource,
168  m_outputFileNameWithoutExtension + "-" + wildcardMatches,
169  onlyOneAggregator);
170  }
171  }
172  else
173  {
174  // There is a problem if there are no matching config paths.
175  NS_FATAL_ERROR ("Lookup of " << path << " got no matches");
176  }
177 }
178 
179 void
180 FileHelper::AddProbe (const std::string &typeId,
181  const std::string &probeName,
182  const std::string &path)
183 {
184  NS_LOG_FUNCTION (this << typeId << probeName << path);
185 
186  // See if this probe had already been added.
187  if (m_probeMap.count (probeName) > 0)
188  {
189  NS_ABORT_MSG ("That probe has already been added");
190  }
191 
192  // Prepare the factory to create an object with the requested type.
193  m_factory.SetTypeId (typeId);
194 
195  // Create a base class object in order to validate the type.
196  Ptr<Probe> probe = m_factory.Create ()->GetObject<Probe> ();
197  if (probe == 0)
198  {
199  NS_ABORT_MSG ("The requested type is not a probe");
200  }
201 
202  // Set the probe's name.
203  probe->SetName (probeName);
204 
205  // Set the path. Note that no return value is checked here.
206  probe->ConnectByPath (path);
207 
208  // Enable logging of data for the probe.
209  probe->Enable ();
210 
211  // Add this probe to the map so that its values can be used.
212  m_probeMap[probeName] = std::make_pair (probe, typeId);
213 }
214 
215 void
216 FileHelper::AddTimeSeriesAdaptor (const std::string &adaptorName)
217 {
218  NS_LOG_FUNCTION (this << adaptorName);
219 
220  // See if this time series adaptor had already been added.
221  if (m_timeSeriesAdaptorMap.count (adaptorName) > 0)
222  {
223  NS_ABORT_MSG ("That time series adaptor has already been added");
224  }
225 
226  // Create the time series adaptor.
227  Ptr<TimeSeriesAdaptor> timeSeriesAdaptor = CreateObject<TimeSeriesAdaptor> ();
228 
229  // Enable logging of data for the time series adaptor.
230  timeSeriesAdaptor->Enable ();
231 
232  // Add this time series adaptor to the map so that it can be used.
233  m_timeSeriesAdaptorMap[adaptorName] = timeSeriesAdaptor;
234 }
235 
236 void
237 FileHelper::AddAggregator (const std::string &aggregatorName,
238  const std::string &outputFileName,
239  bool onlyOneAggregator)
240 {
241  NS_LOG_FUNCTION (this << aggregatorName << outputFileName << onlyOneAggregator);
242 
243  // See if this file aggregator had already been added.
244  if (m_aggregatorMap.count (aggregatorName) > 0)
245  {
246  NS_ABORT_MSG ("That file aggregator has already been added");
247  }
248 
249  // If there is only going to be 1 file aggregator, then use the one
250  // already constructed in the map.
251  if (onlyOneAggregator)
252  {
253  // Get a pointer to the aggregator.
254  Ptr<FileAggregator> singleAggregator = GetAggregatorSingle ();
255 
256  m_aggregatorMap[aggregatorName] = singleAggregator;
257  return;
258  }
259 
260  // Create the file aggregator with the proper file type.
261  Ptr<FileAggregator> multipleAggregator =
262  CreateObject<FileAggregator> (outputFileName, m_fileType);
263 
264  // Set all of the format strings for the aggregator.
265  multipleAggregator->Set1dFormat (m_1dFormat);
266  multipleAggregator->Set2dFormat (m_2dFormat);
267  multipleAggregator->Set3dFormat (m_3dFormat);
268  multipleAggregator->Set4dFormat (m_4dFormat);
269  multipleAggregator->Set5dFormat (m_5dFormat);
270  multipleAggregator->Set6dFormat (m_6dFormat);
271  multipleAggregator->Set7dFormat (m_7dFormat);
272  multipleAggregator->Set8dFormat (m_8dFormat);
273  multipleAggregator->Set9dFormat (m_9dFormat);
274  multipleAggregator->Set10dFormat (m_10dFormat);
275 
276  // Set the heading
277  multipleAggregator->SetHeading (m_heading);
278 
279  // Enable logging of data for the file aggregator.
280  multipleAggregator->Enable ();
281 
282  // Add this file aggregator to the map so that it can be used.
283  m_aggregatorMap[aggregatorName] = multipleAggregator;
284 }
285 
287 FileHelper::GetProbe (std::string probeName) const
288 {
289  NS_LOG_FUNCTION (this << probeName);
290 
291  // Look for the probe.
292  std::map<std::string, std::pair <Ptr<Probe>, std::string> >::const_iterator mapIterator = m_probeMap.find (probeName);
293 
294  // Return the probe if it has been added.
295  if (mapIterator != m_probeMap.end ())
296  {
297  return mapIterator->second.first;
298  }
299  else
300  {
301  NS_ABORT_MSG ("That probe has not been added");
302  }
303 }
304 
307 {
308  NS_LOG_FUNCTION (this);
309 
310  // Do a lazy construction of the single aggregator if it hasn't
311  // already been constructed.
312  if (!m_aggregator)
313  {
314  // Create the aggregator.
315  std::string outputFileName = m_outputFileNameWithoutExtension + ".txt";
316  m_aggregator = CreateObject<FileAggregator> (outputFileName, m_fileType);
317 
318  // Set all of the format strings for the aggregator.
329 
330  // Set the heading
332 
333  // Enable logging of data for the aggregator.
334  m_aggregator->Enable ();
335  }
336  return m_aggregator;
337 }
338 
340 FileHelper::GetAggregatorMultiple (const std::string &aggregatorName,
341  const std::string &outputFileName)
342 {
343  NS_LOG_FUNCTION (this);
344 
345  // See if this file aggregator had already been added.
346  if (m_aggregatorMap.count (aggregatorName) > 0)
347  {
348  return m_aggregatorMap[aggregatorName];
349  }
350 
351  // Do a lazy construction of the aggregator if it hasn't already
352  // been constructed.
353  bool onlyOneAggregator = false;
354  AddAggregator (aggregatorName,
355  outputFileName,
356  onlyOneAggregator);
357 
358  return m_aggregatorMap[aggregatorName];
359 }
360 
361 void
362 FileHelper::SetHeading (const std::string &heading)
363 {
364  NS_LOG_FUNCTION (this << heading);
365 
366  m_hasHeadingBeenSet = true;
367  m_heading = heading;
368 }
369 
370 void
371 FileHelper::Set1dFormat (const std::string &format)
372 {
373  NS_LOG_FUNCTION (this << format);
374 
375  m_1dFormat = format;
376 }
377 
378 void
379 FileHelper::Set2dFormat (const std::string &format)
380 {
381  NS_LOG_FUNCTION (this << format);
382 
383  m_2dFormat = format;
384 }
385 
386 void
387 FileHelper::Set3dFormat (const std::string &format)
388 {
389  NS_LOG_FUNCTION (this << format);
390 
391  m_3dFormat = format;
392 }
393 
394 void
395 FileHelper::Set4dFormat (const std::string &format)
396 {
397  NS_LOG_FUNCTION (this << format);
398 
399  m_4dFormat = format;
400 }
401 
402 void
403 FileHelper::Set5dFormat (const std::string &format)
404 {
405  NS_LOG_FUNCTION (this << format);
406 
407  m_5dFormat = format;
408 }
409 
410 void
411 FileHelper::Set6dFormat (const std::string &format)
412 {
413  NS_LOG_FUNCTION (this << format);
414 
415  m_6dFormat = format;
416 }
417 
418 void
419 FileHelper::Set7dFormat (const std::string &format)
420 {
421  NS_LOG_FUNCTION (this << format);
422 
423  m_7dFormat = format;
424 }
425 
426 void
427 FileHelper::Set8dFormat (const std::string &format)
428 {
429  NS_LOG_FUNCTION (this << format);
430 
431  m_8dFormat = format;
432 }
433 
434 void
435 FileHelper::Set9dFormat (const std::string &format)
436 {
437  NS_LOG_FUNCTION (this << format);
438 
439  m_9dFormat = format;
440 }
441 
442 void
443 FileHelper::Set10dFormat (const std::string &format)
444 {
445  NS_LOG_FUNCTION (this << format);
446 
447  m_10dFormat = format;
448 }
449 
450 void
451 FileHelper::ConnectProbeToAggregator (const std::string &typeId,
452  const std::string &matchIdentifier,
453  const std::string &path,
454  const std::string &probeTraceSource,
455  const std::string &outputFileNameWithoutExtension,
456  bool onlyOneAggregator)
457 {
458  NS_LOG_FUNCTION (this << typeId << matchIdentifier << path << probeTraceSource
459  << outputFileNameWithoutExtension << onlyOneAggregator);
460 
461  // Increment the total number of file probes that have been created.
463 
464  // Create a unique name for this probe.
465  std::ostringstream probeNameStream;
466  probeNameStream << "FileProbe-" << m_fileProbeCount;
467  std::string probeName = probeNameStream.str ();
468 
469  // Create a unique dataset context string for this probe.
470  std::string probeContext = probeName
471  + "/" + matchIdentifier + "/" + probeTraceSource;
472 
473  // Add the probe to the map of probes, which will keep the probe in
474  // memory after this function ends.
475  AddProbe (typeId, probeName, path);
476 
477  // Because the callbacks to the probes' trace sources don't use the
478  // probe's context, a unique adaptor needs to be created for each
479  // probe context so that information is not lost.
480  AddTimeSeriesAdaptor (probeContext);
481 
482  // Connect the probe to the adaptor.
483  if (m_probeMap[probeName].second == "ns3::DoubleProbe")
484  {
485  m_probeMap[probeName].first->TraceConnectWithoutContext
486  (probeTraceSource,
488  m_timeSeriesAdaptorMap[probeContext]));
489  }
490  else if (m_probeMap[probeName].second == "ns3::BooleanProbe")
491  {
492  m_probeMap[probeName].first->TraceConnectWithoutContext
493  (probeTraceSource,
495  m_timeSeriesAdaptorMap[probeContext]));
496  }
497  else if (m_probeMap[probeName].second == "ns3::PacketProbe")
498  {
499  m_probeMap[probeName].first->TraceConnectWithoutContext
500  (probeTraceSource,
502  m_timeSeriesAdaptorMap[probeContext]));
503  }
504  else if (m_probeMap[probeName].second == "ns3::ApplicationPacketProbe")
505  {
506  m_probeMap[probeName].first->TraceConnectWithoutContext
507  (probeTraceSource,
509  m_timeSeriesAdaptorMap[probeContext]));
510  }
511  else if (m_probeMap[probeName].second == "ns3::Ipv4PacketProbe")
512  {
513  m_probeMap[probeName].first->TraceConnectWithoutContext
514  (probeTraceSource,
516  m_timeSeriesAdaptorMap[probeContext]));
517  }
518  else if (m_probeMap[probeName].second == "ns3::Ipv6PacketProbe")
519  {
520  m_probeMap[probeName].first->TraceConnectWithoutContext
521  (probeTraceSource,
523  m_timeSeriesAdaptorMap[probeContext]));
524  }
525  else if (m_probeMap[probeName].second == "ns3::Uinteger8Probe")
526  {
527  m_probeMap[probeName].first->TraceConnectWithoutContext
528  (probeTraceSource,
530  m_timeSeriesAdaptorMap[probeContext]));
531  }
532  else if (m_probeMap[probeName].second == "ns3::Uinteger16Probe")
533  {
534  m_probeMap[probeName].first->TraceConnectWithoutContext
535  (probeTraceSource,
537  m_timeSeriesAdaptorMap[probeContext]));
538  }
539  else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe")
540  {
541  m_probeMap[probeName].first->TraceConnectWithoutContext
542  (probeTraceSource,
544  m_timeSeriesAdaptorMap[probeContext]));
545  }
546  else
547  {
548  NS_FATAL_ERROR ("Unknown probe type " << m_probeMap[probeName].second << "; need to add support in the helper for this");
549  }
550 
551  // Add the aggregator to the map of aggregators, which will keep the
552  // aggregator in memory after this function ends.
553  std::string outputFileName = outputFileNameWithoutExtension + ".txt";
554  AddAggregator (probeContext, outputFileName, onlyOneAggregator);
555 
556  // Connect the adaptor to the aggregator.
557  std::string adaptorTraceSource = "Output";
558  m_timeSeriesAdaptorMap[probeContext]->TraceConnect
559  (adaptorTraceSource,
560  probeContext,
562  m_aggregatorMap[probeContext]));
563 }
564 
565 } // namespace ns3
566