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  ;
37 
39  : m_aggregator (0),
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 
53 GnuplotHelper::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 (0),
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 
77 void
78 GnuplotHelper::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
85  << xLegend << yLegend << terminalType);
86 
87  // See if an aggregator has already been constructed.
88  if (m_aggregator != 0)
89  {
90  NS_LOG_WARN ("An existing aggregator object " << m_aggregator <<
91  " 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 
105 void
106 GnuplotHelper::PlotProbe (const std::string &typeId,
107  const std::string &path,
108  const std::string &probeTraceSource,
109  const std::string &title,
110  enum GnuplotAggregator::KeyLocation keyLocation)
111 {
112  NS_LOG_FUNCTION (this << typeId << path << probeTraceSource << title << keyLocation);
113 
114  // Get a pointer to the aggregator.
115  Ptr<GnuplotAggregator> aggregator = GetAggregator ();
116 
117  // Add a subtitle to the title to show the probe's path.
118  aggregator->SetTitle ( m_title + " \\n\\nProbe 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.
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.
150  Config::MatchContainer matches = Config::LookupMatches (pathWithoutLastToken);
151  uint32_t matchCount = matches.GetN ();
152 
153  // This is used to make the probe's context be unique.
154  std::string matchIdentifier;
155 
156  // Hook one or more probes and the aggregator together.
157  if (matchCount == 1 && pathHasNoWildcards)
158  {
159  // Connect the probe to the aggregator only once because there
160  // is only one matching config path. There is no need to find
161  // the wildcard matches because the passed in path has none.
162  matchIdentifier = "0";
163  ConnectProbeToAggregator (typeId,
164  matchIdentifier,
165  path,
166  probeTraceSource,
167  title);
168  }
169  else if (matchCount > 0)
170  {
171  // Handle all of the matches if there are more than one.
172  for (uint32_t i = 0; i < matchCount; i++)
173  {
174  // Set the match identifier.
175  std::ostringstream matchIdentifierStream;
176  matchIdentifierStream << i;
177  matchIdentifier = matchIdentifierStream.str ();
178 
179  // Construct the matched path and get the matches for each
180  // of the wildcards.
181  std::string wildcardSeparator = " ";
182  std::string matchedPath = matches.GetMatchedPath (i) + lastToken;
183  std::string wildcardMatches = GetWildcardMatches (path,
184  matchedPath,
185  wildcardSeparator);
186 
187  // Connect the probe to the aggregator for this match.
188  ConnectProbeToAggregator (typeId,
189  matchIdentifier,
190  matchedPath,
191  probeTraceSource,
192  title + "-" + wildcardMatches);
193  }
194  }
195  else
196  {
197  // There is a problem if there are no matching config paths.
198  NS_FATAL_ERROR ("Lookup of " << path << " got no matches");
199  }
200 }
201 
202 void
203 GnuplotHelper::AddProbe (const std::string &typeId,
204  const std::string &probeName,
205  const std::string &path)
206 {
207  NS_LOG_FUNCTION (this << typeId << probeName << path);
208 
209  // See if this probe had already been added.
210  if (m_probeMap.count (probeName) > 0)
211  {
212  NS_ABORT_MSG ("That probe has already been added");
213  }
214 
215  // Prepare the factory to create an object with the requested type.
216  m_factory.SetTypeId (typeId);
217 
218  // Create a base class object in order to validate the type.
219  Ptr<Probe> probe = m_factory.Create ()->GetObject<Probe> ();
220  if (probe == 0)
221  {
222  NS_ABORT_MSG ("The requested type is not a probe");
223  }
224 
225  // Set the probe's name.
226  probe->SetName (probeName);
227 
228  // Set the path. Note that no return value is checked here.
229  probe->ConnectByPath (path);
230 
231  // Enable logging of data for the probe.
232  probe->Enable ();
233 
234  // Add this probe to the map so that its values can be used.
235  m_probeMap[probeName] = std::make_pair (probe, typeId);
236 }
237 
238 void
239 GnuplotHelper::AddTimeSeriesAdaptor (const std::string &adaptorName)
240 {
241  NS_LOG_FUNCTION (this << adaptorName);
242 
243  // See if this time series adaptor had already been added.
244  if (m_timeSeriesAdaptorMap.count (adaptorName) > 0)
245  {
246  NS_ABORT_MSG ("That time series adaptor has already been added");
247  }
248 
249  // Create the time series adaptor.
250  Ptr<TimeSeriesAdaptor> timeSeriesAdaptor = CreateObject<TimeSeriesAdaptor> ();
251 
252  // Enable logging of data for the time series adaptor.
253  timeSeriesAdaptor->Enable ();
254 
255  // Add this time series adaptor to the map so that can be used.
256  m_timeSeriesAdaptorMap[adaptorName] = timeSeriesAdaptor;
257 }
258 
260 GnuplotHelper::GetProbe (std::string probeName) const
261 {
262  // Look for the probe.
263  std::map<std::string, std::pair <Ptr<Probe>, std::string> >::const_iterator mapIterator = m_probeMap.find (probeName);
264 
265  // Return the probe if it has been added.
266  if (mapIterator != m_probeMap.end ())
267  {
268  return mapIterator->second.first;
269  }
270  else
271  {
272  NS_ABORT_MSG ("That probe has not been added");
273  }
274 }
275 
278 {
279  NS_LOG_FUNCTION (this);
280 
281  // Do a lazy construction of the aggregator if it hasn't already
282  // been constructed.
283  if (!m_aggregator)
284  {
286  }
287  return m_aggregator;
288 }
289 
290 void
292 {
293  NS_LOG_FUNCTION (this);
294 
295  // Create the aggregator.
296  m_aggregator = CreateObject<GnuplotAggregator> (m_outputFileNameWithoutExtension);
297 
298  // Set the aggregator's properties.
299  m_aggregator->SetTerminal (m_terminalType);
300  m_aggregator->SetTitle (m_title);
301  m_aggregator->SetLegend (m_xLegend, m_yLegend);
302 
303  // Enable logging of data for the aggregator.
304  m_aggregator->Enable ();
305 }
306 
307 void
308 GnuplotHelper::ConnectProbeToAggregator (const std::string &typeId,
309  const std::string &matchIdentifier,
310  const std::string &path,
311  const std::string &probeTraceSource,
312  const std::string &title)
313 {
314  NS_LOG_FUNCTION (this << typeId << matchIdentifier << path << probeTraceSource
315  << title);
316 
317  Ptr<GnuplotAggregator> aggregator = GetAggregator ();
318 
319  // Increment the total number of plot probes that have been created.
321 
322  // Create a unique name for this probe.
323  std::ostringstream probeNameStream;
324  probeNameStream << "PlotProbe-" << m_plotProbeCount;
325  std::string probeName = probeNameStream.str ();
326 
327  // Create a unique dataset context string for this probe.
328  std::string probeContext = probeName
329  + "/" + matchIdentifier + "/" + probeTraceSource;
330 
331  // Add the probe to the map of probes, which will keep the probe in
332  // memory after this function ends.
333  AddProbe (typeId, probeName, path);
334 
335  // Because the callbacks to the probes' trace sources don't use the
336  // probe's context, a unique adaptor needs to be created for each
337  // probe context so that information is not lost.
338  AddTimeSeriesAdaptor (probeContext);
339 
340  // Connect the probe to the adaptor.
341  if (m_probeMap[probeName].second == "ns3::DoubleProbe")
342  {
343  m_probeMap[probeName].first->TraceConnectWithoutContext
344  (probeTraceSource,
346  m_timeSeriesAdaptorMap[probeContext]));
347  }
348  else if (m_probeMap[probeName].second == "ns3::BooleanProbe")
349  {
350  m_probeMap[probeName].first->TraceConnectWithoutContext
351  (probeTraceSource,
353  m_timeSeriesAdaptorMap[probeContext]));
354  }
355  else if (m_probeMap[probeName].second == "ns3::PacketProbe")
356  {
357  m_probeMap[probeName].first->TraceConnectWithoutContext
358  (probeTraceSource,
360  m_timeSeriesAdaptorMap[probeContext]));
361  }
362  else if (m_probeMap[probeName].second == "ns3::ApplicationPacketProbe")
363  {
364  m_probeMap[probeName].first->TraceConnectWithoutContext
365  (probeTraceSource,
367  m_timeSeriesAdaptorMap[probeContext]));
368  }
369  else if (m_probeMap[probeName].second == "ns3::Ipv4PacketProbe")
370  {
371  m_probeMap[probeName].first->TraceConnectWithoutContext
372  (probeTraceSource,
374  m_timeSeriesAdaptorMap[probeContext]));
375  }
376  else if (m_probeMap[probeName].second == "ns3::Ipv6PacketProbe")
377  {
378  m_probeMap[probeName].first->TraceConnectWithoutContext
379  (probeTraceSource,
381  m_timeSeriesAdaptorMap[probeContext]));
382  }
383  else if (m_probeMap[probeName].second == "ns3::Uinteger8Probe")
384  {
385  m_probeMap[probeName].first->TraceConnectWithoutContext
386  (probeTraceSource,
388  m_timeSeriesAdaptorMap[probeContext]));
389  }
390  else if (m_probeMap[probeName].second == "ns3::Uinteger16Probe")
391  {
392  m_probeMap[probeName].first->TraceConnectWithoutContext
393  (probeTraceSource,
395  m_timeSeriesAdaptorMap[probeContext]));
396  }
397  else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe")
398  {
399  m_probeMap[probeName].first->TraceConnectWithoutContext
400  (probeTraceSource,
402  m_timeSeriesAdaptorMap[probeContext]));
403  }
404  else
405  {
406  NS_FATAL_ERROR ("Unknown probe type " << m_probeMap[probeName].second << "; need to add support in the helper for this");
407  }
408 
409  // Connect the adaptor to the aggregator.
410  std::string adaptorTraceSource = "Output";
411  m_timeSeriesAdaptorMap[probeContext]->TraceConnect
412  (adaptorTraceSource,
413  probeContext,
415 
416  // Add the dataset to the plot.
417  aggregator->Add2dDataset (probeContext, title);
418 }
419 
420 } // namespace ns3
421 
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:59
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:345
NS_LOG_COMPONENT_DEFINE("GrantedTimeWindowMpiInterface")
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.
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
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()
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:72
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:1238
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
#define NS_ABORT_MSG(msg)
Abnormal program termination.
Definition: abort.h:43
KeyLocation
The location of the key in the plot.
#define NS_LOG_WARN(msg)
Definition: log.h:280
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:361
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.