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