A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
gnuplot-helper.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013 University of Washington
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: Mitch Watrous (watrous@u.washington.edu)
18 */
19
20#include "gnuplot-helper.h"
21
22#include "ns3/abort.h"
23#include "ns3/assert.h"
24#include "ns3/config.h"
25#include "ns3/get-wildcard-matches.h"
26#include "ns3/log.h"
27
28#include <fstream>
29#include <iostream>
30#include <sstream>
31#include <string>
32
33namespace ns3
34{
35
36NS_LOG_COMPONENT_DEFINE("GnuplotHelper");
37
39 : m_aggregator(nullptr),
40 m_plotProbeCount(0),
41 m_outputFileNameWithoutExtension("gnuplot-helper"),
42 m_title("Gnuplot Helper Plot"),
43 m_xLegend("X Values"),
44 m_yLegend("Y Values"),
45 m_terminalType("png")
46{
47 NS_LOG_FUNCTION(this);
48
49 // Note that this does not construct an aggregator. It will be
50 // constructed later when needed.
51}
52
53GnuplotHelper::GnuplotHelper(const std::string& outputFileNameWithoutExtension,
54 const std::string& title,
55 const std::string& xLegend,
56 const std::string& yLegend,
57 const std::string& terminalType)
58 : m_aggregator(nullptr),
59 m_plotProbeCount(0),
60 m_outputFileNameWithoutExtension(outputFileNameWithoutExtension),
61 m_title(title),
62 m_xLegend(xLegend),
63 m_yLegend(yLegend),
64 m_terminalType(terminalType)
65{
66 NS_LOG_FUNCTION(this);
67
68 // Construct the aggregator.
70}
71
73{
74 NS_LOG_FUNCTION(this);
75}
76
77void
78GnuplotHelper::ConfigurePlot(const std::string& outputFileNameWithoutExtension,
79 const std::string& title,
80 const std::string& xLegend,
81 const std::string& yLegend,
82 const std::string& terminalType)
83{
84 NS_LOG_FUNCTION(this << outputFileNameWithoutExtension << title << xLegend << yLegend
85 << terminalType);
86
87 // See if an aggregator has already been constructed.
88 if (m_aggregator)
89 {
90 NS_LOG_WARN("An existing aggregator object "
91 << m_aggregator << " may be destroyed if no references remain.");
92 }
93
94 // Store these so that they can be used to construct the aggregator.
95 m_outputFileNameWithoutExtension = outputFileNameWithoutExtension;
96 m_title = title;
97 m_xLegend = xLegend;
98 m_yLegend = yLegend;
99 m_terminalType = terminalType;
100
101 // Construct the aggregator.
103}
104
105void
106GnuplotHelper::PlotProbe(const std::string& typeId,
107 const std::string& path,
108 const std::string& probeTraceSource,
109 const std::string& title,
111{
112 NS_LOG_FUNCTION(this << typeId << path << probeTraceSource << title << keyLocation);
113
114 // Get a pointer to the aggregator.
116
117 // Add a subtitle to the title to show the trace source's path.
118 aggregator->SetTitle(m_title + " \\n\\nTrace Source Path: " + path);
119
120 // Set the default dataset plotting style for the values.
121 aggregator->Set2dDatasetDefaultStyle(Gnuplot2dDataset::LINES_POINTS);
122
123 // Set the location of the key in the plot.
124 aggregator->SetKeyLocation(keyLocation);
125
126 std::string pathWithoutLastToken;
127 std::string lastToken;
128
129 // See if the path has any wildcards.
130 bool pathHasNoWildcards = path.find('*') == std::string::npos;
131
132 // Remove the last token from the path; this should correspond to the
133 // trace source attribute.
134 size_t lastSlash = path.find_last_of('/');
135 if (lastSlash == std::string::npos)
136 {
137 pathWithoutLastToken = path;
138 lastToken = "";
139 }
140 else
141 {
142 // Chop off up to last token.
143 pathWithoutLastToken = path.substr(0, lastSlash);
144
145 // Save the last token without the last slash.
146 lastToken = path.substr(lastSlash + 1, std::string::npos);
147 }
148
149 // See if there are any matches for the probe's path with the last
150 // token removed; this corresponds to the traced object itself.
151 NS_LOG_DEBUG("Searching config database for trace source " << path);
152 Config::MatchContainer matches = Config::LookupMatches(pathWithoutLastToken);
153 uint32_t matchCount = matches.GetN();
154 NS_LOG_DEBUG("Found " << matchCount << " matches for trace source " << path);
155
156 // This is used to make the probe's context be unique.
157 std::string matchIdentifier;
158
159 // Hook one or more probes and the aggregator together.
160 if (matchCount == 1 && pathHasNoWildcards)
161 {
162 // Connect the probe to the aggregator only once because there
163 // is only one matching config path. There is no need to find
164 // the wildcard matches because the passed in path has none.
165 matchIdentifier = "0";
166 ConnectProbeToAggregator(typeId, matchIdentifier, path, probeTraceSource, title);
167 }
168 else if (matchCount > 0)
169 {
170 // Handle all of the matches if there are more than one.
171 for (uint32_t i = 0; i < matchCount; i++)
172 {
173 // Set the match identifier.
174 std::ostringstream matchIdentifierStream;
175 matchIdentifierStream << i;
176 matchIdentifier = matchIdentifierStream.str();
177
178 // Construct the matched path and get the matches for each
179 // of the wildcards.
180 std::string wildcardSeparator = " ";
181 std::string matchedPath = matches.GetMatchedPath(i) + lastToken;
182 std::string wildcardMatches = GetWildcardMatches(path, matchedPath, wildcardSeparator);
183
184 // Connect the probe to the aggregator for this match.
186 matchIdentifier,
187 matchedPath,
188 probeTraceSource,
189 title + "-" + wildcardMatches);
190 }
191 }
192 else
193 {
194 // There is a problem if there are no matching config paths.
195 NS_FATAL_ERROR("Lookup of " << path << " got no matches");
196 }
197}
198
199void
200GnuplotHelper::AddProbe(const std::string& typeId,
201 const std::string& probeName,
202 const std::string& path)
203{
204 NS_LOG_FUNCTION(this << typeId << probeName << path);
205
206 // See if this probe had already been added.
207 if (m_probeMap.count(probeName) > 0)
208 {
209 NS_ABORT_MSG("That probe has already been added");
210 }
211
212 // Prepare the factory to create an object with the requested type.
213 m_factory.SetTypeId(typeId);
214
215 // Create a base class object in order to validate the type.
217 if (!probe)
218 {
219 NS_ABORT_MSG("The requested type is not a probe");
220 }
221
222 // Set the probe's name.
223 probe->SetName(probeName);
224
225 // Set the path. Note that no return value is checked here.
226 probe->ConnectByPath(path);
227
228 // Enable logging of data for the probe.
229 probe->Enable();
230
231 // Add this probe to the map so that its values can be used.
232 m_probeMap[probeName] = std::make_pair(probe, typeId);
233}
234
235void
236GnuplotHelper::AddTimeSeriesAdaptor(const std::string& adaptorName)
237{
238 NS_LOG_FUNCTION(this << adaptorName);
239
240 // See if this time series adaptor had already been added.
241 if (m_timeSeriesAdaptorMap.count(adaptorName) > 0)
242 {
243 NS_ABORT_MSG("That time series adaptor has already been added");
244 }
245
246 // Create the time series adaptor.
247 Ptr<TimeSeriesAdaptor> timeSeriesAdaptor = CreateObject<TimeSeriesAdaptor>();
248
249 // Enable logging of data for the time series adaptor.
250 timeSeriesAdaptor->Enable();
251
252 // Add this time series adaptor to the map so that can be used.
253 m_timeSeriesAdaptorMap[adaptorName] = timeSeriesAdaptor;
254}
255
257GnuplotHelper::GetProbe(std::string probeName) const
258{
259 // Look for the probe.
260 auto mapIterator = m_probeMap.find(probeName);
261
262 // Return the probe if it has been added.
263 if (mapIterator != m_probeMap.end())
264 {
265 return mapIterator->second.first;
266 }
267 else
268 {
269 NS_ABORT_MSG("That probe has not been added");
270 }
271}
272
275{
276 NS_LOG_FUNCTION(this);
277
278 // Do a lazy construction of the aggregator if it hasn't already
279 // been constructed.
280 if (!m_aggregator)
281 {
283 }
284 return m_aggregator;
285}
286
287void
289{
290 NS_LOG_FUNCTION(this);
291
292 // Create the aggregator.
293 m_aggregator = CreateObject<GnuplotAggregator>(m_outputFileNameWithoutExtension);
294
295 // Set the aggregator's properties.
296 m_aggregator->SetTerminal(m_terminalType);
297 m_aggregator->SetTitle(m_title);
298 m_aggregator->SetLegend(m_xLegend, m_yLegend);
299
300 // Enable logging of data for the aggregator.
301 m_aggregator->Enable();
302}
303
304void
306 const std::string& matchIdentifier,
307 const std::string& path,
308 const std::string& probeTraceSource,
309 const std::string& title)
310{
311 NS_LOG_FUNCTION(this << typeId << matchIdentifier << path << probeTraceSource << title);
312
314
315 // Increment the total number of plot probes that have been created.
317
318 // Create a unique name for this probe.
319 std::ostringstream probeNameStream;
320 probeNameStream << "PlotProbe-" << m_plotProbeCount;
321 std::string probeName = probeNameStream.str();
322
323 // Create a unique dataset context string for this probe.
324 std::string probeContext = probeName + "/" + matchIdentifier + "/" + probeTraceSource;
325
326 // Add the probe to the map of probes, which will keep the probe in
327 // memory after this function ends.
328 AddProbe(typeId, probeName, path);
329
330 // Because the callbacks to the probes' trace sources don't use the
331 // probe's context, a unique adaptor needs to be created for each
332 // probe context so that information is not lost.
333 AddTimeSeriesAdaptor(probeContext);
334
335 // Connect the probe to the adaptor.
336 if (m_probeMap[probeName].second == "ns3::DoubleProbe")
337 {
338 m_probeMap[probeName].first->TraceConnectWithoutContext(
339 probeTraceSource,
341 m_timeSeriesAdaptorMap[probeContext]));
342 }
343 else if (m_probeMap[probeName].second == "ns3::BooleanProbe")
344 {
345 m_probeMap[probeName].first->TraceConnectWithoutContext(
346 probeTraceSource,
348 m_timeSeriesAdaptorMap[probeContext]));
349 }
350 else if (m_probeMap[probeName].second == "ns3::PacketProbe")
351 {
352 m_probeMap[probeName].first->TraceConnectWithoutContext(
353 probeTraceSource,
355 m_timeSeriesAdaptorMap[probeContext]));
356 }
357 else if (m_probeMap[probeName].second == "ns3::ApplicationPacketProbe")
358 {
359 m_probeMap[probeName].first->TraceConnectWithoutContext(
360 probeTraceSource,
362 m_timeSeriesAdaptorMap[probeContext]));
363 }
364 else if (m_probeMap[probeName].second == "ns3::Ipv4PacketProbe")
365 {
366 m_probeMap[probeName].first->TraceConnectWithoutContext(
367 probeTraceSource,
369 m_timeSeriesAdaptorMap[probeContext]));
370 }
371 else if (m_probeMap[probeName].second == "ns3::Ipv6PacketProbe")
372 {
373 m_probeMap[probeName].first->TraceConnectWithoutContext(
374 probeTraceSource,
376 m_timeSeriesAdaptorMap[probeContext]));
377 }
378 else if (m_probeMap[probeName].second == "ns3::Uinteger8Probe")
379 {
380 m_probeMap[probeName].first->TraceConnectWithoutContext(
381 probeTraceSource,
383 m_timeSeriesAdaptorMap[probeContext]));
384 }
385 else if (m_probeMap[probeName].second == "ns3::Uinteger16Probe")
386 {
387 m_probeMap[probeName].first->TraceConnectWithoutContext(
388 probeTraceSource,
390 m_timeSeriesAdaptorMap[probeContext]));
391 }
392 else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe")
393 {
394 m_probeMap[probeName].first->TraceConnectWithoutContext(
395 probeTraceSource,
397 m_timeSeriesAdaptorMap[probeContext]));
398 }
399 else if (m_probeMap[probeName].second == "ns3::TimeProbe")
400 {
401 m_probeMap[probeName].first->TraceConnectWithoutContext(
402 probeTraceSource,
404 m_timeSeriesAdaptorMap[probeContext]));
405 }
406 else
407 {
408 NS_FATAL_ERROR("Unknown probe type " << m_probeMap[probeName].second
409 << "; need to add support in the helper for this");
410 }
411
412 // Connect the adaptor to the aggregator.
413 std::string adaptorTraceSource = "Output";
414 m_timeSeriesAdaptorMap[probeContext]->TraceConnect(
415 adaptorTraceSource,
416 probeContext,
418
419 // Add the dataset to the plot.
420 aggregator->Add2dDataset(probeContext, title);
421}
422
423} // namespace ns3
hold a set of objects which match a specific search string.
Definition: config.h:195
std::string GetMatchedPath(uint32_t i) const
Definition: config.cc:93
std::size_t GetN() const
Definition: config.cc:79
void Write2d(std::string context, double x, double y)
Writes a 2D value to a 2D gnuplot dataset.
KeyLocation
The location of the key in the plot.
void ConfigurePlot(const std::string &outputFileNameWithoutExtension, const std::string &title, const std::string &xLegend, const std::string &yLegend, const std::string &terminalType="png")
std::string m_title
Title string to use for this plot.
GnuplotHelper()
Constructs a gnuplot helper that will create a space separated gnuplot data file named "gnuplot-helpe...
void AddTimeSeriesAdaptor(const std::string &adaptorName)
Adds a time series adaptor to be used to make the plot.
Ptr< GnuplotAggregator > m_aggregator
The aggregator used to make the plots.
Ptr< Probe > GetProbe(std::string probeName) const
Gets the specified probe.
std::string m_terminalType
Terminal type for the plot.
std::string m_outputFileNameWithoutExtension
The name of the output file to created without its extension.
uint32_t m_plotProbeCount
Number of plot probes that have been created.
virtual ~GnuplotHelper()
ObjectFactory m_factory
Used to create the probes and collectors as they are added.
std::string m_yLegend
Legend for the y axis.
std::map< std::string, Ptr< TimeSeriesAdaptor > > m_timeSeriesAdaptorMap
Maps time series adaptor names to time series adaptors.
void AddProbe(const std::string &typeId, const std::string &probeName, const std::string &path)
Adds a probe to be used to make the plot.
void PlotProbe(const std::string &typeId, const std::string &path, const std::string &probeTraceSource, const std::string &title, GnuplotAggregator::KeyLocation keyLocation=GnuplotAggregator::KEY_INSIDE)
void ConnectProbeToAggregator(const std::string &typeId, const std::string &matchIdentifier, const std::string &path, const std::string &probeTraceSource, const std::string &title)
Connects the probe to the aggregator.
std::map< std::string, std::pair< Ptr< Probe >, std::string > > m_probeMap
Maps probe names to probes.
void ConstructAggregator()
Constructs the aggregator.
std::string m_xLegend
Legend for the x axis.
Ptr< GnuplotAggregator > GetAggregator()
Gets the aggregator.
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:522
Base class for probes.
Definition: probe.h:41
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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:1002
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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:261
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:704
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,...
Definition: second.py:1