Split contrib module into config-store and tools

This commit is contained in:
Mitch Watrous
2011-03-24 09:23:44 -07:00
parent 62607d311d
commit 8a8d425071
76 changed files with 890 additions and 6156 deletions

113
src/tools/model/average.h Normal file
View File

@@ -0,0 +1,113 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2009 IITP RAS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Authors: Pavel Boyko <boyko@iitp.ru>
* Corrections and extensions: Timo Bingmann <tbns@idlebox.net>
*/
#ifndef AVERAGE_H
#define AVERAGE_H
#include <cmath>
#include <ostream>
#include <limits>
#include <stdint.h>
namespace ns3 {
/// Simple average, min, max and std. deviation calculator
template <typename T = double>
class Average
{
public:
Average ()
: m_size (0), m_min (std::numeric_limits<T>::max ()), m_max (0),
m_avg (0), m_avg2 (0)
{
}
/// Add new sample
void Update (T const & x)
{
m_min = std::min (x, m_min);
m_max = std::max (x, m_max);
m_avg = (m_size * m_avg + x) / (m_size + 1);
m_avg2 = (m_size * m_avg2 + x * x) / (m_size + 1);
m_size++;
}
/// Reset statistics
void Reset ()
{
m_size = 0;
m_min = std::numeric_limits<T>::max ();
m_max = 0;
m_avg = 0;
m_avg2 = 0;
}
///\name Sample statistics
//\{
/// Sample size
uint32_t Count () const { return m_size; }
/// Minimum
T Min () const { return m_min; }
/// Maximum
T Max () const { return m_max; }
/// Sample average
double Avg () const { return m_avg; }
/// Estimate of mean, alias to Avg
double Mean () const { return Avg (); }
/// Unbiased estimate of variance
double Var () const { return Count() / (double)(Count() - 1) * (m_avg2 - m_avg*m_avg); }
/// Standard deviation
double Stddev () const { return sqrt (Var ());}
//\}
/**
* \name Error of the mean estimates
*
* Note that estimates are valid for
* - uncorrelated measurements,
* - normal distribution and
* - large enough sample size.
*/
//\{
/// Margin of error of the mean for 90% confidence level
double Error90() const { return 1.645 * sqrt (Var () / Count ()); }
/// Margin of error of the mean for 95% confidence level
double Error95() const { return 1.960 * sqrt (Var () / Count ()); }
/// Margin of error of the mean for 99% confidence level
double Error99() const { return 2.576 * sqrt (Var () / Count ()); }
//\}
private:
uint32_t m_size;
T m_min, m_max;
double m_avg, m_avg2;
};
/// Print avg (err) [min, max]
template <typename T>
std::ostream & operator<< (std::ostream & os, Average<T> const & x)
{
if (x.Count () != 0)
os << x.Avg () << " (" << x.Stddev () << ") [" << x.Min () << ", " << x.Max () << "]";
else
os << "NA"; // not available
return os;
}
}
#endif /* AVERAGE_H */

View File

@@ -0,0 +1,118 @@
#include "delay-jitter-estimation.h"
#include "ns3/tag.h"
#include "ns3/simulator.h"
#include "ns3/string.h"
namespace ns3 {
class DelayJitterEstimationTimestampTag : public Tag
{
public:
DelayJitterEstimationTimestampTag ();
static TypeId GetTypeId (void);
virtual TypeId GetInstanceTypeId (void) const;
virtual uint32_t GetSerializedSize (void) const;
virtual void Serialize (TagBuffer i) const;
virtual void Deserialize (TagBuffer i);
virtual void Print (std::ostream &os) const;
Time GetTxTime (void) const;
private:
uint64_t m_creationTime;
};
DelayJitterEstimationTimestampTag::DelayJitterEstimationTimestampTag ()
: m_creationTime (Simulator::Now ().GetTimeStep ())
{}
TypeId
DelayJitterEstimationTimestampTag::GetTypeId (void)
{
static TypeId tid = TypeId ("anon::DelayJitterEstimationTimestampTag")
.SetParent<Tag> ()
.AddConstructor<DelayJitterEstimationTimestampTag> ()
.AddAttribute ("CreationTime",
"The time at which the timestamp was created",
StringValue ("0.0s"),
MakeTimeAccessor (&DelayJitterEstimationTimestampTag::GetTxTime),
MakeTimeChecker ())
;
return tid;
}
TypeId
DelayJitterEstimationTimestampTag::GetInstanceTypeId (void) const
{
return GetTypeId ();
}
uint32_t
DelayJitterEstimationTimestampTag::GetSerializedSize (void) const
{
return 8;
}
void
DelayJitterEstimationTimestampTag::Serialize (TagBuffer i) const
{
i.WriteU64 (m_creationTime);
}
void
DelayJitterEstimationTimestampTag::Deserialize (TagBuffer i)
{
m_creationTime = i.ReadU64 ();
}
void
DelayJitterEstimationTimestampTag::Print (std::ostream &os) const
{
os << "CreationTime=" << m_creationTime;
}
Time
DelayJitterEstimationTimestampTag::GetTxTime (void) const
{
return TimeStep (m_creationTime);
}
DelayJitterEstimation::DelayJitterEstimation ()
: m_previousRx (Simulator::Now ()),
m_previousRxTx (Simulator::Now ()),
m_jitter (Seconds (0.0)),
m_delay (Seconds (0.0))
{}
void
DelayJitterEstimation::PrepareTx (Ptr<const Packet> packet)
{
DelayJitterEstimationTimestampTag tag;
packet->AddByteTag (tag);
}
void
DelayJitterEstimation::RecordRx (Ptr<const Packet> packet)
{
DelayJitterEstimationTimestampTag tag;
bool found;
found = packet->FindFirstMatchingByteTag (tag);
if (!found)
{
return;
}
tag.GetTxTime ();
Time delta = (Simulator::Now () - m_previousRx) - (tag.GetTxTime () - m_previousRxTx);
m_jitter += (Abs (delta) - m_jitter ) / Scalar (16.0);
m_previousRx = Simulator::Now ();
m_previousRxTx = tag.GetTxTime ();
m_delay = Simulator::Now () - tag.GetTxTime ();
}
Time
DelayJitterEstimation::GetLastDelay (void) const
{
return m_delay;
}
Time
DelayJitterEstimation::GetLastJitter (void) const
{
return m_jitter;
}
} // namespace ns3

View File

@@ -0,0 +1,59 @@
#ifndef DELAY_JITTER_ESTIMATION_H
#define DELAY_JITTER_ESTIMATION_H
#include "ns3/nstime.h"
#include "ns3/packet.h"
namespace ns3 {
/**
* \brief quick and dirty delay and jitter estimation
*
*/
class DelayJitterEstimation
{
public:
DelayJitterEstimation ();
/**
* \param packet the packet to send over a wire
*
* This method should be invoked once on each packet to
* record within the packet the tx time which is used upon
* packet reception to calculate the delay and jitter. The
* tx time is stored in the packet as an ns3::Tag which means
* that it does not use any network resources and is not
* taken into account in transmission delay calculations.
*/
static void PrepareTx (Ptr<const Packet> packet);
/**
* \param packet the packet received
*
* Invoke this method to update the delay and jitter calculations
* After a call to this method, \ref GetLastDelay and \ref GetLastJitter
* will return an updated delay and jitter.
*/
void RecordRx (Ptr<const Packet> packet);
/**
* \returns the updated delay.
*/
Time GetLastDelay (void) const;
/**
* The jitter is calculated using the RFC 1889 (RTP) jitter
* definition.
*
* \returns the updated jitter.
*/
Time GetLastJitter (void) const;
private:
Time m_previousRx;
Time m_previousRxTx;
Time m_jitter;
Time m_delay;
};
} // namespace ns3
#endif /* DELAY_JITTER_ESTIMATION_H */

View File

@@ -0,0 +1,155 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INESC Porto
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
*/
#include "event-garbage-collector.h"
#define CLEANUP_CHUNK_MIN_SIZE 8
#define CLEANUP_CHUNK_MAX_SIZE 128
namespace ns3 {
EventGarbageCollector::EventGarbageCollector () :
m_nextCleanupSize (CLEANUP_CHUNK_MIN_SIZE)
{}
void
EventGarbageCollector::Track (EventId event)
{
m_events.insert (event);
if (m_events.size () >= m_nextCleanupSize)
Cleanup ();
}
void
EventGarbageCollector::Grow ()
{
m_nextCleanupSize += (m_nextCleanupSize < CLEANUP_CHUNK_MAX_SIZE?
m_nextCleanupSize : CLEANUP_CHUNK_MAX_SIZE);
}
void
EventGarbageCollector::Shrink ()
{
while (m_nextCleanupSize > m_events.size ())
m_nextCleanupSize >>= 1;
Grow ();
}
// Called when a new event was added and the cleanup limit was exceeded in consequence.
void
EventGarbageCollector::Cleanup ()
{
for (EventList::iterator iter = m_events.begin (); iter != m_events.end ();)
{
if ((*iter).IsExpired ())
{
m_events.erase (iter++);
}
else
break; // EventIds are sorted by timestamp => further events are not expired for sure
}
// If after cleanup we are still over the limit, increase the limit.
if (m_events.size () >= m_nextCleanupSize)
Grow ();
else
Shrink ();
}
EventGarbageCollector::~EventGarbageCollector ()
{
for (EventList::iterator event = m_events.begin ();
event != m_events.end (); event++)
{
Simulator::Cancel (*event);
}
}
} // namespace ns3
#include "ns3/test.h"
namespace ns3 {
class EventGarbageCollectorTestCase : public TestCase
{
int m_counter;
EventGarbageCollector *m_events;
void EventGarbageCollectorCallback ();
public:
EventGarbageCollectorTestCase ();
virtual ~EventGarbageCollectorTestCase ();
virtual void DoRun (void);
};
EventGarbageCollectorTestCase::EventGarbageCollectorTestCase ()
: TestCase ("EventGarbageCollector"), m_counter (0), m_events (0)
{}
EventGarbageCollectorTestCase::~EventGarbageCollectorTestCase ()
{}
void
EventGarbageCollectorTestCase::EventGarbageCollectorCallback ()
{
m_counter++;
if (m_counter == 50)
{
// this should cause the remaining (50) events to be cancelled
delete m_events;
m_events = 0;
}
}
void EventGarbageCollectorTestCase::DoRun (void)
{
m_events = new EventGarbageCollector ();
for (int n = 0; n < 100; n++)
{
m_events->Track (Simulator::Schedule
(Simulator::Now (),
&EventGarbageCollectorTestCase::EventGarbageCollectorCallback,
this));
}
Simulator::Run ();
NS_TEST_EXPECT_MSG_EQ (m_events, 0, "");
NS_TEST_EXPECT_MSG_EQ (m_counter, 50, "");
Simulator::Destroy ();
}
static class EventGarbageCollectorTestSuite : public TestSuite
{
public:
EventGarbageCollectorTestSuite ()
: TestSuite ("event-garbage-collector", UNIT)
{
AddTestCase (new EventGarbageCollectorTestCase ());
}
} g_eventGarbageCollectorTests;
}

View File

@@ -0,0 +1,71 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INESC Porto
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
*/
#ifndef EVENT_GARBAGE_COLLECTOR_H
#define EVENT_GARBAGE_COLLECTOR_H
#include <set>
#include "ns3/event-id.h"
#include "ns3/simulator.h"
namespace ns3 {
/**
* \brief An object that tracks scheduled events and automatically
* cancels them when it is destroyed. It is useful in situations
* where multiple instances of the same type of event can
* simultaneously be scheduled, and when the events should be limited
* to the lifetime of a container object.
*/
class EventGarbageCollector
{
public:
EventGarbageCollector ();
/**
* \brief Tracks a new event
*/
void Track (EventId event);
~EventGarbageCollector ();
private:
struct EventIdLessThanTs
{
bool operator () (const EventId &a, const EventId &b) const
{
return (a.GetTs () < b.GetTs ());
}
};
typedef std::multiset<EventId, EventIdLessThanTs> EventList;
EventList::size_type m_nextCleanupSize;
EventList m_events;
void Cleanup ();
void Grow ();
void Shrink ();
};
}; // namespace ns3
#endif /* EVENT_GARBAGE_COLLECTOR_H */

733
src/tools/model/gnuplot.cc Normal file
View File

@@ -0,0 +1,733 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA, 2008 Timo Bingmann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Original Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
* Enhancements: Timo Bingmann <timo.bingmann@student.kit.edu>
*/
#include "gnuplot.h"
#include "ns3/assert.h"
#include <ostream>
#include <stdexcept>
namespace ns3 {
// --- GnuplotDataset::Data ------------------------------------------------ //
struct GnuplotDataset::Data
{
// *** Data Variables ***
unsigned int m_references;
std::string m_title;
std::string m_extra;
/**
* Initializes the reference counter to 1 and sets m_title and m_extra.
*/
Data(const std::string& title);
/// Required.
virtual ~Data();
/**
* Returns "plot" or "splot".
*/
virtual std::string GetCommand() const = 0;
/**
* Prints the plot description used as argument to (s)plot. Either the
* function expression or a datafile description. Should include m_title and
* m_extra in the output.
*/
virtual void PrintExpression(std::ostream &os) const = 0;
/**
* Print the inline data file contents trailing the plot command. Empty for
* functions.
*/
virtual void PrintDatafile(std::ostream &os) const = 0;
};
GnuplotDataset::Data::Data(const std::string& title)
: m_references(1),
m_title(title),
m_extra(m_defaultExtra)
{
}
GnuplotDataset::Data::~Data()
{
}
// --- GnuplotDataset ------------------------------------------------------ //
std::string GnuplotDataset::m_defaultExtra = "";
GnuplotDataset::GnuplotDataset (struct Data* data)
: m_data(data)
{
}
GnuplotDataset::GnuplotDataset (const GnuplotDataset& original)
: m_data(original.m_data)
{
++m_data->m_references;
}
GnuplotDataset::~GnuplotDataset()
{
if (--m_data->m_references == 0)
delete m_data;
}
GnuplotDataset& GnuplotDataset::operator= (const GnuplotDataset& original)
{
if (this != &original)
{
if (--m_data->m_references == 0)
delete m_data;
m_data = original.m_data;
++m_data->m_references;
}
return *this;
}
void
GnuplotDataset::SetTitle (const std::string& title)
{
m_data->m_title = title;
}
void
GnuplotDataset::SetDefaultExtra (const std::string& extra)
{
m_defaultExtra = extra;
}
void
GnuplotDataset::SetExtra (const std::string& extra)
{
m_data->m_extra = extra;
}
// --- Gnuplot2dDataset::Data2d -------------------------------------------- //
struct Gnuplot2dDataset::Data2d : public GnuplotDataset::Data
{
// *** Data Variables ***
enum Style m_style;
enum ErrorBars m_errorBars;
PointSet m_pointset;
/**
* Initializes with the values from m_defaultStyle and m_defaultErrorBars.
*/
Data2d(const std::string& title);
virtual std::string GetCommand() const;
virtual void PrintExpression(std::ostream &os) const;
virtual void PrintDatafile(std::ostream &os) const;
};
Gnuplot2dDataset::Data2d::Data2d(const std::string& title)
: Data(title),
m_style(m_defaultStyle),
m_errorBars(m_defaultErrorBars)
{
}
std::string
Gnuplot2dDataset::Data2d::GetCommand() const
{
return "plot";
}
void
Gnuplot2dDataset::Data2d::PrintExpression(std::ostream &os) const
{
os << "'-' ";
if (m_title.size())
os << " title '" << m_title << "'";
switch (m_style) {
case LINES:
os << " with lines";
break;
case POINTS:
switch (m_errorBars)
{
case NONE:
os << " with points";
break;
case X:
os << " with xerrorbars";
break;
case Y:
os << " with yerrorbars";
break;
case XY:
os << " with xyerrorbars";
break;
}
break;
case LINES_POINTS:
switch (m_errorBars)
{
case NONE:
os << " with linespoints";
break;
case X:
os << " with errorlines";
break;
case Y:
os << " with yerrorlines";
break;
case XY:
os << " with xyerrorlines";
break;
}
break;
case DOTS:
os << " with dots";
break;
case IMPULSES:
os << " with impulses";
break;
case STEPS:
os << " with steps";
break;
case FSTEPS:
os << " with fsteps";
break;
case HISTEPS:
os << " with histeps";
break;
}
if (m_extra.size())
os << " " << m_extra;
}
void
Gnuplot2dDataset::Data2d::PrintDatafile(std::ostream &os) const
{
for (PointSet::const_iterator i = m_pointset.begin ();
i != m_pointset.end (); ++i)
{
if (i->empty) {
os << std::endl;
continue;
}
switch (m_errorBars) {
case NONE:
os << i->x << " " << i->y << std::endl;
break;
case X:
os << i->x << " " << i->y << " " << i->dx << std::endl;
break;
case Y:
os << i->x << " " << i->y << " " << i->dy << std::endl;
break;
case XY:
os << i->x << " " << i->y << " " << i->dx << " " << i->dy << std::endl;
break;
}
}
os << "e" << std::endl;
}
// --- Gnuplot2dDataset ---------------------------------------------------- //
enum Gnuplot2dDataset::Style Gnuplot2dDataset::m_defaultStyle = LINES;
enum Gnuplot2dDataset::ErrorBars Gnuplot2dDataset::m_defaultErrorBars = NONE;
Gnuplot2dDataset::Gnuplot2dDataset (const std::string& title)
: GnuplotDataset( new Data2d(title) )
{
}
void
Gnuplot2dDataset::SetDefaultStyle (enum Style style)
{
m_defaultStyle = style;
}
void
Gnuplot2dDataset::SetStyle (enum Style style)
{
reinterpret_cast<Data2d*>(m_data)->m_style = style;
}
void
Gnuplot2dDataset::SetDefaultErrorBars (enum ErrorBars errorBars)
{
m_defaultErrorBars = errorBars;
}
void
Gnuplot2dDataset::SetErrorBars (enum ErrorBars errorBars)
{
reinterpret_cast<Data2d*>(m_data)->m_errorBars = errorBars;
}
void
Gnuplot2dDataset::Add (double x, double y)
{
NS_ASSERT (reinterpret_cast<Data2d*>(m_data)->m_errorBars == NONE);
struct Point data;
data.empty = false;
data.x = x;
data.y = y;
data.dx = 0.0;
data.dy = 0.0;
reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
}
void
Gnuplot2dDataset::Add (double x, double y, double errorDelta)
{
NS_ASSERT ( reinterpret_cast<Data2d*>(m_data)->m_errorBars == X ||
reinterpret_cast<Data2d*>(m_data)->m_errorBars == Y );
struct Point data;
data.empty = false;
data.x = x;
data.y = y;
data.dx = errorDelta;
data.dy = errorDelta;
reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
}
void
Gnuplot2dDataset::Add (double x, double y, double minY, double maxY)
{
NS_ASSERT ( reinterpret_cast<Data2d*>(m_data)->m_errorBars == X ||
reinterpret_cast<Data2d*>(m_data)->m_errorBars == Y );
struct Point data;
data.empty = false;
data.x = x;
data.y = y;
data.dx = minY;
data.dy = maxY;
reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
}
void
Gnuplot2dDataset::AddEmptyLine()
{
struct Point data;
data.empty = true;
reinterpret_cast<Data2d*>(m_data)->m_pointset.push_back (data);
}
// --- Gnuplot2dFunction::Function2d --------------------------------------- //
struct Gnuplot2dFunction::Function2d : public GnuplotDataset::Data
{
// *** Data Variables ***
std::string m_function;
/**
* Initializes with the function and title.
*/
Function2d(const std::string& title, const std::string& function);
virtual std::string GetCommand() const;
virtual void PrintExpression(std::ostream &os) const;
virtual void PrintDatafile(std::ostream &os) const;
};
Gnuplot2dFunction::Function2d::Function2d(const std::string& title, const std::string& function)
: Data(title),
m_function(function)
{
}
std::string
Gnuplot2dFunction::Function2d::GetCommand() const
{
return "plot";
}
void
Gnuplot2dFunction::Function2d::PrintExpression(std::ostream &os) const
{
os << m_function;
if (m_title.size())
os << " title '" << m_title << "'";
if (m_extra.size())
os << " " << m_extra;
}
void
Gnuplot2dFunction::Function2d::PrintDatafile(std::ostream &os) const
{
}
// --- Gnuplot2dFunction --------------------------------------------------- //
Gnuplot2dFunction::Gnuplot2dFunction (const std::string& title, const std::string& function)
: GnuplotDataset( new Function2d(title, function) )
{
}
void
Gnuplot2dFunction::SetFunction (const std::string& function)
{
reinterpret_cast<Function2d*>(m_data)->m_function = function;
}
// --- Gnuplot3dDataset::Data3d -------------------------------------------- //
struct Gnuplot3dDataset::Data3d : public GnuplotDataset::Data
{
// *** Data Variables ***
std::string m_style;
PointSet m_pointset;
/**
* Initializes with value from m_defaultStyle.
*/
Data3d(const std::string& title);
virtual std::string GetCommand() const;
virtual void PrintExpression(std::ostream &os) const;
virtual void PrintDatafile(std::ostream &os) const;
};
Gnuplot3dDataset::Data3d::Data3d(const std::string& title)
: Data(title),
m_style(m_defaultStyle)
{
}
std::string
Gnuplot3dDataset::Data3d::GetCommand() const
{
return "splot";
}
void
Gnuplot3dDataset::Data3d::PrintExpression(std::ostream &os) const
{
os << "'-' ";
if (m_style.size())
os << " " << m_style;
if (m_title.size())
os << " title '" << m_title << "'";
if (m_extra.size())
os << " " << m_extra;
}
void
Gnuplot3dDataset::Data3d::PrintDatafile(std::ostream &os) const
{
for (PointSet::const_iterator i = m_pointset.begin ();
i != m_pointset.end (); ++i)
{
if (i->empty) {
os << std::endl;
continue;
}
os << i->x << " " << i->y << " " << i->z << std::endl;
}
os << "e" << std::endl;
}
// --- Gnuplot3dDataset ---------------------------------------------------- //
std::string Gnuplot3dDataset::m_defaultStyle = "";
Gnuplot3dDataset::Gnuplot3dDataset (const std::string& title)
: GnuplotDataset( new Data3d(title) )
{
}
void
Gnuplot3dDataset::SetDefaultStyle (const std::string& style)
{
m_defaultStyle = style;
}
void
Gnuplot3dDataset::SetStyle (const std::string& style)
{
reinterpret_cast<Data3d*>(m_data)->m_style = style;
}
void
Gnuplot3dDataset::Add (double x, double y, double z)
{
struct Point data;
data.empty = false;
data.x = x;
data.y = y;
data.z = z;
reinterpret_cast<Data3d*>(m_data)->m_pointset.push_back (data);
}
void
Gnuplot3dDataset::AddEmptyLine()
{
struct Point data;
data.empty = true;
reinterpret_cast<Data3d*>(m_data)->m_pointset.push_back (data);
}
// --- Gnuplot3dFunction::Function3d --------------------------------------- //
struct Gnuplot3dFunction::Function3d : public GnuplotDataset::Data
{
// *** Data Variables ***
std::string m_function;
/**
* Initializes with the function and title.
*/
Function3d(const std::string& title, const std::string& function);
virtual std::string GetCommand() const;
virtual void PrintExpression(std::ostream &os) const;
virtual void PrintDatafile(std::ostream &os) const;
};
Gnuplot3dFunction::Function3d::Function3d(const std::string& title, const std::string& function)
: Data(title),
m_function(function)
{
}
std::string
Gnuplot3dFunction::Function3d::GetCommand() const
{
return "splot";
}
void
Gnuplot3dFunction::Function3d::PrintExpression(std::ostream &os) const
{
os << m_function;
if (m_title.size())
os << " title '" << m_title << "'";
if (m_extra.size())
os << " " << m_extra;
}
void
Gnuplot3dFunction::Function3d::PrintDatafile(std::ostream &os) const
{
}
// --- Gnuplot3dFunction --------------------------------------------------- //
Gnuplot3dFunction::Gnuplot3dFunction (const std::string& title, const std::string& function)
: GnuplotDataset( new Function3d(title, function) )
{
}
void
Gnuplot3dFunction::SetFunction (const std::string& function)
{
reinterpret_cast<Function3d*>(m_data)->m_function = function;
}
// ------------------------------------------------------------------------- //
Gnuplot::Gnuplot (const std::string& outputFilename, const std::string& title)
: m_outputFilename(outputFilename),
m_terminal( DetectTerminal(outputFilename) ),
m_title(title)
{
}
std::string Gnuplot::DetectTerminal (const std::string& filename)
{
std::string::size_type dotpos = filename.rfind('.');
if (dotpos == std::string::npos) return "";
if (filename.substr(dotpos) == ".png") {
return "png";
}
else if (filename.substr(dotpos) == ".pdf") {
return "pdf";
}
return "";
}
void
Gnuplot::SetTerminal (const std::string& terminal)
{
m_terminal = terminal;
}
void
Gnuplot::SetTitle (const std::string& title)
{
m_title = title;
}
void
Gnuplot::SetLegend (const std::string& xLegend, const std::string& yLegend)
{
m_xLegend = xLegend;
m_yLegend = yLegend;
}
void
Gnuplot::SetExtra (const std::string& extra)
{
m_extra = extra;
}
void
Gnuplot::AppendExtra (const std::string& extra)
{
m_extra += "\n";
m_extra += extra;
}
void
Gnuplot::AddDataset (const GnuplotDataset& dataset)
{
m_datasets.push_back (dataset);
}
void
Gnuplot::GenerateOutput (std::ostream &os) const
{
if (m_terminal.size())
os << "set terminal " << m_terminal << std::endl;
if (m_outputFilename.size())
os << "set output '" << m_outputFilename << "'" << std::endl;
if (m_title.size())
os << "set title '" << m_title << "'" << std::endl;
if (m_xLegend.size())
os << "set xlabel '" << m_xLegend << "'" << std::endl;
if (m_yLegend.size())
os << "set ylabel '" << m_yLegend << "'" << std::endl;
if (m_extra.size())
os << m_extra << std::endl;
if (m_datasets.empty())
return;
// Determine the GetCommand() values of all datasets included. Check that all
// are equal and print the command.
std::string command = m_datasets.begin()->m_data->GetCommand();
for (Datasets::const_iterator i = m_datasets.begin () + 1;
i != m_datasets.end (); ++i)
{
NS_ASSERT_MSG(command == i->m_data->GetCommand(),
"Cannot mix 'plot' and 'splot' GnuplotDatasets.");
}
os << command << " ";
// Print all dataset expressions
for (Datasets::const_iterator i = m_datasets.begin (); i != m_datasets.end ();)
{
i->m_data->PrintExpression(os);
i++;
if (i != m_datasets.end ())
{
os << ", ";
}
}
os << std::endl;
// followed by the inline datafile.
for (Datasets::const_iterator i = m_datasets.begin (); i != m_datasets.end (); i++)
{
i->m_data->PrintDatafile(os);
}
}
// ------------------------------------------------------------------------- //
GnuplotCollection::GnuplotCollection (const std::string& outputFilename)
: m_outputFilename(outputFilename),
m_terminal( Gnuplot::DetectTerminal(outputFilename) )
{
}
void
GnuplotCollection::SetTerminal (const std::string& terminal)
{
m_terminal = terminal;
}
void
GnuplotCollection::AddPlot (const Gnuplot& plot)
{
m_plots.push_back (plot);
}
Gnuplot&
GnuplotCollection::GetPlot(unsigned int id)
{
if (id >= m_plots.size())
throw(std::range_error("Gnuplot id is out of range"));
else
return m_plots[id];
}
void
GnuplotCollection::GenerateOutput (std::ostream &os) const
{
if (m_terminal.size())
os << "set terminal " << m_terminal << std::endl;
if (m_outputFilename.size())
os << "set output '" << m_outputFilename << "'" << std::endl;
for (Plots::const_iterator i = m_plots.begin (); i != m_plots.end (); ++i)
{
i->GenerateOutput (os);
}
}
// ------------------------------------------------------------------------- //
} // namespace ns3

460
src/tools/model/gnuplot.h Normal file
View File

@@ -0,0 +1,460 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA, 2008 Timo Bingmann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Original Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
* Enhancements: Timo Bingmann <timo.bingmann@student.kit.edu>
*/
#ifndef GNUPLOT_H
#define GNUPLOT_H
#include <string>
#include <vector>
#include <utility>
namespace ns3 {
/**
* \brief Abstract class to store a plot line to be used by ns3::Gnuplot.
*
* This class contains a reference counted data object in m_data. The data
* object contains different structs derived from struct Data by subclasses.
*/
class GnuplotDataset
{
public:
/**
* Reference-counting copy constructor.
*/
GnuplotDataset (const GnuplotDataset& original);
/**
* Reference-counting destructor.
*/
~GnuplotDataset();
/**
* Reference-counting assignment operator.
*/
GnuplotDataset& operator= (const GnuplotDataset& original);
/**
* \brief Change line title.
* \param title the new title string to use for this dataset.
*/
void SetTitle (const std::string& title);
/**
* \brief Change extra formatting style parameters for newly created objects.
* \param extra extra formatting
*/
static void SetDefaultExtra (const std::string& extra);
/**
* \brief Add extra formatting parameters to this dataset.
* \param extra extra formatting
*/
void SetExtra (const std::string& extra);
protected:
/// Friend because it accesses m_data and it's virtual functions directly in
/// GenerateOutput().
friend class Gnuplot;
/**
* \brief Extra gnuplot parameters set on every newly created dataset.
*/
static std::string m_defaultExtra;
/**
* \brief Derived classes subclass this struct and add their own data fields.
*/
struct Data;
/**
* Called by constructors of derived classes.
* \param data the reference counted data object representing this dataset.
*/
GnuplotDataset (struct Data* data);
/**
* Reference counted data object.
*/
struct Data* m_data;
};
/**
* \brief Class to represent a 2D points plot. Set the line or points style
* using SetStyle() and set points using Add().
*/
class Gnuplot2dDataset : public GnuplotDataset
{
public:
/**
* The plotting style to use for this dataset.
*/
enum Style {
LINES,
POINTS,
LINES_POINTS,
DOTS,
IMPULSES,
STEPS,
FSTEPS,
HISTEPS,
};
/**
* Whether errorbars should be used for this dataset.
*/
enum ErrorBars {
NONE,
X,
Y,
XY
};
/**
* \param title the title to be associated to this dataset.
*
* Create an empty dataset. Usually, the dataset's title is
* displayed in the legend box.
*/
Gnuplot2dDataset (const std::string& title = "Untitled");
/**
* Change default style for all newly created objects.
* \param style the style of plotting to use for newly created datasets.
*/
static void SetDefaultStyle (enum Style style);
/**
* \param style the style of plotting to use for this dataset.
*/
void SetStyle (enum Style style);
/**
* Change default errorbars style for all newly created objects.
* \param errorBars the style of errorbars to use for newly created datasets.
*/
static void SetDefaultErrorBars (enum ErrorBars errorBars);
/**
* \param errorBars the style of errorbars to display.
*
* If you use any style other than none, you need
* to make sure you store the delta information in
* this dataset with the right GnuplotDataset::Add
* method.
*/
void SetErrorBars (enum ErrorBars errorBars);
/**
* \param x x coord to new data point
* \param y y coord to new data point
*
* Use this method with error bar style NONE.
*/
void Add (double x, double y);
/**
* \param x x coord to new data point
* \param y y coord to new data point
* \param errorDelta data point error range.
*
* Use this method with error bar style X or Y.
*/
void Add (double x, double y, double errorDelta);
/**
* \param x x coord to new data point
* \param y y coord to new data point
* \param minY minimum error data point
* \param maxY maximum error data point
*
* Use this method with error bar style X or Y.
*/
void Add (double x, double y, double minY, double maxY);
/**
* Add an empty line in the data output sequence. Empty lines in the plot
* data break continuous lines and do other things in the output.
*/
void AddEmptyLine();
private:
struct Point {
bool empty;
double x;
double y;
double dx;
double dy;
};
typedef std::vector<struct Point> PointSet;
static enum Style m_defaultStyle;
static enum ErrorBars m_defaultErrorBars;
/// Forward declaration of the internal data class.
struct Data2d;
};
/**
* \brief Class to represent a 2D function expression plot.
*
* Since the function expression is not escaped, styles and extras could just
* as well be included in the expression string.
*/
class Gnuplot2dFunction : public GnuplotDataset
{
public:
/**
* \param title the title to be associated to this dataset.
* \param function function to plot
*
* Create an function dataset. Usually, the dataset's title is displayed in
* the legend box.
*/
Gnuplot2dFunction (const std::string& title = "Untitled", const std::string& function = "");
/**
* \param function new function string to set
*/
void SetFunction (const std::string& function);
private:
/// Forward declaration of the internal data class.
struct Function2d;
};
/**
* \brief Class to represent a 3D points plot. Set the line or points style
* using SetStyle() and set points using Add().
*/
class Gnuplot3dDataset : public GnuplotDataset
{
public:
/**
* \param title the title to be associated to this dataset.
*
* Create an empty dataset. Usually, the dataset's title is
* displayed in the legend box.
*/
Gnuplot3dDataset (const std::string& title = "Untitled");
/**
* Change default style for all newly created objects.
* \param style the style of plotting to use for newly created datasets.
*/
static void SetDefaultStyle (const std::string& style);
/**
* \param style the style of plotting to use for this dataset.
*/
void SetStyle (const std::string& style);
/**
* \param x x coord to new data point
* \param y y coord to new data point
* \param z z coord to new data point
*
* Use this method to add a new 3D point
*/
void Add (double x, double y, double z);
/**
* Add an empty line in the data output sequence. Empty lines in the plot
* data break continuous lines and do other things in the output.
*/
void AddEmptyLine();
private:
struct Point {
bool empty;
double x, y, z;
};
typedef std::vector<struct Point> PointSet;
static std::string m_defaultStyle;
/// Forward declaration of the internal data class.
struct Data3d;
};
/**
* \brief Class to represent a 3D function expression plot.
*
* Since the function expression is not escaped, styles and extras could just as
* well be included in the expression string. The only difference to
* Gnuplot2dFunction is the splot command string.
*/
class Gnuplot3dFunction : public GnuplotDataset
{
public:
/**
* \param title the title to be associated to this dataset.
* \param function function to plot
*
* Create an function dataset. Usually, the dataset's title is displayed in
* the legend box.
*/
Gnuplot3dFunction (const std::string& title = "Untitled", const std::string& function = "");
/**
* \param function new function string to set
*/
void SetFunction (const std::string& function);
private:
/// Forward declaration of the internal data class.
struct Function3d;
};
/**
* \brief a simple class to generate gnuplot-ready plotting commands
* from a set of datasets.
*
* This class really represents a single graph on which multiple datasets
* can be plotted.
*/
class Gnuplot
{
public:
/**
* \param outputFilename the name of the file where the rendering of the
* graph will be generated if you feed the command stream output by
* Gnuplot::GenerateOutput to the gnuplot program.
* \param title title line of the plot page
*/
Gnuplot (const std::string& outputFilename="", const std::string& title = "");
/**
* Crude attempt to auto-detect the correct terminal setting by inspecting
* the filename's extension.
* \param filename output file name
*/
static std::string DetectTerminal(const std::string& filename);
/**
* \param terminal terminal setting string for output. The default terminal
* string is "png"
*/
void SetTerminal (const std::string& terminal);
/**
* \param title set new plot title string to use for this plot.
*/
void SetTitle (const std::string& title);
/**
* \param xLegend the legend for the x horizontal axis
* \param yLegend the legend for the y vertical axis
*/
void SetLegend (const std::string& xLegend, const std::string& yLegend);
/**
* \param extra set extra gnuplot directive for output.
*/
void SetExtra (const std::string& extra);
/**
* \param extra append extra gnuplot directive for output.
*/
void AppendExtra (const std::string& extra);
/**
* \param dataset add a dataset to the graph to be plotted.
*/
void AddDataset (const GnuplotDataset& dataset);
/**
* \param os the output stream on which the relevant gnuplot commands should
* be generated. Including output file and terminal headers.
*/
void GenerateOutput (std::ostream &os) const;
private:
typedef std::vector<GnuplotDataset> Datasets;
std::string m_outputFilename;
std::string m_terminal;
Datasets m_datasets;
std::string m_title;
std::string m_xLegend;
std::string m_yLegend;
std::string m_extra;
};
/**
* \brief a simple class to group together multiple gnuplots into one file,
* e.g. for PDF multi-page output terminals.
*/
class GnuplotCollection
{
public:
/**
* \param outputFilename the name of the file where the rendering of the
* graph will be generated if you feed the command stream output by
* GnuplotCollection::GenerateOutput to the gnuplot program.
*/
GnuplotCollection (const std::string& outputFilename);
/**
* \param terminal terminal setting string for output. The default terminal
* string is guessed from the output filename's extension.
*/
void SetTerminal (const std::string& terminal);
/**
* \param plot add a plot to the collection to be plotted.
*/
void AddPlot (const Gnuplot& plot);
/**
* Return a pointer to one of the added plots.
* \param id index of plot to return
* \return reference to plot, throws std::range_error if it does not exist.
*/
Gnuplot& GetPlot(unsigned int id);
/**
* \param os the output stream on which the relevant gnuplot commands should
* be generated.
*/
void GenerateOutput (std::ostream &os) const;
private:
typedef std::vector<Gnuplot> Plots;
std::string m_outputFilename;
std::string m_terminal;
Plots m_plots;
};
} // namespace ns3
#endif /* GNUPLOT_H */

21
src/tools/wscript Normal file
View File

@@ -0,0 +1,21 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
module = bld.create_ns3_module('tools', ['network'])
module.source = [
'model/event-garbage-collector.cc',
'model/gnuplot.cc',
'model/delay-jitter-estimation.cc',
]
headers = bld.new_task_gen('ns3header')
headers.module = 'tools'
headers.source = [
'model/average.h',
'model/event-garbage-collector.h',
'model/gnuplot.h',
'model/delay-jitter-estimation.h',
]
bld.ns3_python_bindings()