A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 probe's path.
117  aggregator->SetTitle ( m_title + " \\n\\nProbe 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.
132  size_t lastSlash = path.find_last_of ("/");
133  if (lastSlash == std::string::npos)
134  {
135  pathWithoutLastToken = path;
136  lastToken = "";
137  }
138  else
139  {
140  // Chop off up to last token.
141  pathWithoutLastToken = path.substr (0, lastSlash);
142 
143  // Save the last token without the last slash.
144  lastToken = path.substr (lastSlash + 1, std::string::npos);
145  }
146 
147  // See if there are any matches for the probe's path with the last
148  // token removed.
149  Config::MatchContainer matches = Config::LookupMatches (pathWithoutLastToken);
150  uint32_t matchCount = matches.GetN ();
151 
152  // This is used to make the probe's context be unique.
153  std::string matchIdentifier;
154 
155  // Hook one or more probes and the aggregator together.
156  if (matchCount == 1 && pathHasNoWildcards)
157  {
158  // Connect the probe to the aggregator only once because there
159  // is only one matching config path. There is no need to find
160  // the wildcard matches because the passed in path has none.
161  matchIdentifier = "0";
162  ConnectProbeToAggregator (typeId,
163  matchIdentifier,
164  path,
165  probeTraceSource,
166  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,
183  matchedPath,
184  wildcardSeparator);
185 
186  // Connect the probe to the aggregator for this match.
187  ConnectProbeToAggregator (typeId,
188  matchIdentifier,
189  matchedPath,
190  probeTraceSource,
191  title + "-" + wildcardMatches);
192  }
193  }
194  else
195  {
196  // There is a problem if there are no matching config paths.
197  NS_FATAL_ERROR ("Lookup of " << path << " got no matches");
198  }
199 }
200 
201 void
202 GnuplotHelper::AddProbe (const std::string &typeId,
203  const std::string &probeName,
204  const std::string &path)
205 {
206  NS_LOG_FUNCTION (this << typeId << probeName << path);
207 
208  // See if this probe had already been added.
209  if (m_probeMap.count (probeName) > 0)
210  {
211  NS_ABORT_MSG ("That probe has already been added");
212  }
213 
214  // Prepare the factory to create an object with the requested type.
215  m_factory.SetTypeId (typeId);
216 
217  // Create a base class object in order to validate the type.
218  Ptr<Probe> probe = m_factory.Create ()->GetObject<Probe> ();
219  if (probe == 0)
220  {
221  NS_ABORT_MSG ("The requested type is not a probe");
222  }
223 
224  // Set the probe's name.
225  probe->SetName (probeName);
226 
227  // Set the path. Note that no return value is checked here.
228  probe->ConnectByPath (path);
229 
230  // Enable logging of data for the probe.
231  probe->Enable ();
232 
233  // Add this probe to the map so that its values can be used.
234  m_probeMap[probeName] = std::make_pair (probe, typeId);
235 }
236 
237 void
238 GnuplotHelper::AddTimeSeriesAdaptor (const std::string &adaptorName)
239 {
240  NS_LOG_FUNCTION (this << adaptorName);
241 
242  // See if this time series adaptor had already been added.
243  if (m_timeSeriesAdaptorMap.count (adaptorName) > 0)
244  {
245  NS_ABORT_MSG ("That time series adaptor has already been added");
246  }
247 
248  // Create the time series adaptor.
249  Ptr<TimeSeriesAdaptor> timeSeriesAdaptor = CreateObject<TimeSeriesAdaptor> ();
250 
251  // Enable logging of data for the time series adaptor.
252  timeSeriesAdaptor->Enable ();
253 
254  // Add this time series adaptor to the map so that can be used.
255  m_timeSeriesAdaptorMap[adaptorName] = timeSeriesAdaptor;
256 }
257 
259 GnuplotHelper::GetProbe (std::string probeName) const
260 {
261  // Look for the probe.
262  std::map<std::string, std::pair <Ptr<Probe>, std::string> >::const_iterator mapIterator = m_probeMap.find (probeName);
263 
264  // Return the probe if it has been added.
265  if (mapIterator != m_probeMap.end ())
266  {
267  return mapIterator->second.first;
268  }
269  else
270  {
271  NS_ABORT_MSG ("That probe has not been added");
272  }
273 }
274 
277 {
278  NS_LOG_FUNCTION (this);
279 
280  // Do a lazy construction of the aggregator if it hasn't already
281  // been constructed.
282  if (!m_aggregator)
283  {
285  }
286  return m_aggregator;
287 }
288 
289 void
291 {
292  NS_LOG_FUNCTION (this);
293 
294  // Create the aggregator.
295  m_aggregator = CreateObject<GnuplotAggregator> (m_outputFileNameWithoutExtension);
296 
297  // Set the aggregator's properties.
298  m_aggregator->SetTerminal (m_terminalType);
299  m_aggregator->SetTitle (m_title);
300  m_aggregator->SetLegend (m_xLegend, m_yLegend);
301 
302  // Enable logging of data for the aggregator.
303  m_aggregator->Enable ();
304 }
305 
306 void
307 GnuplotHelper::ConnectProbeToAggregator (const std::string &typeId,
308  const std::string &matchIdentifier,
309  const std::string &path,
310  const std::string &probeTraceSource,
311  const std::string &title)
312 {
313  NS_LOG_FUNCTION (this << typeId << matchIdentifier << path << probeTraceSource
314  << title);
315 
316  Ptr<GnuplotAggregator> aggregator = GetAggregator ();
317 
318  // Increment the total number of plot probes that have been created.
320 
321  // Create a unique name for this probe.
322  std::ostringstream probeNameStream;
323  probeNameStream << "PlotProbe-" << m_plotProbeCount;
324  std::string probeName = probeNameStream.str ();
325 
326  // Create a unique dataset context string for this probe.
327  std::string probeContext = probeName
328  + "/" + matchIdentifier + "/" + probeTraceSource;
329 
330  // Add the probe to the map of probes, which will keep the probe in
331  // memory after this function ends.
332  AddProbe (typeId, probeName, path);
333 
334  // Because the callbacks to the probes' trace sources don't use the
335  // probe's context, a unique adaptor needs to be created for each
336  // probe context so that information is not lost.
337  AddTimeSeriesAdaptor (probeContext);
338 
339  // Connect the probe to the adaptor.
340  if (m_probeMap[probeName].second == "ns3::DoubleProbe")
341  {
342  m_probeMap[probeName].first->TraceConnectWithoutContext
343  (probeTraceSource,
345  m_timeSeriesAdaptorMap[probeContext]));
346  }
347  else if (m_probeMap[probeName].second == "ns3::BooleanProbe")
348  {
349  m_probeMap[probeName].first->TraceConnectWithoutContext
350  (probeTraceSource,
352  m_timeSeriesAdaptorMap[probeContext]));
353  }
354  else if (m_probeMap[probeName].second == "ns3::PacketProbe")
355  {
356  m_probeMap[probeName].first->TraceConnectWithoutContext
357  (probeTraceSource,
359  m_timeSeriesAdaptorMap[probeContext]));
360  }
361  else if (m_probeMap[probeName].second == "ns3::ApplicationPacketProbe")
362  {
363  m_probeMap[probeName].first->TraceConnectWithoutContext
364  (probeTraceSource,
366  m_timeSeriesAdaptorMap[probeContext]));
367  }
368  else if (m_probeMap[probeName].second == "ns3::Ipv4PacketProbe")
369  {
370  m_probeMap[probeName].first->TraceConnectWithoutContext
371  (probeTraceSource,
373  m_timeSeriesAdaptorMap[probeContext]));
374  }
375  else if (m_probeMap[probeName].second == "ns3::Ipv6PacketProbe")
376  {
377  m_probeMap[probeName].first->TraceConnectWithoutContext
378  (probeTraceSource,
380  m_timeSeriesAdaptorMap[probeContext]));
381  }
382  else if (m_probeMap[probeName].second == "ns3::Uinteger8Probe")
383  {
384  m_probeMap[probeName].first->TraceConnectWithoutContext
385  (probeTraceSource,
387  m_timeSeriesAdaptorMap[probeContext]));
388  }
389  else if (m_probeMap[probeName].second == "ns3::Uinteger16Probe")
390  {
391  m_probeMap[probeName].first->TraceConnectWithoutContext
392  (probeTraceSource,
394  m_timeSeriesAdaptorMap[probeContext]));
395  }
396  else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe")
397  {
398  m_probeMap[probeName].first->TraceConnectWithoutContext
399  (probeTraceSource,
401  m_timeSeriesAdaptorMap[probeContext]));
402  }
403  else
404  {
405  NS_FATAL_ERROR ("Unknown probe type " << m_probeMap[probeName].second << "; need to add support in the helper for this");
406  }
407 
408  // Connect the adaptor to the aggregator.
409  std::string adaptorTraceSource = "Output";
410  m_timeSeriesAdaptorMap[probeContext]->TraceConnect
411  (adaptorTraceSource,
412  probeContext,
414 
415  // Add the dataset to the plot.
416  aggregator->Add2dDataset (probeContext, title);
417 }
418 
419 } // namespace ns3
420 
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.
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:60
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
#define NS_ABORT_MSG(msg)
Abnormal program termination.
Definition: abort.h:44
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)
void AddTimeSeriesAdaptor(const std::string &adaptorName)
Adds a time series adaptor to be used to make the plot.
std::map< std::string, std::pair< Ptr< Probe >, std::string > > m_probeMap
Maps probe names to probes.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:170
void SetTypeId(TypeId tid)
void Write2d(std::string context, double x, double y)
Writes a 2D value to a 2D gnuplot dataset.
std::string GetMatchedPath(uint32_t i) const
Definition: config.cc:75
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:95
std::string m_xLegend
Legend for the x axis.
GnuplotHelper()
Constructs a gnuplot helper that will create a space separated gnuplot data file named "gnuplot-helpe...
uint32_t m_plotProbeCount
Number of plot probes that have been created.
ObjectFactory m_factory
Used to create the probes and collectors as they are added.
virtual ~GnuplotHelper()
std::string m_outputFileNameWithoutExtension
The name of the output file to created without its extension.
void ConfigurePlot(const std::string &outputFileNameWithoutExtension, const std::string &title, const std::string &xLegend, const std::string &yLegend, const std::string &terminalType="png")
Config::MatchContainer LookupMatches(std::string path)
Definition: config.cc:739
Ptr< GnuplotAggregator > m_aggregator
The aggregator used to make the plots.
Ptr< Object > Create(void) const
void AddProbe(const std::string &typeId, const std::string &probeName, const std::string &path)
Adds a probe to be used to make the plot.
std::map< std::string, Ptr< TimeSeriesAdaptor > > m_timeSeriesAdaptorMap
Maps time series adaptor names to time series adaptors.
void ConstructAggregator()
Constructs the aggregator.
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1242
void TraceSinkUinteger32(uint32_t oldData, uint32_t newData)
Trace sink for receiving data from uint32_t valued trace sources.
uint32_t GetN(void) const
Definition: config.cc:63
Ptr< GnuplotAggregator > GetAggregator()
Gets the aggregator.
void TraceSinkUinteger8(uint8_t oldData, uint8_t newData)
Trace sink for receiving data from uint8_t valued trace sources.
hold a set of objects which match a specific search string.
Definition: config.h:127
KeyLocation
The location of the key in the plot.
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:203
void TraceSinkUinteger16(uint16_t oldData, uint16_t newData)
Trace sink for receiving data from uint16_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.
Ptr< Probe > GetProbe(std::string probeName) const
Gets the specified probe.
std::string m_yLegend
Legend for the y axis.
Ptr< T > GetObject(void) const
Definition: object.h:362
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...
Base class for probes.
Definition: probe.h:39
std::string m_title
Title string to use for this plot.
std::string m_terminalType
Terminal type for the plot.