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 
33 namespace ns3 {
34 
35 NS_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 
52 GnuplotHelper::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 
76 void
77 GnuplotHelper::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 
104 void
105 GnuplotHelper::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.
114  Ptr<GnuplotAggregator> aggregator = GetAggregator ();
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";
165  ConnectProbeToAggregator (typeId,
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.
190  ConnectProbeToAggregator (typeId,
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 
204 void
205 GnuplotHelper::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 
240 void
241 GnuplotHelper::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 
262 GnuplotHelper::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 
292 void
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 
309 void
310 GnuplotHelper::ConnectProbeToAggregator (const std::string &typeId,
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 
319  Ptr<GnuplotAggregator> aggregator = GetAggregator ();
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 
NS_LOG_COMPONENT_DEFINE
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
ns3::GnuplotHelper::GetAggregator
Ptr< GnuplotAggregator > GetAggregator()
Gets the aggregator.
Definition: gnuplot-helper.cc:279
ns3
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns3::GnuplotHelper::m_factory
ObjectFactory m_factory
Used to create the probes and collectors as they are added.
Definition: gnuplot-helper.h:186
ns3::GnuplotHelper::AddTimeSeriesAdaptor
void AddTimeSeriesAdaptor(const std::string &adaptorName)
Adds a time series adaptor to be used to make the plot.
Definition: gnuplot-helper.cc:241
ns3::Object::GetObject
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
ns3::GnuplotHelper::m_timeSeriesAdaptorMap
std::map< std::string, Ptr< TimeSeriesAdaptor > > m_timeSeriesAdaptorMap
Maps time series adaptor names to time series adaptors.
Definition: gnuplot-helper.h:195
ns3::GnuplotHelper::m_xLegend
std::string m_xLegend
Legend for the x axis.
Definition: gnuplot-helper.h:207
ns3::Gnuplot2dDataset::LINES_POINTS
@ LINES_POINTS
Definition: gnuplot.h:126
ns3::TimeSeriesAdaptor::TraceSinkUinteger32
void TraceSinkUinteger32(uint32_t oldData, uint32_t newData)
Trace sink for receiving data from uint32_t valued trace sources.
Definition: time-series-adaptor.cc:106
NS_LOG_WARN
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:265
ns3::GnuplotHelper::m_aggregator
Ptr< GnuplotAggregator > m_aggregator
The aggregator used to make the plots.
Definition: gnuplot-helper.h:189
ns3::GnuplotHelper::ConstructAggregator
void ConstructAggregator()
Constructs the aggregator.
Definition: gnuplot-helper.cc:293
ns3::TimeSeriesAdaptor::TraceSinkUinteger16
void TraceSinkUinteger16(uint16_t oldData, uint16_t newData)
Trace sink for receiving data from uint16_t valued trace sources.
Definition: time-series-adaptor.cc:97
ns3::Config::LookupMatches
MatchContainer LookupMatches(std::string path)
Definition: config.cc:940
ns3::Config::MatchContainer
hold a set of objects which match a specific search string.
Definition: config.h:181
ns3::GnuplotHelper::AddProbe
void AddProbe(const std::string &typeId, const std::string &probeName, const std::string &path)
Adds a probe to be used to make the plot.
Definition: gnuplot-helper.cc:205
ns3::GnuplotHelper::PlotProbe
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)
Definition: gnuplot-helper.cc:105
ns3::GnuplotHelper::~GnuplotHelper
virtual ~GnuplotHelper()
Definition: gnuplot-helper.cc:71
ns3::GnuplotHelper::m_plotProbeCount
uint32_t m_plotProbeCount
Number of plot probes that have been created.
Definition: gnuplot-helper.h:198
ns3::GnuplotHelper::m_outputFileNameWithoutExtension
std::string m_outputFileNameWithoutExtension
The name of the output file to created without its extension.
Definition: gnuplot-helper.h:201
ns3::Ptr
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
NS_FATAL_ERROR
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
ns3::GnuplotAggregator::Write2d
void Write2d(std::string context, double x, double y)
Writes a 2D value to a 2D gnuplot dataset.
Definition: gnuplot-aggregator.cc:105
ns3::GnuplotHelper::GnuplotHelper
GnuplotHelper()
Constructs a gnuplot helper that will create a space separated gnuplot data file named "gnuplot-helpe...
Definition: gnuplot-helper.cc:37
ns3::Config::MatchContainer::GetMatchedPath
std::string GetMatchedPath(uint32_t i) const
Definition: config.cc:81
gnuplot-helper.h
ns3::GnuplotHelper::m_terminalType
std::string m_terminalType
Terminal type for the plot.
Definition: gnuplot-helper.h:213
ns3::TimeSeriesAdaptor::TraceSinkBoolean
void TraceSinkBoolean(bool oldData, bool newData)
Trace sink for receiving data from bool valued trace sources.
Definition: time-series-adaptor.cc:79
second
Definition: second.py:1
ns3::MakeCallback
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:1642
ns3::TimeSeriesAdaptor::TraceSinkUinteger8
void TraceSinkUinteger8(uint8_t oldData, uint8_t newData)
Trace sink for receiving data from uint8_t valued trace sources.
Definition: time-series-adaptor.cc:88
ns3::Config::MatchContainer::GetN
std::size_t GetN(void) const
Definition: config.cc:69
NS_LOG_DEBUG
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
ns3::GnuplotHelper::ConfigurePlot
void ConfigurePlot(const std::string &outputFileNameWithoutExtension, const std::string &title, const std::string &xLegend, const std::string &yLegend, const std::string &terminalType="png")
Definition: gnuplot-helper.cc:77
ns3::GnuplotHelper::m_yLegend
std::string m_yLegend
Legend for the y axis.
Definition: gnuplot-helper.h:210
ns3::Probe
Base class for probes.
Definition: probe.h:40
ns3::GnuplotHelper::m_title
std::string m_title
Title string to use for this plot.
Definition: gnuplot-helper.h:204
NS_LOG_FUNCTION
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Definition: log-macros-enabled.h:244
ns3::ObjectFactory::SetTypeId
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
Definition: object-factory.cc:40
ns3::ObjectFactory::Create
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
Definition: object-factory.cc:98
ns3::GnuplotHelper::ConnectProbeToAggregator
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.
Definition: gnuplot-helper.cc:310
ns3::GetWildcardMatches
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: get-wildcard-matches.cc:29
ns3::GnuplotAggregator::KeyLocation
KeyLocation
The location of the key in the plot.
Definition: gnuplot-aggregator.h:43
ns3::TimeSeriesAdaptor::TraceSinkDouble
void TraceSinkDouble(double oldData, double newData)
Trace sink for receiving data from double valued trace sources.
Definition: time-series-adaptor.cc:63
ns3::GnuplotHelper::GetProbe
Ptr< Probe > GetProbe(std::string probeName) const
Gets the specified probe.
Definition: gnuplot-helper.cc:262
NS_ABORT_MSG
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
ns3::GnuplotHelper::m_probeMap
std::map< std::string, std::pair< Ptr< Probe >, std::string > > m_probeMap
Maps probe names to probes.
Definition: gnuplot-helper.h:192