A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
file-helper.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013 University of Washington
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mitch Watrous (watrous@u.washington.edu)
7 */
8
9#include "file-helper.h"
10
11#include "ns3/abort.h"
12#include "ns3/config.h"
13#include "ns3/get-wildcard-matches.h"
14#include "ns3/log.h"
15
16#include <fstream>
17#include <iostream>
18#include <string>
19
20namespace ns3
21{
22
23NS_LOG_COMPONENT_DEFINE("FileHelper");
24
26 : m_aggregator(nullptr),
27 m_fileProbeCount(0),
28 m_fileType(FileAggregator::SPACE_SEPARATED),
29 m_outputFileNameWithoutExtension("file-helper"),
30 m_hasHeadingBeenSet(false)
31{
32 NS_LOG_FUNCTION(this);
33
34 // Note that this does not construct an aggregator. It will be
35 // constructed later when needed.
36}
37
38FileHelper::FileHelper(const std::string& outputFileNameWithoutExtension,
40 : m_aggregator(nullptr),
41 m_fileProbeCount(0),
42 m_fileType(fileType),
43 m_outputFileNameWithoutExtension(outputFileNameWithoutExtension),
44 m_hasHeadingBeenSet(false)
45{
46 NS_LOG_FUNCTION(this);
47
48 // Note that this does not construct an aggregator. It will be
49 // constructed later when needed.
50}
51
56
57void
58FileHelper::ConfigureFile(const std::string& outputFileNameWithoutExtension,
60{
61 NS_LOG_FUNCTION(this << outputFileNameWithoutExtension << fileType);
62
63 // See if an aggregator has already been constructed.
64 if (m_aggregator)
65 {
66 NS_LOG_WARN("An existing aggregator object "
67 << m_aggregator << " may be destroyed if no references remain.");
68 }
69
70 // Store these so that they can be used to construct the aggregator.
71 m_fileType = fileType;
72 m_outputFileNameWithoutExtension = outputFileNameWithoutExtension;
73 m_hasHeadingBeenSet = false;
74
75 // Note that this does not construct an aggregator. It will be
76 // constructed later when needed.
77}
78
79void
80FileHelper::WriteProbe(const std::string& typeId,
81 const std::string& path,
82 const std::string& probeTraceSource)
83{
84 NS_LOG_FUNCTION(this << typeId << path << probeTraceSource);
85
86 std::string pathWithoutLastToken;
87 std::string lastToken;
88
89 // See if the path has any wildcards.
90 bool pathHasNoWildcards = path.find('*') == std::string::npos;
91
92 // Remove the last token from the path.
93 size_t lastSlash = path.find_last_of('/');
94 if (lastSlash == std::string::npos)
95 {
96 pathWithoutLastToken = path;
97 lastToken = "";
98 }
99 else
100 {
101 // Chop off up to last token.
102 pathWithoutLastToken = path.substr(0, lastSlash);
103
104 // Save the last token without the last slash.
105 lastToken = path.substr(lastSlash + 1, std::string::npos);
106 }
107
108 // See if there are any matches for the probe's path with the last
109 // token removed.
110 Config::MatchContainer matches = Config::LookupMatches(pathWithoutLastToken);
111 uint32_t matchCount = matches.GetN();
112
113 // This is used to make the probe's context be unique.
114 std::string matchIdentifier;
115
116 /// This is used to indicate if multiple aggregators are needed.
117 bool onlyOneAggregator;
118
119 // Hook one or more probes and one or more aggregators together.
120 if (matchCount == 1 && pathHasNoWildcards)
121 {
122 // Connect the probe to the aggregator only once because there
123 // is only one matching config path. There is no need to find
124 // the wildcard matches because the passed in path has none.
125 matchIdentifier = "0";
126 onlyOneAggregator = true;
128 matchIdentifier,
129 path,
130 probeTraceSource,
132 onlyOneAggregator);
133 }
134 else if (matchCount > 0)
135 {
136 // Handle all of the matches if there are more than one.
137 for (uint32_t i = 0; i < matchCount; i++)
138 {
139 // Set the match identifier.
140 std::ostringstream matchIdentifierStream;
141 matchIdentifierStream << i;
142 matchIdentifier = matchIdentifierStream.str();
143 onlyOneAggregator = false;
144
145 // Construct the matched path and get the matches for each
146 // of the wildcards.
147 std::string wildcardSeparator = "-";
148 std::string matchedPath = matches.GetMatchedPath(i) + lastToken;
149 std::string wildcardMatches = GetWildcardMatches(path, matchedPath, wildcardSeparator);
150
151 // Connect the probe to the aggregator for this match.
153 matchIdentifier,
154 matchedPath,
155 probeTraceSource,
156 m_outputFileNameWithoutExtension + "-" + wildcardMatches,
157 onlyOneAggregator);
158 }
159 }
160 else
161 {
162 // There is a problem if there are no matching config paths.
163 NS_FATAL_ERROR("Lookup of " << path << " got no matches");
164 }
165}
166
167void
168FileHelper::AddProbe(const std::string& typeId,
169 const std::string& probeName,
170 const std::string& path)
171{
172 NS_LOG_FUNCTION(this << typeId << probeName << path);
173
174 // See if this probe had already been added.
175 if (m_probeMap.count(probeName) > 0)
176 {
177 NS_ABORT_MSG("That probe has already been added");
178 }
179
180 // Prepare the factory to create an object with the requested type.
181 m_factory.SetTypeId(typeId);
182
183 // Create a base class object in order to validate the type.
185 if (!probe)
186 {
187 NS_ABORT_MSG("The requested type is not a probe");
188 }
189
190 // Set the probe's name.
191 probe->SetName(probeName);
192
193 // Set the path. Note that no return value is checked here.
194 probe->ConnectByPath(path);
195
196 // Enable logging of data for the probe.
197 probe->Enable();
198
199 // Add this probe to the map so that its values can be used.
200 m_probeMap[probeName] = std::make_pair(probe, typeId);
201}
202
203void
204FileHelper::AddTimeSeriesAdaptor(const std::string& adaptorName)
205{
206 NS_LOG_FUNCTION(this << adaptorName);
207
208 // See if this time series adaptor had already been added.
209 if (m_timeSeriesAdaptorMap.count(adaptorName) > 0)
210 {
211 NS_ABORT_MSG("That time series adaptor has already been added");
212 }
213
214 // Create the time series adaptor.
216
217 // Enable logging of data for the time series adaptor.
218 timeSeriesAdaptor->Enable();
219
220 // Add this time series adaptor to the map so that it can be used.
221 m_timeSeriesAdaptorMap[adaptorName] = timeSeriesAdaptor;
222}
223
224void
225FileHelper::AddAggregator(const std::string& aggregatorName,
226 const std::string& outputFileName,
227 bool onlyOneAggregator)
228{
229 NS_LOG_FUNCTION(this << aggregatorName << outputFileName << onlyOneAggregator);
230
231 // See if this file aggregator had already been added.
232 if (m_aggregatorMap.count(aggregatorName) > 0)
233 {
234 NS_ABORT_MSG("That file aggregator has already been added");
235 }
236
237 // If there is only going to be 1 file aggregator, then use the one
238 // already constructed in the map.
239 if (onlyOneAggregator)
240 {
241 // Get a pointer to the aggregator.
242 Ptr<FileAggregator> singleAggregator = GetAggregatorSingle();
243
244 m_aggregatorMap[aggregatorName] = singleAggregator;
245 return;
246 }
247
248 // Create the file aggregator with the proper file type.
249 Ptr<FileAggregator> multipleAggregator =
251
252 // Set all of the format strings for the aggregator.
253 multipleAggregator->Set1dFormat(m_1dFormat);
254 multipleAggregator->Set2dFormat(m_2dFormat);
255 multipleAggregator->Set3dFormat(m_3dFormat);
256 multipleAggregator->Set4dFormat(m_4dFormat);
257 multipleAggregator->Set5dFormat(m_5dFormat);
258 multipleAggregator->Set6dFormat(m_6dFormat);
259 multipleAggregator->Set7dFormat(m_7dFormat);
260 multipleAggregator->Set8dFormat(m_8dFormat);
261 multipleAggregator->Set9dFormat(m_9dFormat);
262 multipleAggregator->Set10dFormat(m_10dFormat);
263
264 // Set the heading
265 multipleAggregator->SetHeading(m_heading);
266
267 // Enable logging of data for the file aggregator.
268 multipleAggregator->Enable();
269
270 // Add this file aggregator to the map so that it can be used.
271 m_aggregatorMap[aggregatorName] = multipleAggregator;
272}
273
275FileHelper::GetProbe(std::string probeName) const
276{
277 NS_LOG_FUNCTION(this << probeName);
278
279 // Look for the probe.
280 auto mapIterator = m_probeMap.find(probeName);
281
282 // Return the probe if it has been added.
283 if (mapIterator != m_probeMap.end())
284 {
285 return mapIterator->second.first;
286 }
287 else
288 {
289 NS_ABORT_MSG("That probe has not been added");
290 }
291}
292
295{
296 NS_LOG_FUNCTION(this);
297
298 // Do a lazy construction of the single aggregator if it hasn't
299 // already been constructed.
300 if (!m_aggregator)
301 {
302 // Create the aggregator.
303 std::string outputFileName = m_outputFileNameWithoutExtension + ".txt";
305
306 // Set all of the format strings for the aggregator.
307 m_aggregator->Set1dFormat(m_1dFormat);
308 m_aggregator->Set2dFormat(m_2dFormat);
309 m_aggregator->Set3dFormat(m_3dFormat);
310 m_aggregator->Set4dFormat(m_4dFormat);
311 m_aggregator->Set5dFormat(m_5dFormat);
312 m_aggregator->Set6dFormat(m_6dFormat);
313 m_aggregator->Set7dFormat(m_7dFormat);
314 m_aggregator->Set8dFormat(m_8dFormat);
315 m_aggregator->Set9dFormat(m_9dFormat);
316 m_aggregator->Set10dFormat(m_10dFormat);
317
318 // Set the heading
319 m_aggregator->SetHeading(m_heading);
320
321 // Enable logging of data for the aggregator.
322 m_aggregator->Enable();
323 }
324 return m_aggregator;
325}
326
328FileHelper::GetAggregatorMultiple(const std::string& aggregatorName,
329 const std::string& outputFileName)
330{
331 NS_LOG_FUNCTION(this);
332
333 // See if this file aggregator had already been added.
334 if (m_aggregatorMap.count(aggregatorName) > 0)
335 {
336 return m_aggregatorMap[aggregatorName];
337 }
338
339 // Do a lazy construction of the aggregator if it hasn't already
340 // been constructed.
341 bool onlyOneAggregator = false;
342 AddAggregator(aggregatorName, outputFileName, onlyOneAggregator);
343
344 return m_aggregatorMap[aggregatorName];
345}
346
347void
348FileHelper::SetHeading(const std::string& heading)
349{
350 NS_LOG_FUNCTION(this << heading);
351
352 m_hasHeadingBeenSet = true;
353 m_heading = heading;
354}
355
356void
357FileHelper::Set1dFormat(const std::string& format)
358{
359 NS_LOG_FUNCTION(this << format);
360
361 m_1dFormat = format;
362}
363
364void
365FileHelper::Set2dFormat(const std::string& format)
366{
367 NS_LOG_FUNCTION(this << format);
368
369 m_2dFormat = format;
370}
371
372void
373FileHelper::Set3dFormat(const std::string& format)
374{
375 NS_LOG_FUNCTION(this << format);
376
377 m_3dFormat = format;
378}
379
380void
381FileHelper::Set4dFormat(const std::string& format)
382{
383 NS_LOG_FUNCTION(this << format);
384
385 m_4dFormat = format;
386}
387
388void
389FileHelper::Set5dFormat(const std::string& format)
390{
391 NS_LOG_FUNCTION(this << format);
392
393 m_5dFormat = format;
394}
395
396void
397FileHelper::Set6dFormat(const std::string& format)
398{
399 NS_LOG_FUNCTION(this << format);
400
401 m_6dFormat = format;
402}
403
404void
405FileHelper::Set7dFormat(const std::string& format)
406{
407 NS_LOG_FUNCTION(this << format);
408
409 m_7dFormat = format;
410}
411
412void
413FileHelper::Set8dFormat(const std::string& format)
414{
415 NS_LOG_FUNCTION(this << format);
416
417 m_8dFormat = format;
418}
419
420void
421FileHelper::Set9dFormat(const std::string& format)
422{
423 NS_LOG_FUNCTION(this << format);
424
425 m_9dFormat = format;
426}
427
428void
429FileHelper::Set10dFormat(const std::string& format)
430{
431 NS_LOG_FUNCTION(this << format);
432
433 m_10dFormat = format;
434}
435
436void
437FileHelper::ConnectProbeToAggregator(const std::string& typeId,
438 const std::string& matchIdentifier,
439 const std::string& path,
440 const std::string& probeTraceSource,
441 const std::string& outputFileNameWithoutExtension,
442 bool onlyOneAggregator)
443{
444 NS_LOG_FUNCTION(this << typeId << matchIdentifier << path << probeTraceSource
445 << outputFileNameWithoutExtension << onlyOneAggregator);
446
447 // Increment the total number of file probes that have been created.
449
450 // Create a unique name for this probe.
451 std::ostringstream probeNameStream;
452 probeNameStream << "FileProbe-" << m_fileProbeCount;
453 std::string probeName = probeNameStream.str();
454
455 // Create a unique dataset context string for this probe.
456 std::string probeContext = probeName + "/" + matchIdentifier + "/" + probeTraceSource;
457
458 // Add the probe to the map of probes, which will keep the probe in
459 // memory after this function ends.
460 AddProbe(typeId, probeName, path);
461
462 // Because the callbacks to the probes' trace sources don't use the
463 // probe's context, a unique adaptor needs to be created for each
464 // probe context so that information is not lost.
465 AddTimeSeriesAdaptor(probeContext);
466
467 // Connect the probe to the adaptor.
468 if (m_probeMap[probeName].second == "ns3::DoubleProbe" ||
469 m_probeMap[probeName].second == "ns3::TimeProbe")
470 {
471 m_probeMap[probeName].first->TraceConnectWithoutContext(
472 probeTraceSource,
474 m_timeSeriesAdaptorMap[probeContext]));
475 }
476 else if (m_probeMap[probeName].second == "ns3::BooleanProbe")
477 {
478 m_probeMap[probeName].first->TraceConnectWithoutContext(
479 probeTraceSource,
481 m_timeSeriesAdaptorMap[probeContext]));
482 }
483 else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe" ||
484 m_probeMap[probeName].second == "ns3::PacketProbe" ||
485 m_probeMap[probeName].second == "ns3::ApplicationPacketProbe" ||
486 m_probeMap[probeName].second == "ns3::Ipv4PacketProbe" ||
487 m_probeMap[probeName].second == "ns3::Ipv6PacketProbe")
488 {
489 m_probeMap[probeName].first->TraceConnectWithoutContext(
490 probeTraceSource,
492 m_timeSeriesAdaptorMap[probeContext]));
493 }
494 else if (m_probeMap[probeName].second == "ns3::Uinteger8Probe")
495 {
496 m_probeMap[probeName].first->TraceConnectWithoutContext(
497 probeTraceSource,
499 m_timeSeriesAdaptorMap[probeContext]));
500 }
501 else if (m_probeMap[probeName].second == "ns3::Uinteger16Probe")
502 {
503 m_probeMap[probeName].first->TraceConnectWithoutContext(
504 probeTraceSource,
506 m_timeSeriesAdaptorMap[probeContext]));
507 }
508 else
509 {
510 NS_FATAL_ERROR("Unknown probe type " << m_probeMap[probeName].second
511 << "; need to add support in the helper for this");
512 }
513
514 // Add the aggregator to the map of aggregators, which will keep the
515 // aggregator in memory after this function ends.
516 std::string outputFileName = outputFileNameWithoutExtension + ".txt";
517 AddAggregator(probeContext, outputFileName, onlyOneAggregator);
518
519 // Connect the adaptor to the aggregator.
520 std::string adaptorTraceSource = "Output";
521 m_timeSeriesAdaptorMap[probeContext]->TraceConnect(
522 adaptorTraceSource,
523 probeContext,
525}
526
527} // namespace ns3
hold a set of objects which match a specific search string.
Definition config.h:184
std::string GetMatchedPath(uint32_t i) const
Definition config.cc:82
std::size_t GetN() const
Definition config.cc:68
This aggregator sends values it receives to a file.
void Write2d(std::string context, double v1, double v2)
Writes 2 values to the file.
FileType
The type of file written by the aggregator.
void Set2dFormat(const std::string &format)
Sets the 2D format string for the C-style sprintf() function.
void SetHeading(const std::string &heading)
Sets the heading string that will be printed on the first line of the file.
void Set5dFormat(const std::string &format)
Sets the 5D format string for the C-style sprintf() function.
void AddTimeSeriesAdaptor(const std::string &adaptorName)
Adds a time series adaptor to be used to write the file.
Ptr< FileAggregator > GetAggregatorSingle()
Gets the single aggregator that is always constructed.
std::string m_6dFormat
Format string for 6D format C-style sprintf() function.
std::map< std::string, std::pair< Ptr< Probe >, std::string > > m_probeMap
Maps probe names to probes.
void Set3dFormat(const std::string &format)
Sets the 3D format string for the C-style sprintf() function.
Ptr< Probe > GetProbe(std::string probeName) const
Gets the specified probe.
std::map< std::string, Ptr< TimeSeriesAdaptor > > m_timeSeriesAdaptorMap
Maps time series adaptor names to time series adaptors.
void WriteProbe(const std::string &typeId, const std::string &path, const std::string &probeTraceSource)
std::map< std::string, Ptr< FileAggregator > > m_aggregatorMap
Maps aggregator names to aggregators when multiple aggregators are needed.
FileHelper()
Constructs a file helper that will create a space separated file named "file-helper....
void Set6dFormat(const std::string &format)
Sets the 6D format string for the C-style sprintf() function.
ObjectFactory m_factory
Used to create the probes and collectors as they are added.
uint32_t m_fileProbeCount
Number of file probes that have been created.
std::string m_heading
Heading line for the outputfile.
std::string m_outputFileNameWithoutExtension
The name of the output file to created without its extension.
std::string m_8dFormat
Format string for 8D format C-style sprintf() function.
std::string m_9dFormat
Format string for 9D format C-style sprintf() function.
void ConfigureFile(const std::string &outputFileNameWithoutExtension, FileAggregator::FileType fileType=FileAggregator::SPACE_SEPARATED)
bool m_hasHeadingBeenSet
Indicates if the heading line for the file has been set.
std::string m_2dFormat
Format string for 2D format C-style sprintf() function.
void AddAggregator(const std::string &aggregatorName, const std::string &outputFileName, bool onlyOneAggregator)
Adds an aggregator to be used to write values to files.
void Set1dFormat(const std::string &format)
Sets the 1D format string for the C-style sprintf() function.
void AddProbe(const std::string &typeId, const std::string &probeName, const std::string &path)
Adds a probe to be used to write values to files.
std::string m_1dFormat
Format string for 1D format C-style sprintf() function.
std::string m_10dFormat
Format string for 10D format C-style sprintf() function.
std::string m_4dFormat
Format string for 4D format C-style sprintf() function.
std::string m_7dFormat
Format string for 7D format C-style sprintf() function.
void Set4dFormat(const std::string &format)
Sets the 4D format string for the C-style sprintf() function.
void Set7dFormat(const std::string &format)
Sets the 7D format string for the C-style sprintf() function.
FileAggregator::FileType m_fileType
Determines the kind of file written by the aggregator.
Ptr< FileAggregator > m_aggregator
The single aggregator that is always created in the constructor.
virtual ~FileHelper()
std::string m_5dFormat
Format string for 5D format C-style sprintf() function.
std::string m_3dFormat
Format string for 3D format C-style sprintf() function.
void Set8dFormat(const std::string &format)
Sets the 8D format string for the C-style sprintf() function.
Ptr< FileAggregator > GetAggregatorMultiple(const std::string &aggregatorName, const std::string &outputFileName)
Gets one of the multiple aggregators from the map.
void Set10dFormat(const std::string &format)
Sets the 10D format string for the C-style sprintf() function.
void ConnectProbeToAggregator(const std::string &typeId, const std::string &matchIdentifier, const std::string &path, const std::string &probeTraceSource, const std::string &outputFileNameWithoutExtension, bool onlyOneAggregator)
Connects the probe to the aggregator.
void Set9dFormat(const std::string &format)
Sets the 9D format string for the C-style sprintf() function.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
Base class for probes.
Definition probe.h:30
Smart pointer class similar to boost::intrusive_ptr.
void TraceSinkUinteger8(uint8_t oldData, uint8_t newData)
Trace sink for receiving data from uint8_t valued trace sources.
void TraceSinkDouble(double oldData, double newData)
Trace sink for receiving data from double valued trace sources.
void TraceSinkBoolean(bool oldData, bool newData)
Trace sink for receiving data from bool valued trace sources.
void TraceSinkUinteger32(uint32_t oldData, uint32_t newData)
Trace sink for receiving data from uint32_t valued trace sources.
void TraceSinkUinteger16(uint16_t oldData, uint16_t newData)
Trace sink for receiving data from uint16_t valued trace sources.
MatchContainer LookupMatches(std::string path)
Definition config.cc:991
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition log.h:250
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
std::string GetWildcardMatches(const std::string &configPath, const std::string &matchedPath, const std::string &wildcardSeparator)
Returns the text matches from the matched path for each of the wildcards in the Config path,...