data collection extensions for stats module

This commit is contained in:
Tom Henderson
2013-08-08 06:40:41 -07:00
parent fe13017646
commit 2a08426b17
53 changed files with 7212 additions and 63 deletions

View File

@@ -36,6 +36,10 @@ massif.*
\.patch$
\.diff$
\.tr$
\.txt$
\.sh$
\.dat$
\.plt$
\#[^\#/]+\#$
^coverity
syntax: glob

View File

@@ -15,6 +15,7 @@ cpp_examples = [
("fourth", "True", "True"),
("fifth", "True", "True"),
("sixth", "True", "True"),
("seventh", "True", "True"),
]
# A list of Python examples to run in order to ensure that they remain

View File

@@ -0,0 +1,267 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* 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
*/
#include <fstream>
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/stats-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("SeventhScriptExample");
// ===========================================================================
//
// node 0 node 1
// +----------------+ +----------------+
// | ns-3 TCP | | ns-3 TCP |
// +----------------+ +----------------+
// | 10.1.1.1 | | 10.1.1.2 |
// +----------------+ +----------------+
// | point-to-point | | point-to-point |
// +----------------+ +----------------+
// | |
// +---------------------+
// 5 Mbps, 2 ms
//
//
// We want to look at changes in the ns-3 TCP congestion window. We need
// to crank up a flow and hook the CongestionWindow attribute on the socket
// of the sender. Normally one would use an on-off application to generate a
// flow, but this has a couple of problems. First, the socket of the on-off
// application is not created until Application Start time, so we wouldn't be
// able to hook the socket (now) at configuration time. Second, even if we
// could arrange a call after start time, the socket is not public so we
// couldn't get at it.
//
// So, we can cook up a simple version of the on-off application that does what
// we want. On the plus side we don't need all of the complexity of the on-off
// application. On the minus side, we don't have a helper, so we have to get
// a little more involved in the details, but this is trivial.
//
// So first, we create a socket and do the trace connect on it; then we pass
// this socket into the constructor of our simple application which we then
// install in the source node.
// ===========================================================================
//
class MyApp : public Application
{
public:
MyApp ();
virtual ~MyApp ();
void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);
private:
virtual void StartApplication (void);
virtual void StopApplication (void);
void ScheduleTx (void);
void SendPacket (void);
Ptr<Socket> m_socket;
Address m_peer;
uint32_t m_packetSize;
uint32_t m_nPackets;
DataRate m_dataRate;
EventId m_sendEvent;
bool m_running;
uint32_t m_packetsSent;
};
MyApp::MyApp ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nPackets (0),
m_dataRate (0),
m_sendEvent (),
m_running (false),
m_packetsSent (0)
{
}
MyApp::~MyApp ()
{
m_socket = 0;
}
void
MyApp::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate)
{
m_socket = socket;
m_peer = address;
m_packetSize = packetSize;
m_nPackets = nPackets;
m_dataRate = dataRate;
}
void
MyApp::StartApplication (void)
{
m_running = true;
m_packetsSent = 0;
m_socket->Bind ();
m_socket->Connect (m_peer);
SendPacket ();
}
void
MyApp::StopApplication (void)
{
m_running = false;
if (m_sendEvent.IsRunning ())
{
Simulator::Cancel (m_sendEvent);
}
if (m_socket)
{
m_socket->Close ();
}
}
void
MyApp::SendPacket (void)
{
Ptr<Packet> packet = Create<Packet> (m_packetSize);
m_socket->Send (packet);
if (++m_packetsSent < m_nPackets)
{
ScheduleTx ();
}
}
void
MyApp::ScheduleTx (void)
{
if (m_running)
{
Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
}
}
static void
CwndChange (Ptr<OutputStreamWrapper> stream, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
}
static void
RxDrop (Ptr<PcapFileWrapper> file, Ptr<const Packet> p)
{
NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
file->Write (Simulator::Now (), p);
}
int
main (int argc, char *argv[])
{
NodeContainer nodes;
nodes.Create (2);
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
Ptr<RateErrorModel> em = CreateObject<RateErrorModel> ();
em->SetAttribute ("ErrorRate", DoubleValue (0.00001));
devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
InternetStackHelper stack;
stack.Install (nodes);
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.252");
Ipv4InterfaceContainer interfaces = address.Assign (devices);
uint16_t sinkPort = 8080;
Address sinkAddress (InetSocketAddress (interfaces.GetAddress (1), sinkPort));
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
sinkApps.Start (Seconds (0.));
sinkApps.Stop (Seconds (20.));
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ());
Ptr<MyApp> app = CreateObject<MyApp> ();
app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
nodes.Get (0)->AddApplication (app);
app->SetStartTime (Seconds (1.));
app->SetStopTime (Seconds (20.));
AsciiTraceHelper asciiTraceHelper;
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("seventh.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));
PcapHelper pcapHelper;
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile ("seventh.pcap", std::ios::out, PcapHelper::DLT_PPP);
devices.Get (1)->TraceConnectWithoutContext ("PhyRxDrop", MakeBoundCallback (&RxDrop, file));
// Use GnuplotHelper to plot the packet byte count over time
GnuplotHelper plotHelper;
// Configure the plot. The first argument is the file name prefix
// for the output files generated. The second, third, and fourth
// arguments are, respectively, the plot title, x-axis, and y-axis labels
plotHelper.ConfigurePlot ("seventh-packet-byte-count",
"Packet Byte Count vs. Time",
"Time (Seconds)",
"Packet Byte Count");
// Specify the probe type, probe path (in configuration namespace), and
// probe output trace source ("OutputBytes") to plot. The fourth argument
// specifies the name of the data series label on the plot. The last
// argument formats the plot by specifying where the key should be placed.
plotHelper.PlotProbe ("ns3::Ipv4PacketProbe",
"/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
"OutputBytes",
"Packet Byte Count",
GnuplotAggregator::KEY_BELOW);
// Use FileHelper to write out the packet byte count over time
FileHelper fileHelper;
// Configure the file to be written, and the formatting of output data.
fileHelper.ConfigureFile ("seventh-packet-byte-count",
FileAggregator::FORMATTED);
// Set the labels for this formatted output file.
fileHelper.Set2dFormat ("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");
// Specify the probe type, probe path (in configuration namespace), and
// probe output trace source ("OutputBytes") to write.
fileHelper.WriteProbe ("ns3::Ipv4PacketProbe",
"/NodeList/*/$ns3::Ipv4L3Protocol/Tx",
"OutputBytes");
Simulator::Stop (Seconds (20));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}

View File

@@ -23,3 +23,6 @@ def build(bld):
obj = bld.create_ns3_program('sixth', ['core', 'point-to-point', 'internet', 'applications'])
obj.source = 'sixth.cc'
obj = bld.create_ns3_program('seventh', ['core', 'stats', 'point-to-point', 'internet', 'applications'])
obj.source = 'seventh.cc'

View File

@@ -0,0 +1,119 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#include "ns3/application-packet-probe.h"
#include "ns3/object.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/config.h"
#include "ns3/trace-source-accessor.h"
NS_LOG_COMPONENT_DEFINE ("ApplicationPacketProbe");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (ApplicationPacketProbe);
TypeId
ApplicationPacketProbe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::ApplicationPacketProbe")
.SetParent<Probe> ()
.AddConstructor<ApplicationPacketProbe> ()
.AddTraceSource ( "Output",
"The packet plus its socket address that serve as the output for this probe",
MakeTraceSourceAccessor (&ApplicationPacketProbe::m_output))
.AddTraceSource ( "OutputBytes",
"The number of bytes in the packet",
MakeTraceSourceAccessor (&ApplicationPacketProbe::m_outputBytes))
;
return tid;
}
ApplicationPacketProbe::ApplicationPacketProbe ()
{
NS_LOG_FUNCTION (this);
m_packet = 0;
}
ApplicationPacketProbe::~ApplicationPacketProbe ()
{
NS_LOG_FUNCTION (this);
}
void
ApplicationPacketProbe::SetValue (Ptr<const Packet> packet, const Address& address)
{
NS_LOG_FUNCTION (this << packet << address);
m_packet = packet;
m_address = address;
m_output (packet, address);
uint32_t packetSizeNew = packet->GetSize ();
m_outputBytes (m_packetSizeOld, packetSizeNew);
m_packetSizeOld = packetSizeNew;
}
void
ApplicationPacketProbe::SetValueByPath (std::string path, Ptr<const Packet> packet, const Address& address)
{
NS_LOG_FUNCTION (path << packet << address);
Ptr<ApplicationPacketProbe> probe = Names::Find<ApplicationPacketProbe> (path);
NS_ASSERT_MSG (probe, "Error: Can't find probe for path " << path);
probe->SetValue (packet, address);
}
bool
ApplicationPacketProbe::ConnectByObject (std::string traceSource, Ptr<Object> obj)
{
NS_LOG_FUNCTION (this << traceSource << obj);
NS_LOG_DEBUG ("Name of probe (if any) in names database: " << Names::FindPath (obj));
bool connected = obj->TraceConnectWithoutContext (traceSource, MakeCallback (&ns3::ApplicationPacketProbe::TraceSink, this));
return connected;
}
void
ApplicationPacketProbe::ConnectByPath (std::string path)
{
NS_LOG_FUNCTION (this << path);
NS_LOG_DEBUG ("Name of probe to search for in config database: " << path);
Config::ConnectWithoutContext (path, MakeCallback (&ns3::ApplicationPacketProbe::TraceSink, this));
}
void
ApplicationPacketProbe::TraceSink (Ptr<const Packet> packet, const Address& address)
{
NS_LOG_FUNCTION (this << packet << address);
if (IsEnabled ())
{
m_packet = packet;
m_address = address;
m_output (packet, address);
uint32_t packetSizeNew = packet->GetSize ();
m_outputBytes (m_packetSizeOld, packetSizeNew);
m_packetSizeOld = packetSizeNew;
}
}
} // namespace ns3

View File

@@ -0,0 +1,120 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef APPLICATION_PACKET_PROBE_H
#define APPLICATION_PACKET_PROBE_H
#include "ns3/object.h"
#include "ns3/callback.h"
#include "ns3/boolean.h"
#include "ns3/nstime.h"
#include "ns3/packet.h"
#include "ns3/application.h"
#include "ns3/traced-value.h"
#include "ns3/simulator.h"
#include "ns3/probe.h"
namespace ns3 {
/**
* This class is designed to probe an underlying ns3 TraceSource
* exporting a packet and a socket address. This probe exports a
* trace source "Output" with arguments of type Ptr<const Packet> and
* const Address&. This probe exports another trace source
* "OutputBytes" with arguments of type uint32_t, which is the number
* of bytes in the packet. The trace sources emit values when either
* the probed trace source emits a new value, or when SetValue () is
* called.
*/
class ApplicationPacketProbe : public Probe
{
public:
static TypeId GetTypeId ();
ApplicationPacketProbe ();
virtual ~ApplicationPacketProbe ();
/**
* \brief Set a probe value
*
* \param packet set the traced packet equal to this
* \param address set the socket address for the traced packet equal to this
*/
void SetValue (Ptr<const Packet> packet, const Address& address);
/**
* \brief Set a probe value by its name in the Config system
*
* \param path config path to access the probe
* \param packet set the traced packet equal to this
* \param address set the socket address for the traced packet equal to this
*/
static void SetValueByPath (std::string path, Ptr<const Packet> packet, const Address& address);
/**
* \brief connect to a trace source attribute provided by a given object
*
* \param traceSource the name of the attribute TraceSource to connect to
* \param obj ns3::Object to connect to
* \return true if the trace source was successfully connected
*/
virtual bool ConnectByObject (std::string traceSource, Ptr<Object> obj);
/**
* \brief connect to a trace source provided by a config path
*
* \param path Config path to bind to
*
* Note, if an invalid path is provided, the probe will not be connected
* to anything.
*/
virtual void ConnectByPath (std::string path);
private:
/**
* \brief Method to connect to an underlying ns3::TraceSource with
* arguments of type Ptr<const Packet> and const Address&
*
* \param packet the traced packet
* \param address the socket address for the traced packet
*
* \internal
*/
void TraceSink (Ptr<const Packet> packet, const Address& address);
TracedCallback<Ptr<const Packet>, const Address&> m_output;
TracedCallback<uint32_t, uint32_t> m_outputBytes;
/// The traced packet.
Ptr<const Packet> m_packet;
/// The socket address for the traced packet.
Address m_address;
/// The size of the traced packet.
uint32_t m_packetSizeOld;
};
} // namespace ns3
#endif // APPLICATION_PACKET_PROBE_H

View File

@@ -18,6 +18,7 @@ def build(bld):
'model/udp-echo-client.cc',
'model/udp-echo-server.cc',
'model/v4ping.cc',
'model/application-packet-probe.cc',
'helper/bulk-send-helper.cc',
'helper/on-off-helper.cc',
'helper/packet-sink-helper.cc',
@@ -50,6 +51,7 @@ def build(bld):
'model/udp-echo-client.h',
'model/udp-echo-server.h',
'model/v4ping.h',
'model/application-packet-probe.h',
'helper/bulk-send-helper.h',
'helper/on-off-helper.h',
'helper/packet-sink-helper.h',

View File

@@ -0,0 +1,123 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#include "ns3/ipv4-packet-probe.h"
#include "ns3/object.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/config.h"
#include "ns3/trace-source-accessor.h"
NS_LOG_COMPONENT_DEFINE ("Ipv4PacketProbe");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (Ipv4PacketProbe);
TypeId
Ipv4PacketProbe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::Ipv4PacketProbe")
.SetParent<Probe> ()
.AddConstructor<Ipv4PacketProbe> ()
.AddTraceSource ( "Output",
"The packet plus its IPv4 object and interface that serve as the output for this probe",
MakeTraceSourceAccessor (&Ipv4PacketProbe::m_output))
.AddTraceSource ( "OutputBytes",
"The number of bytes in the packet",
MakeTraceSourceAccessor (&Ipv4PacketProbe::m_outputBytes))
;
return tid;
}
Ipv4PacketProbe::Ipv4PacketProbe ()
{
NS_LOG_FUNCTION (this);
m_packet = 0;
m_ipv4 = 0;
m_interface = 0;
}
Ipv4PacketProbe::~Ipv4PacketProbe ()
{
NS_LOG_FUNCTION (this);
}
void
Ipv4PacketProbe::SetValue (Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface)
{
NS_LOG_FUNCTION (this << packet << ipv4 << interface);
m_packet = packet;
m_ipv4 = ipv4;
m_interface = interface;
m_output (packet, ipv4, interface);
uint32_t packetSizeNew = packet->GetSize ();
m_outputBytes (m_packetSizeOld, packetSizeNew);
m_packetSizeOld = packetSizeNew;
}
void
Ipv4PacketProbe::SetValueByPath (std::string path, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface)
{
NS_LOG_FUNCTION (path << packet << ipv4 << interface);
Ptr<Ipv4PacketProbe> probe = Names::Find<Ipv4PacketProbe> (path);
NS_ASSERT_MSG (probe, "Error: Can't find probe for path " << path);
probe->SetValue (packet, ipv4, interface);
}
bool
Ipv4PacketProbe::ConnectByObject (std::string traceSource, Ptr<Object> obj)
{
NS_LOG_FUNCTION (this << traceSource << obj);
NS_LOG_DEBUG ("Name of probe (if any) in names database: " << Names::FindPath (obj));
bool connected = obj->TraceConnectWithoutContext (traceSource, MakeCallback (&ns3::Ipv4PacketProbe::TraceSink, this));
return connected;
}
void
Ipv4PacketProbe::ConnectByPath (std::string path)
{
NS_LOG_FUNCTION (this << path);
NS_LOG_DEBUG ("Name of probe to search for in config database: " << path);
Config::ConnectWithoutContext (path, MakeCallback (&ns3::Ipv4PacketProbe::TraceSink, this));
}
void
Ipv4PacketProbe::TraceSink (Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface)
{
NS_LOG_FUNCTION (this << packet << ipv4 << interface);
if (IsEnabled ())
{
m_packet = packet;
m_ipv4 = ipv4;
m_interface = interface;
m_output (packet, ipv4, interface);
uint32_t packetSizeNew = packet->GetSize ();
m_outputBytes (m_packetSizeOld, packetSizeNew);
m_packetSizeOld = packetSizeNew;
}
}
} // namespace ns3

View File

@@ -0,0 +1,124 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef IPV4_PACKET_PROBE_H
#define IPV4_PACKET_PROBE_H
#include "ns3/object.h"
#include "ns3/callback.h"
#include "ns3/boolean.h"
#include "ns3/nstime.h"
#include "ns3/packet.h"
#include "ns3/ipv4.h"
#include "ns3/traced-value.h"
#include "ns3/simulator.h"
#include "ns3/probe.h"
namespace ns3 {
/**
* This class is designed to probe an underlying ns3 TraceSource
* exporting a packet, an IPv4 object, and an interface. This probe
* exports a trace source "Output" with arguments of type Ptr<const Packet>,
* Ptr<Ipv4>, and uint32_t. The Output trace source emits a value
* when either the trace source emits a new value, or when SetValue ()
* is called.
*/
class Ipv4PacketProbe : public Probe
{
public:
static TypeId GetTypeId ();
Ipv4PacketProbe ();
virtual ~Ipv4PacketProbe ();
/**
* \brief Set a probe value
*
* \param packet set the traced packet equal to this
* \param ipv4 set the IPv4 object for the traced packet equal to this
* \param interface set the IPv4 interface for the traced packet equal to this
*/
void SetValue (Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface);
/**
* \brief Set a probe value by its name in the Config system
*
* \param path config path to access the probe
* \param packet set the traced packet equal to this
* \param ipv4 set the IPv4 object for the traced packet equal to this
* \param interface set the IPv4 interface for the traced packet equal to this
*/
static void SetValueByPath (std::string path, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface);
/**
* \brief connect to a trace source attribute provided by a given object
*
* \param traceSource the name of the attribute TraceSource to connect to
* \param obj ns3::Object to connect to
* \return true if the trace source was successfully connected
*/
virtual bool ConnectByObject (std::string traceSource, Ptr<Object> obj);
/**
* \brief connect to a trace source provided by a config path
*
* \param path Config path to bind to
*
* Note, if an invalid path is provided, the probe will not be connected
* to anything.
*/
virtual void ConnectByPath (std::string path);
private:
/**
* \brief Method to connect to an underlying ns3::TraceSource with
* arguments of type Ptr<const Packet>, Ptr<Ipv4>, and uint32_t
*
* \param packet the traced packet
* \param ipv4 the IPv4 object for the traced packet
* \param interface the IPv4 interface for the traced packet
*
* \internal
*/
void TraceSink (Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface);
TracedCallback<Ptr<const Packet>, Ptr<Ipv4>, uint32_t> m_output;
TracedCallback<uint32_t, uint32_t> m_outputBytes;
/// The traced packet.
Ptr<const Packet> m_packet;
/// The IPv4 object for the traced packet.
Ptr<Ipv4> m_ipv4;
/// The IPv4 interface for the traced packet.
uint32_t m_interface;
/// The size of the traced packet.
uint32_t m_packetSizeOld;
};
} // namespace ns3
#endif // IPV4_PACKET_PROBE_H

View File

@@ -189,6 +189,7 @@ def build(bld):
'helper/ipv6-interface-container.cc',
'helper/ipv6-routing-helper.cc',
'model/ipv6-address-generator.cc',
'model/ipv4-packet-probe.cc',
]
internet_test = bld.create_ns3_module_test_library('internet')
@@ -300,6 +301,7 @@ def build(bld):
'model/tcp-tx-buffer.h',
'model/tcp-rx-buffer.h',
'model/rtt-estimator.h',
'model/ipv4-packet-probe.h',
]
if bld.env['NSC_ENABLED']:

View File

@@ -22,7 +22,7 @@
#include "ns3/packet.h"
#include "ns3/mac48-address.h"
#include "basic-data-calculators.h"
#include "ns3/basic-data-calculators.h"
#include "packet-data-calculators.h"
using namespace ns3;

View File

@@ -23,8 +23,8 @@
#include "ns3/packet.h"
#include "ns3/mac48-address.h"
#include "data-calculator.h"
#include "ns3/data-calculator.h"
#include "ns3/basic-data-calculators.h"
namespace ns3 {

View File

@@ -0,0 +1,117 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#include "ns3/packet-probe.h"
#include "ns3/object.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/config.h"
#include "ns3/trace-source-accessor.h"
NS_LOG_COMPONENT_DEFINE ("PacketProbe");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (PacketProbe);
TypeId
PacketProbe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::PacketProbe")
.SetParent<Probe> ()
.AddConstructor<PacketProbe> ()
.AddTraceSource ( "Output",
"The packet that serve as the output for this probe",
MakeTraceSourceAccessor (&PacketProbe::m_output))
.AddTraceSource ( "OutputBytes",
"The number of bytes in the packet",
MakeTraceSourceAccessor (&PacketProbe::m_outputBytes))
;
return tid;
}
PacketProbe::PacketProbe ()
{
NS_LOG_FUNCTION (this);
m_packet = 0;
}
PacketProbe::~PacketProbe ()
{
NS_LOG_FUNCTION (this);
}
void
PacketProbe::SetValue (Ptr<const Packet> packet)
{
NS_LOG_FUNCTION (this << packet);
m_packet = packet;
m_output (packet);
uint32_t packetSizeNew = packet->GetSize ();
m_outputBytes (m_packetSizeOld, packetSizeNew);
m_packetSizeOld = packetSizeNew;
}
void
PacketProbe::SetValueByPath (std::string path, Ptr<const Packet> packet)
{
NS_LOG_FUNCTION (path << packet);
Ptr<PacketProbe> probe = Names::Find<PacketProbe> (path);
NS_ASSERT_MSG (probe, "Error: Can't find probe for path " << path);
probe->SetValue (packet);
}
bool
PacketProbe::ConnectByObject (std::string traceSource, Ptr<Object> obj)
{
NS_LOG_FUNCTION (this << traceSource << obj);
NS_LOG_DEBUG ("Name of probe (if any) in names database: " << Names::FindPath (obj));
bool connected = obj->TraceConnectWithoutContext (traceSource, MakeCallback (&ns3::PacketProbe::TraceSink, this));
return connected;
}
void
PacketProbe::ConnectByPath (std::string path)
{
NS_LOG_FUNCTION (this << path);
NS_LOG_DEBUG ("Name of probe to search for in config database: " << path);
Config::ConnectWithoutContext (path, MakeCallback (&ns3::PacketProbe::TraceSink, this));
}
void
PacketProbe::TraceSink (Ptr<const Packet> packet)
{
NS_LOG_FUNCTION (this << packet);
if (IsEnabled ())
{
m_packet = packet;
m_output (packet);
uint32_t packetSizeNew = packet->GetSize ();
m_outputBytes (m_packetSizeOld, packetSizeNew);
m_packetSizeOld = packetSizeNew;
}
}
} // namespace ns3

View File

@@ -0,0 +1,112 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef PACKET_PROBE_H
#define PACKET_PROBE_H
#include "ns3/object.h"
#include "ns3/callback.h"
#include "ns3/boolean.h"
#include "ns3/nstime.h"
#include "ns3/packet.h"
#include "ns3/traced-value.h"
#include "ns3/simulator.h"
#include "ns3/probe.h"
namespace ns3 {
/**
* This class is designed to probe an underlying ns3 TraceSource
* exporting a packet. This probe exports a trace source "Output"
* with argument of type Ptr<const Packet>. This probe exports
* another trace source "OutputBytes" with arguments of type uint32_t,
* which is the number of bytes in the packet. The trace sources emit
* values when either the probed trace source emits a new value, or
* when SetValue () is called.
*/
class PacketProbe : public Probe
{
public:
static TypeId GetTypeId ();
PacketProbe ();
virtual ~PacketProbe ();
/**
* \brief Set a probe value
*
* \param packet set the traced packet equal to this
*/
void SetValue (Ptr<const Packet> packet);
/**
* \brief Set a probe value by its name in the Config system
*
* \param path config path to access the probe
* \param packet set the traced packet equal to this
*/
static void SetValueByPath (std::string path, Ptr<const Packet> packet);
/**
* \brief connect to a trace source attribute provided by a given object
*
* \param traceSource the name of the attribute TraceSource to connect to
* \param obj ns3::Object to connect to
* \return true if the trace source was successfully connected
*/
virtual bool ConnectByObject (std::string traceSource, Ptr<Object> obj);
/**
* \brief connect to a trace source provided by a config path
*
* \param path Config path to bind to
*
* Note, if an invalid path is provided, the probe will not be connected
* to anything.
*/
virtual void ConnectByPath (std::string path);
private:
/**
* \brief Method to connect to an underlying ns3::TraceSource with
* arguments of type Ptr<const Packet>
*
* \param packet the traced packet
*
* \internal
*/
void TraceSink (Ptr<const Packet> packet);
TracedCallback<Ptr<const Packet> > m_output;
TracedCallback<uint32_t, uint32_t> m_outputBytes;
/// The traced packet.
Ptr<const Packet> m_packet;
/// The size of the traced packet.
uint32_t m_packetSizeOld;
};
} // namespace ns3
#endif // PACKET_PROBE_H

View File

@@ -1,7 +1,7 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
network = bld.create_ns3_module('network', ['core'])
network = bld.create_ns3_module('network', ['core', 'stats'])
network.source = [
'model/address.cc',
'model/application.cc',
@@ -52,6 +52,8 @@ def build(bld):
'utils/red-queue.cc',
'utils/simple-channel.cc',
'utils/simple-net-device.cc',
'utils/packet-data-calculators.cc',
'utils/packet-probe.cc',
'helper/application-container.cc',
'helper/net-device-container.cc',
'helper/node-container.cc',
@@ -130,6 +132,8 @@ def build(bld):
'utils/simple-channel.h',
'utils/simple-net-device.h',
'utils/pcap-test.h',
'utils/packet-data-calculators.h',
'utils/packet-probe.h',
'helper/application-container.h',
'helper/net-device-container.h',
'helper/node-container.h',

View File

@@ -0,0 +1,197 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 University of Washington
*
* 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
*
*/
/*
* This example is designed to show the main features of an
* ns3::DoubleProbe.
*/
#include <string>
#include "ns3/core-module.h"
#include "ns3/double-probe.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("DoubleProbeExample");
/*
* This is our test object, an object that increments counters at
* various times and emits one of them as a trace source.
*/
class Emitter : public Object
{
public:
static TypeId GetTypeId (void);
Emitter ();
private:
void DoInitialize (void);
void Emit (void);
void Count (void);
TracedValue<double> m_counter; // normally this would be integer type
Ptr<ExponentialRandomVariable> m_var;
};
NS_OBJECT_ENSURE_REGISTERED (Emitter);
TypeId
Emitter::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::Emitter")
.AddConstructor<Emitter> ()
.SetParent<Object> ()
.AddTraceSource ("Counter",
"sample counter",
MakeTraceSourceAccessor (&Emitter::m_counter))
;
return tid;
}
Emitter::Emitter (void)
{
NS_LOG_FUNCTION (this);
m_counter = 0;
m_var = CreateObject<ExponentialRandomVariable> ();
}
void
Emitter::DoInitialize (void)
{
NS_LOG_FUNCTION (this);
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Emit, this);
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Count, this);
}
void
Emitter::Emit (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_DEBUG ("Emitting at " << Simulator::Now ().GetSeconds ());
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Emit, this);
}
void
Emitter::Count (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_DEBUG ("Counting at " << Simulator::Now ().GetSeconds ());
m_counter += 1.0;
DoubleProbe::SetValueByPath ("/Names/StaticallyAccessedProbe", m_counter);
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Count, this);
}
// This is a function to test hooking a raw function to the trace source
void
NotifyViaTraceSource (std::string context, double oldVal, double newVal)
{
NS_LOG_DEBUG ("context: " << context << " old " << oldVal << " new " << newVal);
}
// This is a function to test hooking it to the probe output
void
NotifyViaProbe (std::string context, double oldVal, double newVal)
{
NS_LOG_DEBUG ("context: " << context << " old " << oldVal << " new " << newVal);
}
int main (int argc, char *argv[])
{
CommandLine cmd;
cmd.Parse (argc, argv);
bool connected;
Ptr<Emitter> emitter = CreateObject<Emitter> ();
Names::Add ("/Names/Emitter", emitter);
//
// The below shows typical functionality without a probe
// (connect a sink function to a trace source)
//
connected = emitter->TraceConnect ("Counter", "sample context", MakeCallback (&NotifyViaTraceSource));
NS_ASSERT_MSG (connected, "Trace source not connected");
//
// Next, we'll show several use cases of using a Probe to access and
// filter the values of the underlying trace source
//
//
// Probe1 will be hooked directly to the Emitter trace source object
//
// probe1 will be hooked to the Emitter trace source
Ptr<DoubleProbe> probe1 = CreateObject<DoubleProbe> ();
// the probe's name can serve as its context in the tracing
probe1->SetName ("ObjectProbe");
// Connect the probe to the emitter's Counter
connected = probe1->ConnectByObject ("Counter", emitter);
NS_ASSERT_MSG (connected, "Trace source not connected to probe1");
// The probe itself should generate output. The context that we provide
// to this probe (in this case, the probe name) will help to disambiguate
// the source of the trace
connected = probe1->TraceConnect ("Output", probe1->GetName (), MakeCallback (&NotifyViaProbe));
NS_ASSERT_MSG (connected, "Trace source not connected to probe1 Output");
//
// Probe2 will be hooked to the Emitter trace source object by
// accessing it by path name in the Config database
//
// Create another similar probe; this will hook up via a Config path
Ptr<DoubleProbe> probe2 = CreateObject<DoubleProbe> ();
probe2->SetName ("PathProbe");
// Note, no return value is checked here
probe2->ConnectByPath ("/Names/Emitter/Counter");
// The probe itself should generate output. The context that we provide
// to this probe (in this case, the probe name) will help to disambiguate
// the source of the trace
connected = probe2->TraceConnect ("Output", "/Names/Probes/PathProbe/Output", MakeCallback (&NotifyViaProbe));
NS_ASSERT_MSG (connected, "Trace source not connected to probe2 Output");
//
// Probe3 will be called by the emitter directly through the
// static method SetValueByPath().
//
Ptr<DoubleProbe> probe3 = CreateObject<DoubleProbe> ();
probe3->SetName ("StaticallyAccessedProbe");
// We must add it to the config database
Names::Add ("/Names/Probes", probe3->GetName (), probe3);
// The probe itself should generate output. The context that we provide
// to this probe (in this case, the probe name) will help to disambiguate
// the source of the trace
connected = probe3->TraceConnect ("Output", "/Names/Probes/StaticallyAccessedProbe/Output", MakeCallback (&NotifyViaProbe));
NS_ASSERT_MSG (connected, "Trace source not connected to probe3 Output");
// The Emitter object is not associated with an ns-3 node, so
// it won't get started automatically, so we need to do this ourselves
Simulator::Schedule (Seconds (0.0), &Emitter::Initialize, emitter);
Simulator::Stop (Seconds (100.0));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}

View File

@@ -0,0 +1,173 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#include "ns3/core-module.h"
#include "ns3/stats-module.h"
using namespace ns3;
namespace {
//===========================================================================
// Function: CreateCommaSeparatedFile
//
//
// This function creates a file with 2 columns of values and separated
// by commas.
//===========================================================================
void CreateCommaSeparatedFile ()
{
using namespace std;
string fileName = "file-aggregator-comma-separated.txt";
string datasetContext = "Dataset/Context/String";
// Create an aggregator.
Ptr<FileAggregator> aggregator =
CreateObject<FileAggregator> (fileName, FileAggregator::COMMA_SEPARATED);
// aggregator must be turned on
aggregator->Enable ();
double time;
double value;
// Create the 2-D dataset.
for (time = -5.0; time <= +5.0; time += 1.0)
{
// Calculate the 2-D curve
//
// 2
// value = time .
//
value = time * time;
// Add this point to the plot.
aggregator->Write2d (datasetContext, time, value);
}
// Disable logging of data for the aggregator.
aggregator->Disable ();
}
//===========================================================================
// Function: CreateSpaceSeparatedFile
//
//
// This function creates a file with 2 columns of values and separated
// by spaces.
//===========================================================================
void CreateSpaceSeparatedFile ()
{
using namespace std;
string fileName = "file-aggregator-space-separated.txt";
string datasetContext = "Dataset/Context/String";
// Create an aggregator. Note that the default type is space
// separated.
Ptr<FileAggregator> aggregator =
CreateObject<FileAggregator> (fileName);
// aggregator must be turned on
aggregator->Enable ();
double time;
double value;
// Create the 2-D dataset.
for (time = -5.0; time <= +5.0; time += 1.0)
{
// Calculate the 2-D curve
//
// 2
// value = time .
//
value = time * time;
// Add this point to the plot.
aggregator->Write2d (datasetContext, time, value);
}
// Disable logging of data for the aggregator.
aggregator->Disable ();
}
//===========================================================================
// Function: CreateFormattedFile
//
//
// This function creates a file with formatted values.
//===========================================================================
void CreateFormattedFile ()
{
using namespace std;
string fileName = "file-aggregator-formatted-values.txt";
string datasetContext = "Dataset/Context/String";
// Create an aggregator that will have formatted values.
Ptr<FileAggregator> aggregator =
CreateObject<FileAggregator> (fileName, FileAggregator::FORMATTED);
// Set the format for the values.
aggregator->Set2dFormat ("Time = %.3e\tValue = %.0f");
// aggregator must be turned on
aggregator->Enable ();
double time;
double value;
// Create the 2-D dataset.
for (time = -5.0; time < 5.5; time += 1.0)
{
// Calculate the 2-D curve
//
// 2
// value = time .
//
value = time * time;
// Add this point to the plot.
aggregator->Write2d (datasetContext, time, value);
}
// Disable logging of data for the aggregator.
aggregator->Disable ();
}
} // anonymous namespace
int main (int argc, char *argv[])
{
CreateCommaSeparatedFile ();
CreateSpaceSeparatedFile ();
CreateFormattedFile ();
return 0;
}

View File

@@ -0,0 +1,157 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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
*
* This is based on double-probe-example.cc.
*
* Author: Mitch Watrous (watrous@u.washington.edu)
*/
/*
* This example is designed to show the main features of an
* ns3::FileHelper.
*/
#include <string>
#include "ns3/core-module.h"
#include "ns3/stats-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("FileHelperExample");
/*
* This is our test object, an object that increments counters at
* various times and emits one of them as a trace source.
*/
class Emitter : public Object
{
public:
static TypeId GetTypeId (void);
Emitter ();
private:
void DoInitialize (void);
void Emit (void);
void Count (void);
TracedValue<double> m_counter; // normally this would be integer type
Ptr<ExponentialRandomVariable> m_var;
};
NS_OBJECT_ENSURE_REGISTERED (Emitter);
TypeId
Emitter::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::Emitter")
.AddConstructor<Emitter> ()
.SetParent<Object> ()
.AddTraceSource ("Counter",
"sample counter",
MakeTraceSourceAccessor (&Emitter::m_counter))
;
return tid;
}
Emitter::Emitter (void)
{
NS_LOG_FUNCTION (this);
m_counter = 0;
m_var = CreateObject<ExponentialRandomVariable> ();
}
void
Emitter::DoInitialize (void)
{
NS_LOG_FUNCTION (this);
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Emit, this);
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Count, this);
}
void
Emitter::Emit (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_DEBUG ("Emitting at " << Simulator::Now ().GetSeconds ());
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Emit, this);
}
void
Emitter::Count (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_DEBUG ("Counting at " << Simulator::Now ().GetSeconds ());
m_counter += 1.0;
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Count, this);
}
int main (int argc, char *argv[])
{
CommandLine cmd;
cmd.Parse (argc, argv);
//
// This Emitter has a trace source object that will emit values at
// random times.
//
Ptr<Emitter> emitter = CreateObject<Emitter> ();
Names::Add ("/Names/Emitter", emitter);
//
// This Probe will be hooked to the Emitter's trace source object by
// accessing it by path name in the Config database.
//
Ptr<DoubleProbe> probe = CreateObject<DoubleProbe> ();
probe->SetName ("PathProbe");
Names::Add ("/Names/Probe", probe);
// Note, no return value is checked here.
probe->ConnectByPath ("/Names/Emitter/Counter");
//
// This file helper will be used to put data values into a file.
//
// Create the file helper.
FileHelper fileHelper;
// Configure the file to be written.
fileHelper.ConfigureFile ("file-helper-example",
FileAggregator::FORMATTED);
// Set the labels for this formatted output file.
fileHelper.Set2dFormat ("Time (Seconds) = %.3e\tCount = %.0f");
// Write the values generated by the probe. The path that we
// provide helps to disambiguate the source of the trace.
fileHelper.WriteProbe ("ns3::DoubleProbe",
"/Names/Probe/Output",
"Output");
// The Emitter object is not associated with an ns-3 node, so
// it won't get started automatically, so we need to do this ourselves
Simulator::Schedule (Seconds (0.0), &Emitter::Initialize, emitter);
Simulator::Stop (Seconds (100.0));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}

View File

@@ -0,0 +1,91 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#include "ns3/core-module.h"
#include "ns3/stats-module.h"
using namespace ns3;
namespace {
//===========================================================================
// Function: Create2dPlot
//
//
// This function creates a 2-Dimensional plot.
//===========================================================================
void Create2dPlot ()
{
using namespace std;
string fileNameWithoutExtension = "gnuplot-aggregator";
string plotTitle = "Gnuplot Aggregator Plot";
string plotXAxisHeading = "Time (seconds)";
string plotYAxisHeading = "Double Values";
string plotDatasetLabel = "Data Values";
string datasetContext = "Dataset/Context/String";
// Create an aggregator.
Ptr<GnuplotAggregator> aggregator =
CreateObject<GnuplotAggregator> (fileNameWithoutExtension);
// Set the aggregator's properties.
aggregator->SetTerminal ("png");
aggregator->SetTitle (plotTitle);
aggregator->SetLegend (plotXAxisHeading, plotYAxisHeading);
// Add a data set to the aggregator.
aggregator->Add2dDataset (datasetContext, plotDatasetLabel);
// aggregator must be turned on
aggregator->Enable ();
double time;
double value;
// Create the 2-D dataset.
for (time = -5.0; time <= +5.0; time += 1.0)
{
// Calculate the 2-D curve
//
// 2
// value = time .
//
value = time * time;
// Add this point to the plot.
aggregator->Write2d (datasetContext, time, value);
}
// Disable logging of data for the aggregator.
aggregator->Disable ();
}
} // anonymous namespace
int main (int argc, char *argv[])
{
Create2dPlot ();
return 0;
}

View File

@@ -201,9 +201,9 @@ void Create3DPlotFile ()
plot.AppendExtra ("set ticslevel 0");
// Set the labels for each axis.
plot.AppendExtra ("set xlabel 'X Values'");
plot.AppendExtra ("set ylabel 'Y Values'");
plot.AppendExtra ("set zlabel 'Z Values'");
plot.AppendExtra ("set xlabel \"X Values\"");
plot.AppendExtra ("set ylabel \"Y Values\"");
plot.AppendExtra ("set zlabel \"Z Values\"");
// Set the ranges for the x and y axis.
plot.AppendExtra ("set xrange [-5:+5]");

View File

@@ -0,0 +1,160 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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
*
* This is based on double-probe-example.cc.
*
* Author: Mitch Watrous (watrous@u.washington.edu)
*/
/*
* This example is designed to show the main features of an
* ns3::GnuplotHelper.
*/
#include <string>
#include "ns3/core-module.h"
#include "ns3/stats-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("GnuplotHelperExample");
/*
* This is our test object, an object that increments counters at
* various times and emits one of them as a trace source.
*/
class Emitter : public Object
{
public:
static TypeId GetTypeId (void);
Emitter ();
private:
void DoInitialize (void);
void Emit (void);
void Count (void);
TracedValue<double> m_counter; // normally this would be integer type
Ptr<ExponentialRandomVariable> m_var;
};
NS_OBJECT_ENSURE_REGISTERED (Emitter);
TypeId
Emitter::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::Emitter")
.AddConstructor<Emitter> ()
.SetParent<Object> ()
.AddTraceSource ("Counter",
"sample counter",
MakeTraceSourceAccessor (&Emitter::m_counter))
;
return tid;
}
Emitter::Emitter (void)
{
NS_LOG_FUNCTION (this);
m_counter = 0;
m_var = CreateObject<ExponentialRandomVariable> ();
}
void
Emitter::DoInitialize (void)
{
NS_LOG_FUNCTION (this);
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Emit, this);
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Count, this);
}
void
Emitter::Emit (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_DEBUG ("Emitting at " << Simulator::Now ().GetSeconds ());
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Emit, this);
}
void
Emitter::Count (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_DEBUG ("Counting at " << Simulator::Now ().GetSeconds ());
m_counter += 1.0;
Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Count, this);
}
int main (int argc, char *argv[])
{
CommandLine cmd;
cmd.Parse (argc, argv);
//
// This Emitter has a trace source object that will emit values at
// random times.
//
Ptr<Emitter> emitter = CreateObject<Emitter> ();
Names::Add ("/Names/Emitter", emitter);
//
// This Probe will be hooked to the Emitter's trace source object by
// accessing it by path name in the Config database.
//
Ptr<DoubleProbe> probe = CreateObject<DoubleProbe> ();
probe->SetName ("PathProbe");
Names::Add ("/Names/Probe", probe);
// Note, no return value is checked here.
probe->ConnectByPath ("/Names/Emitter/Counter");
//
// This gnuplot helper will be used to produce output used to make
// gnuplot plots.
//
// Create the gnuplot helper.
GnuplotHelper plotHelper;
// Configure the plot.
plotHelper.ConfigurePlot ("gnuplot-helper-example",
"Emitter Counts vs. Time",
"Time (Seconds)",
"Emitter Count",
"png");
// Plot the values generated by the probe. The path that we provide
// helps to disambiguate the source of the trace.
plotHelper.PlotProbe ("ns3::DoubleProbe",
"/Names/Probe/Output",
"Output",
"Emitter Count",
GnuplotAggregator::KEY_INSIDE);
// The Emitter object is not associated with an ns-3 node, so
// it won't get started automatically, so we need to do this ourselves
Simulator::Schedule (Seconds (0.0), &Emitter::Initialize, emitter);
Simulator::Stop (Seconds (100.0));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}

View File

@@ -4,7 +4,22 @@ def build(bld):
if not bld.env['ENABLE_EXAMPLES']:
return;
obj = bld.create_ns3_program('gnuplot-example', ['stats'])
obj = bld.create_ns3_program('gnuplot-example', ['network', 'stats'])
obj.source = 'gnuplot-example.cc'
program = bld.create_ns3_program('double-probe-example', ['network', 'stats'])
program.source = 'double-probe-example.cc'
program = bld.create_ns3_program('gnuplot-aggregator-example', ['network', 'stats'])
program.source = 'gnuplot-aggregator-example.cc'
program = bld.create_ns3_program('gnuplot-helper-example', ['network', 'stats'])
program.source = 'gnuplot-helper-example.cc'
program = bld.create_ns3_program('file-aggregator-example', ['network', 'stats'])
program.source = 'file-aggregator-example.cc'
program = bld.create_ns3_program('file-helper-example', ['network', 'stats'])
program.source = 'file-helper-example.cc'

View File

@@ -0,0 +1,559 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#include <iostream>
#include <fstream>
#include <string>
#include "file-helper.h"
#include "ns3/abort.h"
#include "ns3/log.h"
#include "ns3/config.h"
#include "ns3/get-wildcard-matches.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("FileHelper");
FileHelper::FileHelper ()
: m_aggregator (0),
m_fileProbeCount (0),
m_fileType (FileAggregator::SPACE_SEPARATED),
m_outputFileNameWithoutExtension ("file-helper"),
m_hasHeadingBeenSet (false)
{
NS_LOG_FUNCTION (this);
// Note that this does not construct an aggregator. It will be
// constructed later when needed.
}
FileHelper::FileHelper (const std::string &outputFileNameWithoutExtension,
enum FileAggregator::FileType fileType)
: m_aggregator (0),
m_fileProbeCount (0),
m_fileType (fileType),
m_outputFileNameWithoutExtension (outputFileNameWithoutExtension),
m_hasHeadingBeenSet (false)
{
NS_LOG_FUNCTION (this);
// Note that this does not construct an aggregator. It will be
// constructed later when needed.
}
FileHelper::~FileHelper ()
{
NS_LOG_FUNCTION (this);
}
void
FileHelper::ConfigureFile (const std::string &outputFileNameWithoutExtension,
enum FileAggregator::FileType fileType)
{
NS_LOG_FUNCTION (this << outputFileNameWithoutExtension << fileType);
// See if an aggregator has already been constructed.
if (m_aggregator != 0)
{
NS_LOG_WARN ("An existing aggregator object " << m_aggregator <<
" may be destroyed if no references remain.");
}
// Store these so that they can be used to construct the aggregator.
m_fileType = fileType;
m_outputFileNameWithoutExtension = outputFileNameWithoutExtension;
m_hasHeadingBeenSet = false;
// Note that this does not construct an aggregator. It will be
// constructed later when needed.
}
void
FileHelper::WriteProbe (const std::string &typeId,
const std::string &path,
const std::string &probeTraceSource)
{
NS_LOG_FUNCTION (this << typeId << path << probeTraceSource);
std::string pathWithoutLastToken;
std::string lastToken;
// See if the path has any wildcards.
bool pathHasNoWildcards = path.find ("*") == std::string::npos;
// Remove the last token from the path.
unsigned lastSlash = path.find_last_of ("/");
if (lastSlash == std::string::npos)
{
pathWithoutLastToken = path;
lastToken = "";
}
else
{
// Chop off up to last token.
pathWithoutLastToken = path.substr (0, lastSlash);
// Save the last token without the last slash.
lastToken = path.substr (lastSlash + 1, std::string::npos);
}
// See if there are any matches for the probe's path with the last
// token removed.
Config::MatchContainer matches = Config::LookupMatches (pathWithoutLastToken);
uint32_t matchCount = matches.GetN ();
// This is used to make the probe's context be unique.
std::string matchIdentifier;
/// This is used to indicate if multiple aggregators are needed.
bool onlyOneAggregator;
// Hook one or more probes and one or more aggregators together.
if (matchCount == 1 && pathHasNoWildcards)
{
// Connect the probe to the aggregator only once because there
// is only one matching config path. There is no need to find
// the wildcard matches because the passed in path has none.
matchIdentifier = "0";
onlyOneAggregator = true;
ConnectProbeToAggregator (typeId,
matchIdentifier,
path,
probeTraceSource,
m_outputFileNameWithoutExtension,
onlyOneAggregator);
}
else if (matchCount > 0)
{
// Handle all of the matches if there are more than one.
for (uint32_t i = 0; i < matchCount; i++)
{
// Set the match identifier.
std::ostringstream matchIdentifierStream;
matchIdentifierStream << i;
matchIdentifier = matchIdentifierStream.str ();
onlyOneAggregator = false;
// Construct the matched path and get the matches for each
// of the wildcards.
std::string wildcardSeparator = "-";
std::string matchedPath = matches.GetMatchedPath (i) + lastToken;
std::string wildcardMatches = GetWildcardMatches (path,
matchedPath,
wildcardSeparator);
// Connect the probe to the aggregator for this match.
ConnectProbeToAggregator (typeId,
matchIdentifier,
matchedPath,
probeTraceSource,
m_outputFileNameWithoutExtension + "-" + wildcardMatches,
onlyOneAggregator);
}
}
else
{
// There is a problem if there are no matching config paths.
NS_FATAL_ERROR ("Lookup of " << path << " got no matches");
}
}
void
FileHelper::AddProbe (const std::string &typeId,
const std::string &probeName,
const std::string &path)
{
NS_LOG_FUNCTION (this << typeId << probeName << path);
// See if this probe had already been added.
if (m_probeMap.count (probeName) > 0)
{
NS_ABORT_MSG ("That probe has already been added");
}
// Prepare the factory to create an object with the requested type.
m_factory.SetTypeId (typeId);
// Create a base class object in order to validate the type.
Ptr<Probe> probe = m_factory.Create ()->GetObject<Probe> ();
if (probe == 0)
{
NS_ABORT_MSG ("The requested type is not a probe");
}
// Set the probe's name.
probe->SetName (probeName);
// Set the path. Note that no return value is checked here.
probe->ConnectByPath (path);
// Enable logging of data for the probe.
probe->Enable ();
// Add this probe to the map so that its values can be used.
m_probeMap[probeName] = std::make_pair (probe, typeId);
}
void
FileHelper::AddTimeSeriesAdaptor (const std::string &adaptorName)
{
NS_LOG_FUNCTION (this << adaptorName);
// See if this time series adaptor had already been added.
if (m_timeSeriesAdaptorMap.count (adaptorName) > 0)
{
NS_ABORT_MSG ("That time series adaptor has already been added");
}
// Create the time series adaptor.
Ptr<TimeSeriesAdaptor> timeSeriesAdaptor = CreateObject<TimeSeriesAdaptor> ();
// Enable logging of data for the time series adaptor.
timeSeriesAdaptor->Enable ();
// Add this time series adaptor to the map so that it can be used.
m_timeSeriesAdaptorMap[adaptorName] = timeSeriesAdaptor;
}
void
FileHelper::AddAggregator (const std::string &aggregatorName,
const std::string &outputFileName,
bool onlyOneAggregator)
{
NS_LOG_FUNCTION (this << aggregatorName << outputFileName << onlyOneAggregator);
// See if this file aggregator had already been added.
if (m_aggregatorMap.count (aggregatorName) > 0)
{
NS_ABORT_MSG ("That file aggregator has already been added");
}
// If there is only going to be 1 file aggregator, then use the one
// already constructed in the map.
if (onlyOneAggregator)
{
// Get a pointer to the aggregator.
Ptr<FileAggregator> singleAggregator = GetAggregatorSingle ();
m_aggregatorMap[aggregatorName] = singleAggregator;
return;
}
// Create the file aggregator with the proper file type.
Ptr<FileAggregator> multipleAggregator =
CreateObject<FileAggregator> (outputFileName, m_fileType);
// Set all of the format strings for the aggregator.
multipleAggregator->Set1dFormat (m_1dFormat);
multipleAggregator->Set2dFormat (m_2dFormat);
multipleAggregator->Set3dFormat (m_3dFormat);
multipleAggregator->Set4dFormat (m_4dFormat);
multipleAggregator->Set5dFormat (m_5dFormat);
multipleAggregator->Set6dFormat (m_6dFormat);
multipleAggregator->Set7dFormat (m_7dFormat);
multipleAggregator->Set8dFormat (m_8dFormat);
multipleAggregator->Set9dFormat (m_9dFormat);
multipleAggregator->Set10dFormat (m_10dFormat);
// Set the heading
multipleAggregator->SetHeading (m_heading);
// Enable logging of data for the file aggregator.
multipleAggregator->Enable ();
// Add this file aggregator to the map so that it can be used.
m_aggregatorMap[aggregatorName] = multipleAggregator;
}
Ptr<Probe>
FileHelper::GetProbe (std::string probeName) const
{
NS_LOG_FUNCTION (this << probeName);
// Look for the probe.
std::map<std::string, std::pair <Ptr<Probe>, std::string> >::const_iterator mapIterator = m_probeMap.find (probeName);
// Return the probe if it has been added.
if (mapIterator != m_probeMap.end ())
{
return mapIterator->second.first;
}
else
{
NS_ABORT_MSG ("That probe has not been added");
}
}
Ptr<FileAggregator>
FileHelper::GetAggregatorSingle ()
{
NS_LOG_FUNCTION (this);
// Do a lazy construction of the single aggregator if it hasn't
// already been constructed.
if (!m_aggregator)
{
// Create the aggregator.
std::string outputFileName = m_outputFileNameWithoutExtension + ".txt";
m_aggregator = CreateObject<FileAggregator> (outputFileName, m_fileType);
// Set all of the format strings for the aggregator.
m_aggregator->Set1dFormat (m_1dFormat);
m_aggregator->Set2dFormat (m_2dFormat);
m_aggregator->Set3dFormat (m_3dFormat);
m_aggregator->Set4dFormat (m_4dFormat);
m_aggregator->Set5dFormat (m_5dFormat);
m_aggregator->Set6dFormat (m_6dFormat);
m_aggregator->Set7dFormat (m_7dFormat);
m_aggregator->Set8dFormat (m_8dFormat);
m_aggregator->Set9dFormat (m_9dFormat);
m_aggregator->Set10dFormat (m_10dFormat);
// Set the heading
m_aggregator->SetHeading (m_heading);
// Enable logging of data for the aggregator.
m_aggregator->Enable ();
}
return m_aggregator;
}
Ptr<FileAggregator>
FileHelper::GetAggregatorMultiple (const std::string &aggregatorName,
const std::string &outputFileName)
{
NS_LOG_FUNCTION (this);
// See if this file aggregator had already been added.
if (m_aggregatorMap.count (aggregatorName) > 0)
{
return m_aggregatorMap[aggregatorName];
}
// Do a lazy construction of the aggregator if it hasn't already
// been constructed.
bool onlyOneAggregator = false;
AddAggregator (aggregatorName,
outputFileName,
onlyOneAggregator);
return m_aggregatorMap[aggregatorName];
}
void
FileHelper::SetHeading (const std::string &heading)
{
NS_LOG_FUNCTION (this << heading);
m_hasHeadingBeenSet = true;
m_heading = heading;
}
void
FileHelper::Set1dFormat (const std::string &format)
{
NS_LOG_FUNCTION (this << format);
m_1dFormat = format;
}
void
FileHelper::Set2dFormat (const std::string &format)
{
NS_LOG_FUNCTION (this << format);
m_2dFormat = format;
}
void
FileHelper::Set3dFormat (const std::string &format)
{
NS_LOG_FUNCTION (this << format);
m_3dFormat = format;
}
void
FileHelper::Set4dFormat (const std::string &format)
{
NS_LOG_FUNCTION (this << format);
m_4dFormat = format;
}
void
FileHelper::Set5dFormat (const std::string &format)
{
NS_LOG_FUNCTION (this << format);
m_5dFormat = format;
}
void
FileHelper::Set6dFormat (const std::string &format)
{
NS_LOG_FUNCTION (this << format);
m_6dFormat = format;
}
void
FileHelper::Set7dFormat (const std::string &format)
{
NS_LOG_FUNCTION (this << format);
m_7dFormat = format;
}
void
FileHelper::Set8dFormat (const std::string &format)
{
NS_LOG_FUNCTION (this << format);
m_8dFormat = format;
}
void
FileHelper::Set9dFormat (const std::string &format)
{
NS_LOG_FUNCTION (this << format);
m_9dFormat = format;
}
void
FileHelper::Set10dFormat (const std::string &format)
{
NS_LOG_FUNCTION (this << format);
m_10dFormat = format;
}
void
FileHelper::ConnectProbeToAggregator (const std::string &typeId,
const std::string &matchIdentifier,
const std::string &path,
const std::string &probeTraceSource,
const std::string &outputFileNameWithoutExtension,
bool onlyOneAggregator)
{
NS_LOG_FUNCTION (this << typeId << matchIdentifier << path << probeTraceSource
<< outputFileNameWithoutExtension << onlyOneAggregator);
// Increment the total number of file probes that have been created.
m_fileProbeCount++;
// Create a unique name for this probe.
std::ostringstream probeNameStream;
probeNameStream << "FileProbe-" << m_fileProbeCount;
std::string probeName = probeNameStream.str ();
// Create a unique dataset context string for this probe.
std::string probeContext = probeName
+ "/" + matchIdentifier + "/" + probeTraceSource;
// Add the probe to the map of probes, which will keep the probe in
// memory after this function ends.
AddProbe (typeId, probeName, path);
// Because the callbacks to the probes' trace sources don't use the
// probe's context, a unique adaptor needs to be created for each
// probe context so that information is not lost.
AddTimeSeriesAdaptor (probeContext);
// Connect the probe to the adaptor.
if (m_probeMap[probeName].second == "ns3::DoubleProbe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkDouble,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::BooleanProbe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkBoolean,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::PacketProbe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger32,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::ApplicationPacketProbe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger32,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::Ipv4PacketProbe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger32,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::Uinteger8Probe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger8,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::Uinteger16Probe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger16,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger32,
m_timeSeriesAdaptorMap[probeContext]));
}
else
{
NS_FATAL_ERROR ("Unknown probe type " << m_probeMap[probeName].second << "; need to add support in the helper for this");
}
// Add the aggregator to the map of aggregators, which will keep the
// aggregator in memory after this function ends.
std::string outputFileName = outputFileNameWithoutExtension + ".txt";
AddAggregator (probeContext, outputFileName, onlyOneAggregator);
// Connect the adaptor to the aggregator.
std::string adaptorTraceSource = "Output";
m_timeSeriesAdaptorMap[probeContext]->TraceConnect
(adaptorTraceSource,
probeContext,
MakeCallback (&FileAggregator::Write2d,
m_aggregatorMap[probeContext]));
}
} // namespace ns3

View File

@@ -0,0 +1,323 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef FILE_HELPER_H
#define FILE_HELPER_H
#include <map>
#include <string>
#include "ns3/object-factory.h"
#include "ns3/ptr.h"
#include "ns3/probe.h"
#include "ns3/file-aggregator.h"
#include "ns3/time-series-adaptor.h"
namespace ns3 {
/**
* \brief Helper class used to put data values into a file.
**/
class FileHelper
{
public:
/**
* Constructs a file helper that will create a space separated file
* named "file-helper.txt" unless it is later configured otherwise.
*/
FileHelper ();
/**
* \param outputFileNameWithoutExtension name of output file to
* write with no extension
* \param fileType type of file to write.
*
* Constructs a file helper that will create a file named
* outputFileNameWithoutExtension plus possible extra information
* from wildcard matches plus ".txt" with values printed as
* specified by fileType. The default file type is space-separated.
*/
FileHelper (const std::string &outputFileNameWithoutExtension,
enum FileAggregator::FileType fileType = FileAggregator::SPACE_SEPARATED);
virtual ~FileHelper ();
/**
* \param outputFileNameWithoutExtension name of output file to
* write with no extension
* \param fileType type of file to write.
*
* Configures file related parameters for this file helper so that
* it will create a file named outputFileNameWithoutExtension plus
* possible extra information from wildcard matches plus ".txt" with
* values printed as specified by fileType. The default file type
* is space-separated.
*/
void ConfigureFile (const std::string &outputFileNameWithoutExtension,
enum FileAggregator::FileType fileType = FileAggregator::SPACE_SEPARATED);
/**
* \param typeId the type ID for the probe used when it is created.
* \param path Config path to access the probe.
* \param probeTraceSource the probe trace source to access.
*
* Creates output files generated by hooking the ns-3 trace source
* with a probe, and then writing the values from the
* probeTraceSource. The output file names will have the text stored
* in m_outputFileNameWithoutExtension plus ".txt", and will consist
* of the 'newValue' at each timestamp.
*
* If the config path has more than one match in the system
* (e.g. there is a wildcard), then one output file for each match
* will be created. The output file names will contain the text in
* m_outputFileNameWithoutExtension plus the matched characters for
* each of the wildcards in the config path, separated by dashes,
* plus ".txt". For example, if the value in
* m_outputFileNameWithoutExtension is the string
* "packet-byte-count", and there are two wildcards in the path,
* then output file names like "packet-byte-count-0-0.txt" or
* "packet-byte-count-12-9.txt" will be possible as names for the
* files that will be created.
*
* A fatal error will result if an unknown probe type is used.
*/
void WriteProbe (const std::string &typeId,
const std::string &path,
const std::string &probeTraceSource);
/**
* \param typeId the type ID for the probe used when it is created.
* \param probeName the probe's name.
* \param path Config path to access the probe
*
* \brief Adds a probe to be used to write values to files.
*/
void AddProbe (const std::string &typeId,
const std::string &probeName,
const std::string &path);
/**
* \param adaptorName the timeSeriesAdaptor's name.
*
* \brief Adds a time series adaptor to be used to write the file.
*/
void AddTimeSeriesAdaptor (const std::string &adaptorName);
/**
* \param aggregatorName the aggregator's name.
* \param outputFileName name of the file to write.
* \param onlyOneAggregator indicates if more than one aggregator
* should be created or not.
*
* \brief Adds an aggregator to be used to write values to files.
*/
void AddAggregator (const std::string &aggregatorName,
const std::string &outputFileName,
bool onlyOneAggregator);
/**
* \param probeName the probe's name.
*
* \brief Gets the specified probe.
*/
Ptr<Probe> GetProbe (std::string probeName) const;
/**
* \brief Gets the single aggregator that is always constructed.
*
* This function is non-const because an aggregator may be lazily
* created by this method.
*/
Ptr<FileAggregator> GetAggregatorSingle ();
/**
* \param aggregatorName name for aggregator.
* \param outputFileName name of output file to write.
*
* \brief Gets one of the multiple aggregators from the map.
*
* This function is non-const because an aggregator may be lazily
* created by this method.
*/
Ptr<FileAggregator> GetAggregatorMultiple (const std::string &aggregatorName,
const std::string &outputFileName);
/**
* \param heading the heading string.
*
* \brief Sets the heading string that will be printed on the first
* line of the file.
*
* Note that the heading string will only be printed if it has been
* set by calling this function.
*/
void SetHeading (const std::string &heading);
/**
* \param format the 1D format string.
*
* \brief Sets the 1D format string for the C-style sprintf()
* function.
*/
void Set1dFormat (const std::string &format);
/**
* \param format the 2D format string.
*
* \brief Sets the 2D format string for the C-style sprintf()
* function.
*/
void Set2dFormat (const std::string &format);
/**
* \param format the 3D format string.
*
* \brief Sets the 3D format string for the C-style sprintf()
* function.
*/
void Set3dFormat (const std::string &format);
/**
* \param format the 4D format string.
*
* \brief Sets the 4D format string for the C-style sprintf()
* function.
*/
void Set4dFormat (const std::string &format);
/**
* \param format the 5D format string.
*
* \brief Sets the 5D format string for the C-style sprintf()
* function.
*/
void Set5dFormat (const std::string &format);
/**
* \param format the 6D format string.
*
* \brief Sets the 6D format string for the C-style sprintf()
* function.
*/
void Set6dFormat (const std::string &format);
/**
* \param format the 7D format string.
*
* \brief Sets the 7D format string for the C-style sprintf()
* function.
*/
void Set7dFormat (const std::string &format);
/**
* \param format the 8D format string.
*
* \brief Sets the 8D format string for the C-style sprintf()
* function.
*/
void Set8dFormat (const std::string &format);
/**
* \param format the 9D format string.
*
* \brief Sets the 9D format string for the C-style sprintf()
* function.
*/
void Set9dFormat (const std::string &format);
/**
* \param format the 10D format string.
*
* \brief Sets the 10D format string for the C-style sprintf()
* function.
*/
void Set10dFormat (const std::string &format);
private:
/**
* \param typeId the type ID for the probe used when it is created.
* \param matchIdentifier this string is used to make the probe's
* context be unique.
* \param path Config path to access the probe.
* \param probeTraceSource the probe trace source to access.
* \param outputFileNameWithoutExtension name of output file to
* write with no extension
* \param onlyOneAggregator indicates if more than one aggregator
* should be created or not.
*
* \brief Connects the probe to the aggregator.
*
* A fatal error will result if an unknown probe type is used.
*/
void ConnectProbeToAggregator (const std::string &typeId,
const std::string &matchIdentifier,
const std::string &path,
const std::string &probeTraceSource,
const std::string &outputFileNameWithoutExtension,
bool onlyOneAggregator);
/// Used to create the probes and collectors as they are added.
ObjectFactory m_factory;
/// The single aggregator that is always created in the constructor.
Ptr<FileAggregator> m_aggregator;
/// Maps aggregator names to aggregators when multiple aggregators
/// are needed.
std::map<std::string, Ptr<FileAggregator> > m_aggregatorMap;
/// Maps probe names to probes.
std::map<std::string, std::pair <Ptr<Probe>, std::string> > m_probeMap;
/// Maps time series adaptor names to time series adaptors.
std::map<std::string, Ptr<TimeSeriesAdaptor> > m_timeSeriesAdaptorMap;
/// Number of file probes that have been created.
uint32_t m_fileProbeCount;
/// Determines the kind of file written by the aggregator.
enum FileAggregator::FileType m_fileType;
/// The name of the output file to created without its extension.
std::string m_outputFileNameWithoutExtension;
/// Indicates if the heading line for the file has been set.
bool m_hasHeadingBeenSet;
/// Heading line for the outputfile.
std::string m_heading;
/// Format strings for C-style sprintf() function.
std::string m_1dFormat;
std::string m_2dFormat;
std::string m_3dFormat;
std::string m_4dFormat;
std::string m_5dFormat;
std::string m_6dFormat;
std::string m_7dFormat;
std::string m_8dFormat;
std::string m_9dFormat;
std::string m_10dFormat;
}; // class FileHelper
} // namespace ns3
#endif // FILE_HELPER_H

View File

@@ -0,0 +1,413 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "gnuplot-helper.h"
#include "ns3/abort.h"
#include "ns3/assert.h"
#include "ns3/config.h"
#include "ns3/log.h"
#include "ns3/get-wildcard-matches.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("GnuplotHelper");
GnuplotHelper::GnuplotHelper ()
: m_aggregator (0),
m_plotProbeCount (0),
m_outputFileNameWithoutExtension ("gnuplot-helper"),
m_title ("Gnuplot Helper Plot"),
m_xLegend ("X Values"),
m_yLegend ("Y Values"),
m_terminalType ("png")
{
NS_LOG_FUNCTION (this);
// Note that this does not construct an aggregator. It will be
// constructed later when needed.
}
GnuplotHelper::GnuplotHelper (const std::string &outputFileNameWithoutExtension,
const std::string &title,
const std::string &xLegend,
const std::string &yLegend,
const std::string &terminalType)
: m_aggregator (0),
m_plotProbeCount (0),
m_outputFileNameWithoutExtension (outputFileNameWithoutExtension),
m_title (title),
m_xLegend (xLegend),
m_yLegend (yLegend),
m_terminalType (terminalType)
{
NS_LOG_FUNCTION (this);
// Construct the aggregator.
ConstructAggregator ();
}
GnuplotHelper::~GnuplotHelper ()
{
NS_LOG_FUNCTION (this);
}
void
GnuplotHelper::ConfigurePlot (const std::string &outputFileNameWithoutExtension,
const std::string &title,
const std::string &xLegend,
const std::string &yLegend,
const std::string &terminalType)
{
NS_LOG_FUNCTION (this << outputFileNameWithoutExtension << title
<< xLegend << yLegend << terminalType);
// See if an aggregator has already been constructed.
if (m_aggregator != 0)
{
NS_LOG_WARN ("An existing aggregator object " << m_aggregator <<
" may be destroyed if no references remain.");
}
// Store these so that they can be used to construct the aggregator.
m_outputFileNameWithoutExtension = outputFileNameWithoutExtension;
m_title = title;
m_xLegend = xLegend;
m_yLegend = yLegend;
m_terminalType = terminalType;
// Construct the aggregator.
ConstructAggregator ();
}
void
GnuplotHelper::PlotProbe (const std::string &typeId,
const std::string &path,
const std::string &probeTraceSource,
const std::string &title,
enum GnuplotAggregator::KeyLocation keyLocation)
{
NS_LOG_FUNCTION (this << typeId << path << probeTraceSource << title << keyLocation);
// Get a pointer to the aggregator.
Ptr<GnuplotAggregator> aggregator = GetAggregator ();
// Add a subtitle to the title to show the probe's path.
aggregator->SetTitle ( m_title + " \\n\\nProbe Path: " + path);
// Set the default dataset plotting style for the values.
aggregator->Set2dDatasetDefaultStyle (Gnuplot2dDataset::LINES_POINTS);
// Set the location of the key in the plot.
aggregator->SetKeyLocation (keyLocation);
std::string pathWithoutLastToken;
std::string lastToken;
// See if the path has any wildcards.
bool pathHasNoWildcards = path.find ("*") == std::string::npos;
// Remove the last token from the path.
unsigned lastSlash = path.find_last_of ("/");
if (lastSlash == std::string::npos)
{
pathWithoutLastToken = path;
lastToken = "";
}
else
{
// Chop off up to last token.
pathWithoutLastToken = path.substr (0, lastSlash);
// Save the last token without the last slash.
lastToken = path.substr (lastSlash + 1, std::string::npos);
}
// See if there are any matches for the probe's path with the last
// token removed.
Config::MatchContainer matches = Config::LookupMatches (pathWithoutLastToken);
uint32_t matchCount = matches.GetN ();
// This is used to make the probe's context be unique.
std::string matchIdentifier;
// Hook one or more probes and the aggregator together.
if (matchCount == 1 && pathHasNoWildcards)
{
// Connect the probe to the aggregator only once because there
// is only one matching config path. There is no need to find
// the wildcard matches because the passed in path has none.
matchIdentifier = "0";
ConnectProbeToAggregator (typeId,
matchIdentifier,
path,
probeTraceSource,
title);
}
else if (matchCount > 0)
{
// Handle all of the matches if there are more than one.
for (uint32_t i = 0; i < matchCount; i++)
{
// Set the match identifier.
std::ostringstream matchIdentifierStream;
matchIdentifierStream << i;
matchIdentifier = matchIdentifierStream.str ();
// Construct the matched path and get the matches for each
// of the wildcards.
std::string wildcardSeparator = " ";
std::string matchedPath = matches.GetMatchedPath (i) + lastToken;
std::string wildcardMatches = GetWildcardMatches (path,
matchedPath,
wildcardSeparator);
// Connect the probe to the aggregator for this match.
ConnectProbeToAggregator (typeId,
matchIdentifier,
matchedPath,
probeTraceSource,
title + "-" + wildcardMatches);
}
}
else
{
// There is a problem if there are no matching config paths.
NS_FATAL_ERROR ("Lookup of " << path << " got no matches");
}
}
void
GnuplotHelper::AddProbe (const std::string &typeId,
const std::string &probeName,
const std::string &path)
{
NS_LOG_FUNCTION (this << typeId << probeName << path);
// See if this probe had already been added.
if (m_probeMap.count (probeName) > 0)
{
NS_ABORT_MSG ("That probe has already been added");
}
// Prepare the factory to create an object with the requested type.
m_factory.SetTypeId (typeId);
// Create a base class object in order to validate the type.
Ptr<Probe> probe = m_factory.Create ()->GetObject<Probe> ();
if (probe == 0)
{
NS_ABORT_MSG ("The requested type is not a probe");
}
// Set the probe's name.
probe->SetName (probeName);
// Set the path. Note that no return value is checked here.
probe->ConnectByPath (path);
// Enable logging of data for the probe.
probe->Enable ();
// Add this probe to the map so that its values can be used.
m_probeMap[probeName] = std::make_pair (probe, typeId);
}
void
GnuplotHelper::AddTimeSeriesAdaptor (const std::string &adaptorName)
{
NS_LOG_FUNCTION (this << adaptorName);
// See if this time series adaptor had already been added.
if (m_timeSeriesAdaptorMap.count (adaptorName) > 0)
{
NS_ABORT_MSG ("That time series adaptor has already been added");
}
// Create the time series adaptor.
Ptr<TimeSeriesAdaptor> timeSeriesAdaptor = CreateObject<TimeSeriesAdaptor> ();
// Enable logging of data for the time series adaptor.
timeSeriesAdaptor->Enable ();
// Add this time series adaptor to the map so that can be used.
m_timeSeriesAdaptorMap[adaptorName] = timeSeriesAdaptor;
}
Ptr<Probe>
GnuplotHelper::GetProbe (std::string probeName) const
{
// Look for the probe.
std::map<std::string, std::pair <Ptr<Probe>, std::string> >::const_iterator mapIterator = m_probeMap.find (probeName);
// Return the probe if it has been added.
if (mapIterator != m_probeMap.end ())
{
return mapIterator->second.first;
}
else
{
NS_ABORT_MSG ("That probe has not been added");
}
}
Ptr<GnuplotAggregator>
GnuplotHelper::GetAggregator ()
{
NS_LOG_FUNCTION (this);
// Do a lazy construction of the aggregator if it hasn't already
// been constructed.
if (!m_aggregator)
{
ConstructAggregator ();
}
return m_aggregator;
}
void
GnuplotHelper::ConstructAggregator ()
{
NS_LOG_FUNCTION (this);
// Create the aggregator.
m_aggregator = CreateObject<GnuplotAggregator> (m_outputFileNameWithoutExtension);
// Set the aggregator's properties.
m_aggregator->SetTerminal (m_terminalType);
m_aggregator->SetTitle (m_title);
m_aggregator->SetLegend (m_xLegend, m_yLegend);
// Enable logging of data for the aggregator.
m_aggregator->Enable ();
}
void
GnuplotHelper::ConnectProbeToAggregator (const std::string &typeId,
const std::string &matchIdentifier,
const std::string &path,
const std::string &probeTraceSource,
const std::string &title)
{
NS_LOG_FUNCTION (this << typeId << matchIdentifier << path << probeTraceSource
<< title);
Ptr<GnuplotAggregator> aggregator = GetAggregator ();
// Increment the total number of plot probes that have been created.
m_plotProbeCount++;
// Create a unique name for this probe.
std::ostringstream probeNameStream;
probeNameStream << "PlotProbe-" << m_plotProbeCount;
std::string probeName = probeNameStream.str ();
// Create a unique dataset context string for this probe.
std::string probeContext = probeName
+ "/" + matchIdentifier + "/" + probeTraceSource;
// Add the probe to the map of probes, which will keep the probe in
// memory after this function ends.
AddProbe (typeId, probeName, path);
// Because the callbacks to the probes' trace sources don't use the
// probe's context, a unique adaptor needs to be created for each
// probe context so that information is not lost.
AddTimeSeriesAdaptor (probeContext);
// Connect the probe to the adaptor.
if (m_probeMap[probeName].second == "ns3::DoubleProbe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkDouble,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::BooleanProbe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkBoolean,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::PacketProbe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger32,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::ApplicationPacketProbe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger32,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::Ipv4PacketProbe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger32,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::Uinteger8Probe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger8,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::Uinteger16Probe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger16,
m_timeSeriesAdaptorMap[probeContext]));
}
else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe")
{
m_probeMap[probeName].first->TraceConnectWithoutContext
(probeTraceSource,
MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger32,
m_timeSeriesAdaptorMap[probeContext]));
}
else
{
NS_FATAL_ERROR ("Unknown probe type " << m_probeMap[probeName].second << "; need to add support in the helper for this");
}
// Connect the adaptor to the aggregator.
std::string adaptorTraceSource = "Output";
m_timeSeriesAdaptorMap[probeContext]->TraceConnect
(adaptorTraceSource,
probeContext,
MakeCallback (&GnuplotAggregator::Write2d, aggregator));
// Add the dataset to the plot.
aggregator->Add2dDataset (probeContext, title);
}
} // namespace ns3

View File

@@ -0,0 +1,212 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef GNUPLOT_HELPER_H
#define GNUPLOT_HELPER_H
#include <map>
#include <utility>
#include <string>
#include "ns3/object-factory.h"
#include "ns3/ptr.h"
#include "ns3/probe.h"
#include "ns3/gnuplot-aggregator.h"
#include "ns3/time-series-adaptor.h"
namespace ns3 {
/**
* \brief Helper class used to make gnuplot plots.
**/
class GnuplotHelper
{
public:
/**
* Constructs a gnuplot helper that will create a space separated
* gnuplot data file named "gnuplot-helper.dat", a gnuplot control
* file named "gnuplot-helper.plt", and a shell script to generate
* the gnuplot named "gnuplot-helper.sh" unless it is later
* configured otherwise.
*/
GnuplotHelper ();
/**
* \param outputFileNameWithoutExtension name of gnuplot related files to
* write with no extension
* \param title plot title string to use for this plot.
* \param xLegend the legend for the x horizontal axis.
* \param yLegend the legend for the y vertical axis.
* \param terminalType terminal type setting string for output. The
* default terminal type is "png"
*
* Constructs a gnuplot helper that will create a space separated
* gnuplot data file named outputFileNameWithoutExtension + ".dat",
* a gnuplot control file named outputFileNameWithoutExtension +
* ".plt", and a shell script to generate the gnuplot named
* outputFileNameWithoutExtension + ".sh".
*/
GnuplotHelper (const std::string &outputFileNameWithoutExtension,
const std::string &title,
const std::string &xLegend,
const std::string &yLegend,
const std::string &terminalType = "png");
virtual ~GnuplotHelper ();
/**
* \param outputFileNameWithoutExtension name of gnuplot related files to
* write with no extension
* \param title plot title string to use for this plot.
* \param xLegend the legend for the x horizontal axis.
* \param yLegend the legend for the y vertical axis.
* \param terminalType terminal type setting string for output. The
* default terminal type is "png"
*
* Configures plot related parameters for this gnuplot helper so
* that it will create a space separated gnuplot data file named
* outputFileNameWithoutExtension + ".dat", a gnuplot control file
* named outputFileNameWithoutExtension + ".plt", and a shell script
* to generate the gnuplot named outputFileNameWithoutExtension +
* ".sh".
*/
void ConfigurePlot (const std::string &outputFileNameWithoutExtension,
const std::string &title,
const std::string &xLegend,
const std::string &yLegend,
const std::string &terminalType = ".png");
/**
* \param typeId the type ID for the probe used when it is created.
* \param path Config path to access the probe.
* \param probeTraceSource the probe trace source to access.
* \param title the title to be associated to this dataset
* \param keyLocation the location of the key in the plot.
*
* Plots a dataset generated by hooking the ns-3 trace source with a
* probe, and then plot the values from the probeTraceSource. The dataset
* will have the provided title, and will consist of the 'newValue'
* at each timestamp.
*
* If the config path has more than one match in the system
* (e.g. there is a wildcard), then one dataset for each match will
* be plotted. The dataset titles will be suffixed with the matched
* characters for each of the wildcards in the config path,
* separated by spaces. For example, if the proposed dataset title
* is the string "bytes", and there are two wildcards in the path,
* then dataset titles like "bytes-0 0" or "bytes-12 9" will be
* possible as labels for the datasets that are plotted.
*/
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);
/**
* \param typeId the type ID for the probe used when it is created.
* \param probeName the probe's name.
* \param path Config path to access the probe.
*
* \brief Adds a probe to be used to make the plot.
*/
void AddProbe (const std::string &typeId,
const std::string &probeName,
const std::string &path);
/**
* \param adaptorName the timeSeriesAdaptor's name.
*
* \brief Adds a time series adaptor to be used to make the plot.
*/
void AddTimeSeriesAdaptor (const std::string &adaptorName);
/**
* \param probeName the probe's name.
*
* \brief Gets the specified probe.
*/
Ptr<Probe> GetProbe (std::string probeName) const;
/**
* \brief Gets the aggregator.
*
* This function is non-const because an aggregator may be lazily
* created by this method.
*/
Ptr<GnuplotAggregator> GetAggregator ();
private:
/**
* \brief Constructs the aggregator.
*/
void ConstructAggregator ();
/**
* \param typeId the type ID for the probe used when it is created.
* \param matchIdentifier this string is used to make the probe's
* context be unique.
* \param path Config path to access the probe.
* \param probeTraceSource the probe trace source to access.
* \param title the title to be associated to this dataset.
*
* \brief Connects the probe to the aggregator.
*/
void ConnectProbeToAggregator (const std::string &typeId,
const std::string &matchIdentifier,
const std::string &path,
const std::string &probeTraceSource,
const std::string &title);
/// Used to create the probes and collectors as they are added.
ObjectFactory m_factory;
/// The aggregator used to make the plots.
Ptr<GnuplotAggregator> m_aggregator;
/// Maps probe names to probes.
std::map<std::string, std::pair <Ptr<Probe>, std::string> > m_probeMap;
/// Maps time series adaptor names to time series adaptors.
std::map<std::string, Ptr<TimeSeriesAdaptor> > m_timeSeriesAdaptorMap;
/// Number of plot probes that have been created.
uint32_t m_plotProbeCount;
/// The name of the output file to created without its extension.
std::string m_outputFileNameWithoutExtension;
/// Title string to use for this plot.
std::string m_title;
/// Legend for the x axis.
std::string m_xLegend;
/// Legend for the y axis.
std::string m_yLegend;
/// Terminal type for the plot.
std::string m_terminalType;
}; // class GnuplotHelper
} // namespace ns3
#endif // GNUPLOT_HELPER_H

View File

@@ -0,0 +1,110 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#include "ns3/boolean-probe.h"
#include "ns3/object.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/config.h"
#include "ns3/trace-source-accessor.h"
NS_LOG_COMPONENT_DEFINE ("BooleanProbe");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (BooleanProbe);
TypeId
BooleanProbe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::BooleanProbe")
.SetParent<Probe> ()
.AddConstructor<BooleanProbe> ()
.AddTraceSource ( "Output",
"The bool that serves as output for this probe",
MakeTraceSourceAccessor (&BooleanProbe::m_output))
;
return tid;
}
BooleanProbe::BooleanProbe ()
{
NS_LOG_FUNCTION (this);
m_output = 0;
}
BooleanProbe::~BooleanProbe ()
{
NS_LOG_FUNCTION (this);
}
bool
BooleanProbe::GetValue (void) const
{
NS_LOG_FUNCTION (this);
return m_output;
}
void
BooleanProbe::SetValue (bool newVal)
{
NS_LOG_FUNCTION (this << newVal);
m_output = newVal;
}
void
BooleanProbe::SetValueByPath (std::string path, bool newVal)
{
NS_LOG_FUNCTION (path << newVal);
Ptr<BooleanProbe> probe = Names::Find<BooleanProbe> (path);
NS_ASSERT_MSG (probe, "Error: Can't find probe for path " << path);
probe->SetValue (newVal);
}
bool
BooleanProbe::ConnectByObject (std::string traceSource, Ptr<Object> obj)
{
NS_LOG_FUNCTION (this << traceSource << obj);
NS_LOG_DEBUG ("Name of probe (if any) in names database: " << Names::FindPath (obj));
bool connected = obj->TraceConnectWithoutContext (traceSource, MakeCallback (&ns3::BooleanProbe::TraceSink, this));
return connected;
}
void
BooleanProbe::ConnectByPath (std::string path)
{
NS_LOG_FUNCTION (this << path);
NS_LOG_DEBUG ("Name of probe to search for in config database: " << path);
Config::ConnectWithoutContext (path, MakeCallback (&ns3::BooleanProbe::TraceSink, this));
}
void
BooleanProbe::TraceSink (bool oldData, bool newData)
{
NS_LOG_FUNCTION (this << oldData << newData);
if (IsEnabled ())
{
m_output = newData;
}
}
} // namespace ns3

View File

@@ -0,0 +1,105 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef BOOL_PROBE_H
#define BOOL_PROBE_H
#include "ns3/probe.h"
#include "ns3/object.h"
#include "ns3/callback.h"
#include "ns3/boolean.h"
#include "ns3/traced-value.h"
#include "ns3/simulator.h"
namespace ns3 {
/**
* This class is designed to probe an underlying ns3 TraceSource exporting
* a bool. This probe exports a trace source "Output" of type bool.
* The Output trace source emits a value when either the trace source
* emits a new value, or when SetValue () is called.
*
* The current value of the probe can be polled with the GetValue ()
* method.
*/
class BooleanProbe : public Probe
{
public:
static TypeId GetTypeId ();
BooleanProbe ();
virtual ~BooleanProbe ();
/**
* \return the most recent value
*/
bool GetValue (void) const;
/**
* \param value set the traced bool to a new value
*/
void SetValue (bool value);
/**
* \brief Set a probe value by its name in the Config system
*
* \param path Config path to access the probe
* \param value set the traced bool to a new value
*/
static void SetValueByPath (std::string path, bool value);
/**
* \brief connect to a trace source attribute provided by a given object
*
* \param traceSource the name of the attribute TraceSource to connect to
* \param obj ns3::Object to connect to
* \return true if the trace source was successfully connected
*/
virtual bool ConnectByObject (std::string traceSource, Ptr<Object> obj);
/**
* \brief connect to a trace source provided by a config path
*
* \param path Config path to bind to
*
* Note, if an invalid path is provided, the probe will not be connected
* to anything.
*/
virtual void ConnectByPath (std::string path);
private:
/**
* \brief Method to connect to an underlying ns3::TraceSource of type bool
*
* \param oldData previous value of the bool
* \param newData new value of the bool
*
* \internal
*/
void TraceSink (bool oldData, bool newData);
TracedValue<bool> m_output;
};
} // namespace ns3
#endif // BOOL_PROBE_H

View File

@@ -0,0 +1,96 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: Tiago G. Rodrigues (tgr002@bucknell.edu)
*/
#include "ns3/log.h"
#include "ns3/string.h"
#include "ns3/boolean.h"
#include "data-collection-object.h"
NS_LOG_COMPONENT_DEFINE ("DataCollectionObject");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (DataCollectionObject);
TypeId
DataCollectionObject::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::DataCollectionObject")
.SetParent<Object> ()
.AddConstructor<DataCollectionObject> ()
.AddAttribute ( "Name",
"Object's name",
StringValue ("unnamed"), MakeStringAccessor (&DataCollectionObject::GetName, &DataCollectionObject::SetName), MakeStringChecker ())
.AddAttribute ( "Enabled",
"Object's enabled status",
BooleanValue (true), MakeBooleanAccessor (&DataCollectionObject::m_enabled), MakeBooleanChecker ())
;
return tid;
}
DataCollectionObject::DataCollectionObject ()
{
}
DataCollectionObject::~DataCollectionObject ()
{
NS_LOG_FUNCTION (this);
}
bool
DataCollectionObject::IsEnabled (void) const
{
return m_enabled;
}
std::string
DataCollectionObject::GetName (void) const
{
return m_name;
}
void
DataCollectionObject::SetName (std::string name)
{
NS_LOG_FUNCTION (this << name);
for (size_t pos = name.find (" "); pos != std::string::npos; pos = name.find (" ", pos + 1, 1))
{
name[pos] = '_';
}
m_name = name;
}
void
DataCollectionObject::Enable (void)
{
NS_LOG_FUNCTION (this);
m_enabled = true;
}
void
DataCollectionObject::Disable (void)
{
NS_LOG_FUNCTION (this);
m_enabled = false;
}
} // namespace ns3

View File

@@ -0,0 +1,67 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: Tiago G. Rodrigues (tgr002@bucknell.edu)
*/
#ifndef DATA_COLLECTION_OBJECT_H
#define DATA_COLLECTION_OBJECT_H
#include <string>
#include "ns3/object.h"
namespace ns3 {
/**
* Base class for data collection framework objects.
*
* All data collection objects have 1) a string name, and 2) enabled
* or disabled status.
*/
class DataCollectionObject : public Object
{
public:
static TypeId GetTypeId ();
DataCollectionObject ();
virtual ~DataCollectionObject ();
/// Set the status of an individual object.
void Enable (void);
void Disable (void);
/// Check the status of an individual object.
virtual bool IsEnabled (void) const;
/// Get the object's name.
std::string GetName (void) const;
/// Set the object's name. All spaces are replaced by underscores.
void SetName (std::string name);
protected:
/// Object's activation state.
bool m_enabled;
/// Name of the object within the data collection framework
std::string m_name;
};
} // namespace ns3
#endif // DATA_COLLECTION_OBJECT_H

View File

@@ -0,0 +1,110 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#include "ns3/double-probe.h"
#include "ns3/object.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/config.h"
#include "ns3/trace-source-accessor.h"
NS_LOG_COMPONENT_DEFINE ("DoubleProbe");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (DoubleProbe);
TypeId
DoubleProbe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::DoubleProbe")
.SetParent<Probe> ()
.AddConstructor<DoubleProbe> ()
.AddTraceSource ( "Output",
"The double that serves as output for this probe",
MakeTraceSourceAccessor (&DoubleProbe::m_output))
;
return tid;
}
DoubleProbe::DoubleProbe ()
{
NS_LOG_FUNCTION (this);
m_output = 0;
}
DoubleProbe::~DoubleProbe ()
{
NS_LOG_FUNCTION (this);
}
double
DoubleProbe::GetValue (void) const
{
NS_LOG_FUNCTION (this);
return m_output;
}
void
DoubleProbe::SetValue (double newVal)
{
NS_LOG_FUNCTION (this << newVal);
m_output = newVal;
}
void
DoubleProbe::SetValueByPath (std::string path, double newVal)
{
NS_LOG_FUNCTION (path << newVal);
Ptr<DoubleProbe> probe = Names::Find<DoubleProbe> (path);
NS_ASSERT_MSG (probe, "Error: Can't find probe for path " << path);
probe->SetValue (newVal);
}
bool
DoubleProbe::ConnectByObject (std::string traceSource, Ptr<Object> obj)
{
NS_LOG_FUNCTION (this << traceSource << obj);
NS_LOG_DEBUG ("Name of probe (if any) in names database: " << Names::FindPath (obj));
bool connected = obj->TraceConnectWithoutContext (traceSource, MakeCallback (&ns3::DoubleProbe::TraceSink, this));
return connected;
}
void
DoubleProbe::ConnectByPath (std::string path)
{
NS_LOG_FUNCTION (this << path);
NS_LOG_DEBUG ("Name of probe to search for in config database: " << path);
Config::ConnectWithoutContext (path, MakeCallback (&ns3::DoubleProbe::TraceSink, this));
}
void
DoubleProbe::TraceSink (double oldData, double newData)
{
NS_LOG_FUNCTION (this << oldData << newData);
if (IsEnabled ())
{
m_output = newData;
}
}
} // namespace ns3

View File

@@ -0,0 +1,105 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef DOUBLE_PROBE_H
#define DOUBLE_PROBE_H
#include "ns3/probe.h"
#include "ns3/object.h"
#include "ns3/callback.h"
#include "ns3/boolean.h"
#include "ns3/traced-value.h"
#include "ns3/simulator.h"
namespace ns3 {
/**
* This class is designed to probe an underlying ns3 TraceSource exporting
* a double. This probe exports a trace source "Output" of type double.
* The Output trace source emits a value when either the trace source
* emits a new value, or when SetValue () is called.
*
* The current value of the probe can be polled with the GetValue ()
* method.
*/
class DoubleProbe : public Probe
{
public:
static TypeId GetTypeId ();
DoubleProbe ();
virtual ~DoubleProbe ();
/**
* \return the most recent value
*/
double GetValue (void) const;
/**
* \param value set the traced double to a new value
*/
void SetValue (double value);
/**
* \brief Set a probe value by its name in the Config system
*
* \param path Config path to access the probe
* \param value set the traced double to a new value
*/
static void SetValueByPath (std::string path, double value);
/**
* \brief connect to a trace source attribute provided by a given object
*
* \param traceSource the name of the attribute TraceSource to connect to
* \param obj ns3::Object to connect to
* \return true if the trace source was successfully connected
*/
virtual bool ConnectByObject (std::string traceSource, Ptr<Object> obj);
/**
* \brief connect to a trace source provided by a config path
*
* \param path Config path to bind to
*
* Note, if an invalid path is provided, the probe will not be connected
* to anything.
*/
virtual void ConnectByPath (std::string path);
private:
/**
* \brief Method to connect to an underlying ns3::TraceSource of type double
*
* \param oldData previous value of the double
* \param newData new value of the double
*
* \internal
*/
void TraceSink (double oldData, double newData);
TracedValue<double> m_output;
};
} // namespace ns3
#endif // DOUBLE_PROBE_H

View File

@@ -0,0 +1,661 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#include <iostream>
#include <fstream>
#include <string>
#include "file-aggregator.h"
#include "ns3/abort.h"
#include "ns3/log.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("FileAggregator");
NS_OBJECT_ENSURE_REGISTERED (FileAggregator);
TypeId
FileAggregator::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::FileAggregator")
.SetParent<DataCollectionObject> ()
;
return tid;
}
FileAggregator::FileAggregator (const std::string &outputFileName,
enum FileType fileType)
: m_outputFileName (outputFileName),
m_fileType (fileType),
m_hasHeadingBeenSet (false),
m_1dFormat ("%e"),
m_2dFormat ("%e %e"),
m_3dFormat ("%e %e %e"),
m_4dFormat ("%e %e %e %e"),
m_5dFormat ("%e %e %e %e %e"),
m_6dFormat ("%e %e %e %e %e %e"),
m_7dFormat ("%e %e %e %e %e %e %e"),
m_8dFormat ("%e %e %e %e %e %e %e %e"),
m_9dFormat ("%e %e %e %e %e %e %e %e %e"),
m_10dFormat ("%e %e %e %e %e %e %e %e %e %e")
{
// Set the values separator.
switch (m_fileType)
{
case COMMA_SEPARATED:
m_separator = ",";
break;
case TAB_SEPARATED:
m_separator = "\t";
break;
default:
// Space separated.
m_separator = " ";
break;
}
// Open the output file.
m_file.open (m_outputFileName.c_str ());
}
FileAggregator::~FileAggregator ()
{
// Close the output file.
m_file.close ();
}
void
FileAggregator::SetFileType (enum FileType fileType)
{
m_fileType = fileType;
}
void
FileAggregator::SetHeading (const std::string &heading)
{
if (!m_hasHeadingBeenSet)
{
m_heading = heading;
m_hasHeadingBeenSet = true;
// Print the heading to the file.
m_file << m_heading << std::endl;
}
}
void
FileAggregator::Set1dFormat (const std::string &format)
{
m_1dFormat = format;
}
void
FileAggregator::Set2dFormat (const std::string &format)
{
m_2dFormat = format;
}
void
FileAggregator::Set3dFormat (const std::string &format)
{
m_3dFormat = format;
}
void
FileAggregator::Set4dFormat (const std::string &format)
{
m_4dFormat = format;
}
void
FileAggregator::Set5dFormat (const std::string &format)
{
m_5dFormat = format;
}
void
FileAggregator::Set6dFormat (const std::string &format)
{
m_6dFormat = format;
}
void
FileAggregator::Set7dFormat (const std::string &format)
{
m_7dFormat = format;
}
void
FileAggregator::Set8dFormat (const std::string &format)
{
m_8dFormat = format;
}
void
FileAggregator::Set9dFormat (const std::string &format)
{
m_9dFormat = format;
}
void
FileAggregator::Set10dFormat (const std::string &format)
{
m_10dFormat = format;
}
void
FileAggregator::Write1d (std::string context,
double v1)
{
if (m_enabled)
{
// Write the 1D data point to the file.
if (m_fileType == FORMATTED)
{
// Initially, have the C-style string in the buffer, which
// is terminated by a null character, be of length zero.
char buffer[500];
int maxBufferSize = 500;
buffer[0] = 0;
// Format the value.
int charWritten = snprintf (buffer,
maxBufferSize,
m_1dFormat.c_str (),
v1);
if (charWritten < 0)
{
NS_LOG_DEBUG ("Error writing value to output file");
}
// Write the formatted value.
m_file << buffer << std::endl;
}
else
{
// Write the value.
m_file << v1 << std::endl;
}
}
}
void
FileAggregator::Write2d (std::string context,
double v1,
double v2)
{
if (m_enabled)
{
// Write the 2D data point to the file.
if (m_fileType == FORMATTED)
{
// Initially, have the C-style string in the buffer, which
// is terminated by a null character, be of length zero.
char buffer[500];
int maxBufferSize = 500;
buffer[0] = 0;
// Format the values.
int charWritten = snprintf (buffer,
maxBufferSize,
m_2dFormat.c_str (),
v1,
v2);
if (charWritten < 0)
{
NS_LOG_DEBUG ("Error writing values to output file");
}
// Write the formatted values.
m_file << buffer << std::endl;
}
else
{
// Write the values with the proper separator.
m_file << v1 << m_separator
<< v2 << std::endl;
}
}
}
void
FileAggregator::Write3d (std::string context,
double v1,
double v2,
double v3)
{
if (m_enabled)
{
// Write the 3D data point to the file.
if (m_fileType == FORMATTED)
{
// Initially, have the C-style string in the buffer, which
// is terminated by a null character, be of length zero.
char buffer[500];
int maxBufferSize = 500;
buffer[0] = 0;
// Format the values.
int charWritten = snprintf (buffer,
maxBufferSize,
m_3dFormat.c_str (),
v1,
v2,
v3);
if (charWritten < 0)
{
NS_LOG_DEBUG ("Error writing values to output file");
}
// Write the formatted values.
m_file << buffer << std::endl;
}
else
{
// Write the values with the proper separator.
m_file << v1 << m_separator
<< v2 << m_separator
<< v3 << std::endl;
}
}
}
void
FileAggregator::Write4d (std::string context,
double v1,
double v2,
double v3,
double v4)
{
if (m_enabled)
{
// Write the 4D data point to the file.
if (m_fileType == FORMATTED)
{
// Initially, have the C-style string in the buffer, which
// is terminated by a null character, be of length zero.
char buffer[500];
int maxBufferSize = 500;
buffer[0] = 0;
// Format the values.
int charWritten = snprintf (buffer,
maxBufferSize,
m_4dFormat.c_str (),
v1,
v2,
v3,
v4);
if (charWritten < 0)
{
NS_LOG_DEBUG ("Error writing values to output file");
}
// Write the formatted values.
m_file << buffer << std::endl;
}
else
{
// Write the values with the proper separator.
m_file << v1 << m_separator
<< v2 << m_separator
<< v3 << m_separator
<< v4 << std::endl;
}
}
}
void
FileAggregator::Write5d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5)
{
if (m_enabled)
{
// Write the 5D data point to the file.
if (m_fileType == FORMATTED)
{
// Initially, have the C-style string in the buffer, which
// is terminated by a null character, be of length zero.
char buffer[500];
int maxBufferSize = 500;
buffer[0] = 0;
// Format the values.
int charWritten = snprintf (buffer,
maxBufferSize,
m_5dFormat.c_str (),
v1,
v2,
v3,
v4,
v5);
if (charWritten < 0)
{
NS_LOG_DEBUG ("Error writing values to output file");
}
// Write the formatted values.
m_file << buffer << std::endl;
}
else
{
// Write the values with the proper separator.
m_file << v1 << m_separator
<< v2 << m_separator
<< v3 << m_separator
<< v4 << m_separator
<< v5 << std::endl;
}
}
}
void
FileAggregator::Write6d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5,
double v6)
{
if (m_enabled)
{
// Write the 6D data point to the file.
if (m_fileType == FORMATTED)
{
// Initially, have the C-style string in the buffer, which
// is terminated by a null character, be of length zero.
char buffer[500];
int maxBufferSize = 500;
buffer[0] = 0;
// Format the values.
int charWritten = snprintf (buffer,
maxBufferSize,
m_6dFormat.c_str (),
v1,
v2,
v3,
v4,
v5,
v6);
if (charWritten < 0)
{
NS_LOG_DEBUG ("Error writing values to output file");
}
// Write the formatted values.
m_file << buffer << std::endl;
}
else
{
// Write the values with the proper separator.
m_file << v1 << m_separator
<< v2 << m_separator
<< v3 << m_separator
<< v4 << m_separator
<< v5 << m_separator
<< v6 << std::endl;
}
}
}
void
FileAggregator::Write7d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5,
double v6,
double v7)
{
if (m_enabled)
{
// Write the 7D data point to the file.
if (m_fileType == FORMATTED)
{
// Initially, have the C-style string in the buffer, which
// is terminated by a null character, be of length zero.
char buffer[500];
int maxBufferSize = 500;
buffer[0] = 0;
// Format the values.
int charWritten = snprintf (buffer,
maxBufferSize,
m_7dFormat.c_str (),
v1,
v2,
v3,
v4,
v5,
v6,
v7);
if (charWritten < 0)
{
NS_LOG_DEBUG ("Error writing values to output file");
}
// Write the formatted values.
m_file << buffer << std::endl;
}
else
{
// Write the values with the proper separator.
m_file << v1 << m_separator
<< v2 << m_separator
<< v3 << m_separator
<< v4 << m_separator
<< v5 << m_separator
<< v6 << m_separator
<< v7 << std::endl;
}
}
}
void
FileAggregator::Write8d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5,
double v6,
double v7,
double v8)
{
if (m_enabled)
{
// Write the 8D data point to the file.
if (m_fileType == FORMATTED)
{
// Initially, have the C-style string in the buffer, which
// is terminated by a null character, be of length zero.
char buffer[500];
int maxBufferSize = 500;
buffer[0] = 0;
// Format the values.
int charWritten = snprintf (buffer,
maxBufferSize,
m_8dFormat.c_str (),
v1,
v2,
v3,
v4,
v5,
v6,
v7,
v8);
if (charWritten < 0)
{
NS_LOG_DEBUG ("Error writing values to output file");
}
// Write the formatted values.
m_file << buffer << std::endl;
}
else
{
// Write the values with the proper separator.
m_file << v1 << m_separator
<< v2 << m_separator
<< v3 << m_separator
<< v4 << m_separator
<< v5 << m_separator
<< v6 << m_separator
<< v7 << m_separator
<< v8 << std::endl;
}
}
}
void
FileAggregator::Write9d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5,
double v6,
double v7,
double v8,
double v9)
{
if (m_enabled)
{
// Write the 9D data point to the file.
if (m_fileType == FORMATTED)
{
// Initially, have the C-style string in the buffer, which
// is terminated by a null character, be of length zero.
char buffer[500];
int maxBufferSize = 500;
buffer[0] = 0;
// Format the values.
int charWritten = snprintf (buffer,
maxBufferSize,
m_9dFormat.c_str (),
v1,
v2,
v3,
v4,
v5,
v6,
v7,
v8,
v9);
if (charWritten < 0)
{
NS_LOG_DEBUG ("Error writing values to output file");
}
// Write the formatted values.
m_file << buffer << std::endl;
}
else
{
// Write the values with the proper separator.
m_file << v1 << m_separator
<< v2 << m_separator
<< v3 << m_separator
<< v4 << m_separator
<< v5 << m_separator
<< v6 << m_separator
<< v7 << m_separator
<< v8 << m_separator
<< v9 << std::endl;
}
}
}
void
FileAggregator::Write10d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5,
double v6,
double v7,
double v8,
double v9,
double v10)
{
if (m_enabled)
{
// Write the 10D data point to the file.
if (m_fileType == FORMATTED)
{
// Initially, have the C-style string in the buffer, which
// is terminated by a null character, be of length zero.
char buffer[500];
int maxBufferSize = 500;
buffer[0] = 0;
// Format the values.
int charWritten = snprintf (buffer,
maxBufferSize,
m_10dFormat.c_str (),
v1,
v2,
v3,
v4,
v5,
v6,
v7,
v8,
v9,
v10);
if (charWritten < 0)
{
NS_LOG_DEBUG ("Error writing values to output file");
}
// Write the formatted values.
m_file << buffer << std::endl;
}
else
{
// Write the values with the proper separator.
m_file << v1 << m_separator
<< v2 << m_separator
<< v3 << m_separator
<< v4 << m_separator
<< v5 << m_separator
<< v6 << m_separator
<< v7 << m_separator
<< v8 << m_separator
<< v9 << m_separator
<< v10 << std::endl;
}
}
}
} // namespace ns3

View File

@@ -0,0 +1,384 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*
*/
#ifndef FILE_AGGREGATOR_H
#define FILE_AGGREGATOR_H
#include <fstream>
#include <map>
#include <string>
#include "ns3/data-collection-object.h"
namespace ns3 {
/**
* This aggregator sends values it receives to a file.
**/
class FileAggregator : public DataCollectionObject
{
public:
/// The type of file written by the aggregator.
enum FileType
{
FORMATTED,
SPACE_SEPARATED,
COMMA_SEPARATED,
TAB_SEPARATED
};
static TypeId GetTypeId ();
/**
* \param outputFileName name of the file to write.
* \param fileType type of file to write.
*
* Constructs a file aggregator that will create a file named
* outputFileName with values printed as specified by fileType. The
* default file type is space-separated.
*/
FileAggregator (const std::string &outputFileName,
enum FileType fileType = SPACE_SEPARATED);
virtual ~FileAggregator ();
/**
* \param fileType file type specifies the separator to use in
* printing the file.
*
* \brief Set the file type to create, which determines the
* separator to use when printing values to the file.
*/
void SetFileType (enum FileType fileType);
/**
* \param heading the heading string.
*
* \brief Sets the heading string that will be printed on the first
* line of the file.
*
* Note that the heading string will only be printed if it has been
* set by calling this function.
*/
void SetHeading (const std::string &heading);
/**
* \param format the 1D format string.
*
* \brief Sets the 1D format string for the C-style sprintf()
* function.
*/
void Set1dFormat (const std::string &format);
/**
* \param format the 2D format string.
*
* \brief Sets the 2D format string for the C-style sprintf()
* function.
*/
void Set2dFormat (const std::string &format);
/**
* \param format the 3D format string.
*
* \brief Sets the 3D format string for the C-style sprintf()
* function.
*/
void Set3dFormat (const std::string &format);
/**
* \param format the 4D format string.
*
* \brief Sets the 4D format string for the C-style sprintf()
* function.
*/
void Set4dFormat (const std::string &format);
/**
* \param format the 5D format string.
*
* \brief Sets the 5D format string for the C-style sprintf()
* function.
*/
void Set5dFormat (const std::string &format);
/**
* \param format the 6D format string.
*
* \brief Sets the 6D format string for the C-style sprintf()
* function.
*/
void Set6dFormat (const std::string &format);
/**
* \param format the 7D format string.
*
* \brief Sets the 7D format string for the C-style sprintf()
* function.
*/
void Set7dFormat (const std::string &format);
/**
* \param format the 8D format string.
*
* \brief Sets the 8D format string for the C-style sprintf()
* function.
*/
void Set8dFormat (const std::string &format);
/**
* \param format the 9D format string.
*
* \brief Sets the 9D format string for the C-style sprintf()
* function.
*/
void Set9dFormat (const std::string &format);
/**
* \param format the 10D format string.
*
* \brief Sets the 10D format string for the C-style sprintf()
* function.
*/
void Set10dFormat (const std::string &format);
// Below are hooked to connectors exporting data
// They are not overloaded since it confuses the compiler when made
// into callbacks
/**
* \param context specifies the 1D dataset these values came from.
* \param v1 value for the new data point.
*
* \brief Writes 1 value to the file.
*/
void Write1d (std::string context,
double v1);
/**
* \param context specifies the 2D dataset these values came from.
* \param v1 first value for the new data point.
* \param v2 second value for the new data point.
*
* \brief Writes 2 values to the file.
*/
void Write2d (std::string context,
double v1,
double v2);
/**
* \param context specifies the 3D dataset these values came from.
* \param v1 first value for the new data point.
* \param v2 second value for the new data point.
* \param v3 third value for the new data point.
*
* \brief Writes 3 values to the file.
*/
void Write3d (std::string context,
double v1,
double v2,
double v3);
/**
* \param context specifies the 4D dataset these values came from.
* \param v1 first value for the new data point.
* \param v2 second value for the new data point.
* \param v3 third value for the new data point.
* \param v4 fourth value for the new data point.
*
* \brief Writes 4 values to the file.
*/
void Write4d (std::string context,
double v1,
double v2,
double v3,
double v4);
/**
* \param context specifies the 5D dataset these values came from.
* \param v1 first value for the new data point.
* \param v2 second value for the new data point.
* \param v3 third value for the new data point.
* \param v4 fourth value for the new data point.
* \param v5 fifth value for the new data point.
*
* \brief Writes 5 values to the file.
*/
void Write5d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5);
/**
* \param context specifies the 6D dataset these values came from.
* \param v1 first value for the new data point.
* \param v2 second value for the new data point.
* \param v3 third value for the new data point.
* \param v4 fourth value for the new data point.
* \param v5 fifth value for the new data point.
* \param v6 sixth value for the new data point.
*
* \brief Writes 6 values to the file.
*/
void Write6d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5,
double v6);
/**
* \param context specifies the 7D dataset these values came from.
* \param v1 first value for the new data point.
* \param v2 second value for the new data point.
* \param v3 third value for the new data point.
* \param v4 fourth value for the new data point.
* \param v5 fifth value for the new data point.
* \param v6 sixth value for the new data point.
* \param v7 seventh value for the new data point.
*
* \brief Writes 7 values to the file.
*/
void Write7d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5,
double v6,
double v7);
/**
* \param context specifies the 8D dataset these values came from.
* \param v1 first value for the new data point.
* \param v2 second value for the new data point.
* \param v3 third value for the new data point.
* \param v4 fourth value for the new data point.
* \param v5 fifth value for the new data point.
* \param v6 sixth value for the new data point.
* \param v7 seventh value for the new data point.
* \param v8 eighth value for the new data point.
*
* \brief Writes 8 values to the file.
*/
void Write8d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5,
double v6,
double v7,
double v8);
/**
* \param context specifies the 9D dataset these values came from.
* \param v1 first value for the new data point.
* \param v2 second value for the new data point.
* \param v3 third value for the new data point.
* \param v4 fourth value for the new data point.
* \param v5 fifth value for the new data point.
* \param v6 sixth value for the new data point.
* \param v7 seventh value for the new data point.
* \param v8 eighth value for the new data point.
* \param v9 nineth value for the new data point.
*
* \brief Writes 9 values to the file.
*/
void Write9d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5,
double v6,
double v7,
double v8,
double v9);
/**
* \param context specifies the 10D dataset these values came from.
* \param v1 first value for the new data point.
* \param v2 second value for the new data point.
* \param v3 third value for the new data point.
* \param v4 fourth value for the new data point.
* \param v5 fifth value for the new data point.
* \param v6 sixth value for the new data point.
* \param v7 seventh value for the new data point.
* \param v8 eighth value for the new data point.
* \param v9 nineth value for the new data point.
* \param v10 tenth value for the new data point.
*
* \brief Writes 10 values to the file.
*/
void Write10d (std::string context,
double v1,
double v2,
double v3,
double v4,
double v5,
double v6,
double v7,
double v8,
double v9,
double v10);
private:
/// The file name.
std::string m_outputFileName;
/// Used to write values to the file.
std::ofstream m_file;
/// Determines the kind of file written by the aggregator.
enum FileType m_fileType;
/// Printed between values in the file.
std::string m_separator;
/// Indicates if the heading line for the file has been set.
bool m_hasHeadingBeenSet;
/// Heading line for the outputfile.
std::string m_heading;
/// Format strings for C-style sprintf() function.
std::string m_1dFormat;
std::string m_2dFormat;
std::string m_3dFormat;
std::string m_4dFormat;
std::string m_5dFormat;
std::string m_6dFormat;
std::string m_7dFormat;
std::string m_8dFormat;
std::string m_9dFormat;
std::string m_10dFormat;
}; // class FileAggregator
} // namespace ns3
#endif // FILE_AGGREGATOR_H

View File

@@ -0,0 +1,148 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#include <string>
#include <vector>
#include "get-wildcard-matches.h"
#include "ns3/assert.h"
namespace ns3 {
std::string
GetWildcardMatches (const std::string &configPath,
const std::string &matchedPath,
const std::string &wildcardSeparator)
{
// If the Config path is just "*", return the whole matched path.
if (configPath == "*")
{
return matchedPath;
}
std::vector<std::string> nonWildcardTokens;
std::vector<std::size_t> nonWildcardTokenPositions;
size_t nonWildcardTokenCount;
size_t wildcardCount = 0;
// Get the non-wildcard tokens from the Config path.
size_t tokenStart;
size_t asterisk = -1;
do
{
// Find the non-wildcard token.
tokenStart = asterisk + 1;
asterisk = configPath.find ("*", tokenStart);
// If a wildcard character was found, increment this counter.
if (asterisk != std::string::npos)
{
wildcardCount++;
}
// Save this non-wildcard token.
nonWildcardTokens.push_back (configPath.substr (tokenStart, asterisk - tokenStart));
}
while (asterisk != std::string::npos);
// If there are no wildcards, return an empty string.
if (wildcardCount == 0)
{
return "";
}
// Set the number of non-wildcard tokens in the Config path.
nonWildcardTokenCount = nonWildcardTokens.size ();
size_t i;
// Find the positions of the non-wildcard tokens in the matched path.
size_t token;
tokenStart = 0;
for (i = 0; i < nonWildcardTokenCount; i++)
{
// Look for the non-wilcard token.
token = matchedPath.find (nonWildcardTokens[i], tokenStart);
// Make sure that the token is found.
if (token == std::string::npos)
{
NS_ASSERT_MSG (false, "Error: non-wildcard token not found in matched path");
}
// Save the position of this non-wildcard token.
nonWildcardTokenPositions.push_back (token);
// Start looking for the next non-wildcard token after the end of
// this one.
tokenStart = token + nonWildcardTokens[i].size ();
}
std::string wildcardMatches = "";
// Put the text matches from the matched path for each of the
// wildcards in the Config path into a string, separated by the
// specified separator.
size_t wildcardMatchesSet = 0;
size_t matchStart;
size_t matchEnd;
for (i = 0; i < nonWildcardTokenCount; i++)
{
// Find the start and end of this wildcard match.
matchStart = nonWildcardTokenPositions[i] + nonWildcardTokens[i].size ();
if (i != nonWildcardTokenCount - 1)
{
matchEnd = nonWildcardTokenPositions[i + 1] - 1;
}
else
{
matchEnd = matchedPath.length () - 1;
}
// This algorithm gets confused by zero length non-wildcard
// tokens. So, only add this wildcard match and update the
// counters if the match was calculated to start before it began.
if (matchStart <= matchEnd)
{
// Add the wildcard match.
wildcardMatches += matchedPath.substr (matchStart,
matchEnd - matchStart + 1);
// See if all of the wilcard matches have been set.
wildcardMatchesSet++;
if (wildcardMatchesSet == wildcardCount)
{
break;
}
else
{
// If there are still more to set, add the separator to
// the end of the one just added.
wildcardMatches += wildcardSeparator;
}
}
}
// Return the wildcard matches.
return wildcardMatches;
}
} // namespace ns3

View File

@@ -0,0 +1,44 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef GET_WILDCARD_MATCHES_H
#define GET_WILDCARD_MATCHES_H
#include <string>
namespace ns3 {
/**
* \param configPath Config path to access the probe.
* \param matchedPath the path that matched the Config path.
* \param wildcardSeparator the text to put betwen the wildcard
* matches. By default, a space is used.
*
* \brief Returns the text matches from the matched path for each of
* the wildcards in the Config path, separated by the wild card
* separator.
*/
std::string GetWildcardMatches (const std::string &configPath,
const std::string &matchedPath,
const std::string &wildcardSeparator = " ");
} // namespace ns3
#endif // GET_WILDCARD_MATCHES_H

View File

@@ -0,0 +1,327 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#include <iostream>
#include <fstream>
#include <string>
#include "gnuplot-aggregator.h"
#include "ns3/abort.h"
#include "ns3/log.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("GnuplotAggregator");
NS_OBJECT_ENSURE_REGISTERED (GnuplotAggregator);
TypeId
GnuplotAggregator::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::GnuplotAggregator")
.SetParent<DataCollectionObject> ()
;
return tid;
}
GnuplotAggregator::GnuplotAggregator (const std::string &outputFileNameWithoutExtension)
: m_outputFileNameWithoutExtension (outputFileNameWithoutExtension),
m_graphicsFileName (m_outputFileNameWithoutExtension + ".png"),
m_title ("Data Values"),
m_xLegend ("X Values"),
m_yLegend ("Y Values"),
m_titleSet (false),
m_xAndYLegendsSet (false),
m_gnuplot (m_graphicsFileName)
{
}
GnuplotAggregator::~GnuplotAggregator ()
{
// Give any warnings that should be issued.
if (!m_titleSet)
{
NS_LOG_UNCOND ("Warning: The plot title was not set for the gnuplot aggregator");
}
if (!m_xAndYLegendsSet)
{
NS_LOG_UNCOND ("Warning: The axis legends were not set for the gnuplot aggregator");
}
std::string dataFileName = m_outputFileNameWithoutExtension + ".dat";
std::string plotFileName = m_outputFileNameWithoutExtension + ".plt";
std::string scriptFileName = m_outputFileNameWithoutExtension + ".sh";
// Open the gnuplot plot and data files.
std::ofstream plotFile;
plotFile.open (plotFileName.c_str ());
std::ofstream dataFile;
dataFile.open (dataFileName.c_str ());
// Skip any NaN's that appear in data.
m_gnuplot.AppendExtra ("set datafile missing \"-nan\"");
// Write the gnuplot plot and data files.
m_gnuplot.GenerateOutput (plotFile, dataFile, dataFileName);
// Close the gnuplot plot and data files.
plotFile.close ();
dataFile.close ();
// Open the shell script file.
std::ofstream scriptFile;
scriptFile.open (scriptFileName.c_str ());
// Write the shell script file.
scriptFile << "#!/bin/sh" << std::endl;
scriptFile << std::endl;
scriptFile << "gnuplot " << plotFileName << std::endl;
// Close the shell script file.
scriptFile.close ();
}
void
GnuplotAggregator::Write2d (std::string context, double x, double y)
{
if (m_2dDatasetMap.count (context) == 0)
{
NS_ABORT_MSG ("That 2D data set has not been added");
return;
}
if (m_enabled)
{
// Add this 2D data point to its dataset.
m_2dDatasetMap[context].Add (x, y);
}
}
void
GnuplotAggregator::Write2dWithXErrorDelta (std::string context,
double x,
double y,
double errorDelta)
{
// See if this dataset has been added.
if (m_2dDatasetMap.count (context) == 0)
{
NS_ABORT_MSG ("That 2D data set has not been added");
return;
}
if (m_enabled)
{
// Add this 2D data point with its error bar to its dataset.
m_2dDatasetMap[context].Add (x, y, errorDelta);
}
}
void
GnuplotAggregator::Write2dWithYErrorDelta (std::string context,
double x,
double y,
double errorDelta)
{
// See if this dataset has been added.
if (m_2dDatasetMap.count (context) == 0)
{
NS_ABORT_MSG ("That 2D data set has not been added");
return;
}
if (m_enabled)
{
// Add this 2D data point with its error bar to its dataset.
m_2dDatasetMap[context].Add (x, y, errorDelta);
}
}
void
GnuplotAggregator::Write2dWithXYErrorDelta (std::string context,
double x,
double y,
double xErrorDelta,
double yErrorDelta)
{
// See if this dataset has been added.
if (m_2dDatasetMap.count (context) == 0)
{
NS_ABORT_MSG ("That 2D data set has not been added");
return;
}
if (m_enabled)
{
// Add this 2D data point with its error bar to its dataset.
m_2dDatasetMap[context].Add (x, y, xErrorDelta, yErrorDelta);
}
}
void
GnuplotAggregator::SetTerminal (const std::string &terminal)
{
// Change the extension for the graphics file.
m_graphicsFileName = m_outputFileNameWithoutExtension + "." + terminal;
// Update the gnuplot, too.
m_gnuplot.SetTerminal (terminal);
m_gnuplot.SetOutputFilename (m_graphicsFileName);
}
void
GnuplotAggregator::SetTitle (const std::string &title)
{
m_gnuplot.SetTitle (title);
m_titleSet = true;
}
void
GnuplotAggregator::SetLegend (const std::string &xLegend, const std::string &yLegend)
{
m_gnuplot.SetLegend (xLegend, yLegend);
m_xAndYLegendsSet = true;
}
void
GnuplotAggregator::SetExtra (const std::string &extra)
{
m_gnuplot.SetExtra (extra);
}
void
GnuplotAggregator::AppendExtra (const std::string &extra)
{
m_gnuplot.AppendExtra (extra);
}
void
GnuplotAggregator::Add2dDataset (const std::string &dataset, const std::string &title)
{
// See if this dataset had already been added.
if (m_2dDatasetMap.count (dataset) > 0)
{
NS_ABORT_MSG ("That 2D data set has already been added");
}
// Add this dataset to the map so that its values can be saved.
Gnuplot2dDataset gnuplot2dDataset (title);
m_2dDatasetMap[dataset] = gnuplot2dDataset;
// Add this dataset to the plot so that its values can be plotted.
m_gnuplot.AddDataset (m_2dDatasetMap[dataset]);
}
void
GnuplotAggregator::Set2dDatasetDefaultExtra (const std::string &extra)
{
Gnuplot2dDataset::SetDefaultExtra (extra);
}
void
GnuplotAggregator::Set2dDatasetExtra (const std::string &dataset, const std::string &extra)
{
if (m_2dDatasetMap.count (dataset) == 0)
{
NS_ABORT_MSG ("That 2D data set has not been added");
return;
}
// Set the extra parameters for the dataset.
m_2dDatasetMap[dataset].SetExtra (extra);
}
void
GnuplotAggregator::Write2dDatasetEmptyLine (const std::string &dataset)
{
if (m_2dDatasetMap.count (dataset) == 0)
{
NS_ABORT_MSG ("That 2D data set has not been added");
return;
}
if (m_enabled)
{
// Add an empty line to the dataset.
m_2dDatasetMap[dataset].AddEmptyLine ();
}
}
void
GnuplotAggregator::Set2dDatasetDefaultStyle (enum Gnuplot2dDataset::Style style)
{
Gnuplot2dDataset::SetDefaultStyle (style);
}
void
GnuplotAggregator::Set2dDatasetStyle (const std::string &dataset, enum Gnuplot2dDataset::Style style)
{
if (m_2dDatasetMap.count (dataset) == 0)
{
NS_ABORT_MSG ("That 2D data set has not been added");
return;
}
// Set the style for the dataset.
m_2dDatasetMap[dataset].SetStyle (style);
}
void
GnuplotAggregator::Set2dDatasetDefaultErrorBars (enum Gnuplot2dDataset::ErrorBars errorBars)
{
Gnuplot2dDataset::SetDefaultErrorBars (errorBars);
}
void
GnuplotAggregator::Set2dDatasetErrorBars (const std::string &dataset, enum Gnuplot2dDataset::ErrorBars errorBars)
{
if (m_2dDatasetMap.count (dataset) == 0)
{
NS_ABORT_MSG ("That 2D data set has not been added");
return;
}
// Set the error bars for the dataset.
m_2dDatasetMap[dataset].SetErrorBars (errorBars);
}
void
GnuplotAggregator::SetKeyLocation (enum GnuplotAggregator::KeyLocation keyLocation)
{
// Set the specifed key location.
switch (keyLocation)
{
case NO_KEY:
m_gnuplot.AppendExtra ("set key off");
break;
case KEY_ABOVE:
m_gnuplot.AppendExtra ("set key outside center above");
break;
case KEY_BELOW:
m_gnuplot.AppendExtra ("set key outside center below");
break;
default:
m_gnuplot.AppendExtra ("set key inside");
break;
}
}
} // namespace ns3

View File

@@ -0,0 +1,296 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*
*/
#ifndef GNUPLOT_AGGREGATOR_H
#define GNUPLOT_AGGREGATOR_H
#include <map>
#include <string>
#include "ns3/gnuplot.h"
#include "ns3/data-collection-object.h"
namespace ns3 {
/**
* This aggregator produces output used to make gnuplot plots.
**/
class GnuplotAggregator : public DataCollectionObject
{
public:
/// The location of the key in the plot.
enum KeyLocation
{
NO_KEY,
KEY_INSIDE,
KEY_ABOVE,
KEY_BELOW
};
static TypeId GetTypeId ();
/**
* \param outputFileNameWithoutExtension name of gnuplot related
* files to write with no extension
*
* Constructs a gnuplot file aggregator that will create a space
* separated gnuplot data file named outputFileNameWithoutExtension
* + ".dat", a gnuplot control file named
* outputFileNameWithoutExtension + ".plt", and a shell script to
* generate the gnuplot named outputFileNameWithoutExtension +
* ".sh".
*/
GnuplotAggregator (const std::string &outputFileNameWithoutExtension);
virtual ~GnuplotAggregator ();
// Below are hooked to connectors exporting data
// They are not overloaded since it confuses the compiler when made
// into callbacks
/**
* \param context specifies the gnuplot 2D dataset for these values
* \param x x coordinate for the new data point
* \param y y coordinate for the new data point
*
* \brief Writes a 2D value to a 2D gnuplot dataset.
*
* Use this method with error bar style NONE.
*/
void Write2d (std::string context, double x, double y);
/**
* \param context specifies the gnuplot 2D dataset for these values
* \param x x coordinate for the new data point
* \param y y coordinate for the new data point
* \param errorDelta x data point uncertainty
*
* \brief Writes a 2D value to a 2D gnuplot dataset with error bars
* in the x direction.
*
* Use this method with error bar style X.
*/
void Write2dWithXErrorDelta (std::string context,
double x,
double y,
double errorDelta);
/**
* \param context specifies the gnuplot 2D dataset for these values
* \param x x coordinate for the new data point
* \param y y coordinate for the new data point
* \param errorDelta y data point uncertainty
*
* \brief Writes a 2D value to a 2D gnuplot dataset with error bars
* in the y direction.
*
* Use this method with error bar style Y.
*/
void Write2dWithYErrorDelta (std::string context,
double x,
double y,
double errorDelta);
/**
* \param context specifies the gnuplot 2D dataset for these values
* \param x x coordinate for the new data point
* \param y y coordinate for the new data point
* \param xErrorDelta x data point uncertainty
* \param yErrorDelta y data point uncertainty
*
* \brief Writes a 2D value to a 2D gnuplot dataset with error bars
* in the x and y directions.
*
* Use this method with error bar style XY.
*/
void Write2dWithXYErrorDelta (std::string context,
double x,
double y,
double xErrorDelta,
double yErrorDelta);
// Methods to configure the plot
/**
* \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);
// Methods for datasets
/**
* \param dataset the gnuplot 2D dataset to be plotted.
* \param title the title to be associated to this dataset.
*
* \brief Adds a 2D dataset to the plot.
*
* Creates an empty dataset. Usually, the dataset's title is
* displayed in the legend box.
*
* The string in dataset should match the context for the Collector
* it is connected to.
*/
void Add2dDataset (const std::string &dataset, const std::string &title);
/**
* \param extra extra formatting
*
* \brief Change extra formatting style parameters for newly created
* objects.
*/
static void Set2dDatasetDefaultExtra (const std::string &extra);
/**
* \param dataset the gnuplot 2D dataset to be plotted.
* \param extra extra formatting
*
* \brief Add extra formatting parameters to this dataset.
*
* The string in dataset should match the context for the Collector
* it is connected to.
*/
void Set2dDatasetExtra (const std::string &dataset, const std::string &extra);
/**
* \param dataset the gnuplot 2D dataset to be plotted.
*
* \brief Add an empty line in the data output sequence.
*
* Writes an empty line in the plot data, which breaks continuous
* lines and does other things in the output.
*
* The string in dataset should match the context for the Collector
* it is connected to.
*/
void Write2dDatasetEmptyLine (const std::string &dataset);
/**
* \param style the style of plotting to use for newly created datasets.
*
* \brief Change default style for all newly created objects.
*/
static void Set2dDatasetDefaultStyle (enum Gnuplot2dDataset::Style style);
/**
* \param dataset the gnuplot 2D dataset to be plotted.
* \param style the style of plotting to use for this dataset.
*
* \brief Set the style of plotting to use for this dataset.
*
* The string in dataset should match the context for the Collector
* it is connected to.
*/
void Set2dDatasetStyle (const std::string &dataset, enum Gnuplot2dDataset::Style style);
/**
* \param errorBars the style of errorbars to use for newly created datasets.
*
* \brief Change default errorbars style for all newly created objects.
*/
static void Set2dDatasetDefaultErrorBars (enum Gnuplot2dDataset::ErrorBars errorBars);
/**
* \param dataset the gnuplot 2D dataset to be plotted.
* \param errorBars the style of errorbars to display.
*
* \brief Set the error bars to use for this dataset.
*
* 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.
*
* The string in dataset should match the context for the Collector
* it is connected to.
*/
void Set2dDatasetErrorBars (const std::string &dataset, enum Gnuplot2dDataset::ErrorBars errorBars);
/**
* \param keyLocation the location of the key in the plot.
*
* \brief Set the location of the key in the plot.
*/
void SetKeyLocation (enum KeyLocation keyLocation);
private:
/// The output file name without any extension.
std::string m_outputFileNameWithoutExtension;
/// The graphics file name with its extension.
std::string m_graphicsFileName;
/// The title.
std::string m_title;
/// The terminal.
std::string m_terminal;
/// The x legend.
std::string m_xLegend;
/// The y legend.
std::string m_yLegend;
/// The extra gnuplot command that will be added to the gnuplot
/// control statements.
std::string m_extra;
/// Set equal to true after setting the title.
bool m_titleSet;
/// Set equal to true after setting the x and y legends.
bool m_xAndYLegendsSet;
/// Used to create gnuplot files.
Gnuplot m_gnuplot;
/// Maps context strings to 2D datasets.
std::map<std::string, Gnuplot2dDataset> m_2dDatasetMap;
}; // class GnuplotAggregator
} // namespace ns3
#endif // GNUPLOT_AGGREGATOR_H

View File

@@ -50,17 +50,30 @@ struct GnuplotDataset::Data
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.
* 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.
*
* If more than one output file is being generated, i.e. separate
* data and control files, then the index for the current dataset
* and the name for the data file are also included.
*/
virtual void PrintExpression (std::ostream &os) const = 0;
virtual void PrintExpression (std::ostream &os,
bool generateOneOutputFile,
unsigned int dataFileDatasetIndex,
std::string &dataFileName) const = 0;
/**
* Print the inline data file contents trailing the plot command. Empty for
* functions.
*/
virtual void PrintDatafile (std::ostream &os) const = 0;
virtual void PrintDataFile (std::ostream &os, bool generateOneOutputFile) const = 0;
/**
* Checks to see if this GnuplotDataset is empty.
* \return indicates if this GnuplotDataset is empty.
*/
virtual bool IsEmpty () const = 0;
};
GnuplotDataset::Data::Data(const std::string& title)
@@ -142,8 +155,12 @@ struct Gnuplot2dDataset::Data2d : public GnuplotDataset::Data
Data2d(const std::string& title);
virtual std::string GetCommand () const;
virtual void PrintExpression (std::ostream &os) const;
virtual void PrintDatafile (std::ostream &os) const;
virtual void PrintExpression (std::ostream &os,
bool generateOneOutputFile,
unsigned int dataFileDatasetIndex,
std::string &dataFileName) const;
virtual void PrintDataFile (std::ostream &os, bool generateOneOutputFile) const;
virtual bool IsEmpty () const;
};
Gnuplot2dDataset::Data2d::Data2d(const std::string& title)
@@ -160,12 +177,24 @@ Gnuplot2dDataset::Data2d::GetCommand () const
}
void
Gnuplot2dDataset::Data2d::PrintExpression (std::ostream &os) const
Gnuplot2dDataset::Data2d::PrintExpression (std::ostream &os,
bool generateOneOutputFile,
unsigned int dataFileDatasetIndex,
std::string &dataFileName) const
{
os << "'-' ";
// Print the appropriate thing based on whether separate output and
// date files are being generated.
if (generateOneOutputFile)
{
os << "\"-\" ";
}
else
{
os << "\"" << dataFileName << "\" index " << dataFileDatasetIndex;
}
if (m_title.size ())
os << " title '" << m_title << "'";
os << " title \"" << m_title << "\"";
switch (m_style) {
case LINES:
@@ -227,7 +256,7 @@ Gnuplot2dDataset::Data2d::PrintExpression (std::ostream &os) const
}
void
Gnuplot2dDataset::Data2d::PrintDatafile (std::ostream &os) const
Gnuplot2dDataset::Data2d::PrintDataFile (std::ostream &os, bool generateOneOutputFile) const
{
for (PointSet::const_iterator i = m_pointset.begin ();
i != m_pointset.end (); ++i)
@@ -252,7 +281,24 @@ Gnuplot2dDataset::Data2d::PrintDatafile (std::ostream &os) const
break;
}
}
os << "e" << std::endl;
// Print the appropriate thing based on whether separate output and
// date files are being generated.
if (generateOneOutputFile)
{
os << "e" << std::endl;
}
else
{
os << std::endl;
os << std::endl;
}
}
bool
Gnuplot2dDataset::Data2d::IsEmpty () const
{
return (m_pointset.size () == 0);
}
// --- Gnuplot2dDataset ---------------------------------------------------- //
@@ -352,8 +398,12 @@ struct Gnuplot2dFunction::Function2d : public GnuplotDataset::Data
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;
virtual void PrintExpression (std::ostream &os,
bool generateOneOutputFile,
unsigned int dataFileDatasetIndex,
std::string &dataFileName) const;
virtual void PrintDataFile (std::ostream &os, bool generateOneOutputFile) const;
virtual bool IsEmpty () const;
};
Gnuplot2dFunction::Function2d::Function2d(const std::string& title, const std::string& function)
@@ -369,22 +419,31 @@ Gnuplot2dFunction::Function2d::GetCommand () const
}
void
Gnuplot2dFunction::Function2d::PrintExpression (std::ostream &os) const
Gnuplot2dFunction::Function2d::PrintExpression (std::ostream &os,
bool generateOneOutputFile,
unsigned int dataFileDatasetIndex,
std::string &dataFileName) const
{
os << m_function;
if (m_title.size ())
os << " title '" << m_title << "'";
os << " title \"" << m_title << "\"";
if (m_extra.size ())
os << " " << m_extra;
}
void
Gnuplot2dFunction::Function2d::PrintDatafile (std::ostream &os) const
Gnuplot2dFunction::Function2d::PrintDataFile (std::ostream &os, bool generateOneOutputFile) const
{
}
bool
Gnuplot2dFunction::Function2d::IsEmpty () const
{
return false;
}
// --- Gnuplot2dFunction --------------------------------------------------- //
Gnuplot2dFunction::Gnuplot2dFunction (const std::string& title, const std::string& function)
@@ -414,8 +473,12 @@ struct Gnuplot3dDataset::Data3d : public GnuplotDataset::Data
Data3d(const std::string& title);
virtual std::string GetCommand () const;
virtual void PrintExpression (std::ostream &os) const;
virtual void PrintDatafile (std::ostream &os) const;
virtual void PrintExpression (std::ostream &os,
bool generateOneOutputFile,
unsigned int dataFileDatasetIndex,
std::string &dataFileName) const;
virtual void PrintDataFile (std::ostream &os, bool generateOneOutputFile) const;
virtual bool IsEmpty () const;
};
Gnuplot3dDataset::Data3d::Data3d(const std::string& title)
@@ -431,22 +494,25 @@ Gnuplot3dDataset::Data3d::GetCommand () const
}
void
Gnuplot3dDataset::Data3d::PrintExpression (std::ostream &os) const
Gnuplot3dDataset::Data3d::PrintExpression (std::ostream &os,
bool generateOneOutputFile,
unsigned int dataFileDatasetIndex,
std::string &dataFileName) const
{
os << "'-' ";
os << "\"-\" ";
if (m_style.size ())
os << " " << m_style;
if (m_title.size ())
os << " title '" << m_title << "'";
os << " title \"" << m_title << "\"";
if (m_extra.size ())
os << " " << m_extra;
}
void
Gnuplot3dDataset::Data3d::PrintDatafile (std::ostream &os) const
Gnuplot3dDataset::Data3d::PrintDataFile (std::ostream &os, bool generateOneOutputFile) const
{
for (PointSet::const_iterator i = m_pointset.begin ();
i != m_pointset.end (); ++i)
@@ -461,6 +527,12 @@ Gnuplot3dDataset::Data3d::PrintDatafile (std::ostream &os) const
os << "e" << std::endl;
}
bool
Gnuplot3dDataset::Data3d::IsEmpty () const
{
return (m_pointset.size () == 0);
}
// --- Gnuplot3dDataset ---------------------------------------------------- //
std::string Gnuplot3dDataset::m_defaultStyle = "";
@@ -514,8 +586,12 @@ struct Gnuplot3dFunction::Function3d : public GnuplotDataset::Data
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;
virtual void PrintExpression (std::ostream &os,
bool generateOneOutputFile,
unsigned int dataFileDatasetIndex,
std::string &dataFileName) const;
virtual void PrintDataFile (std::ostream &os, bool generateOneOutputFile) const;
virtual bool IsEmpty () const;
};
Gnuplot3dFunction::Function3d::Function3d(const std::string& title, const std::string& function)
@@ -531,22 +607,31 @@ Gnuplot3dFunction::Function3d::GetCommand () const
}
void
Gnuplot3dFunction::Function3d::PrintExpression (std::ostream &os) const
Gnuplot3dFunction::Function3d::PrintExpression (std::ostream &os,
bool generateOneOutputFile,
unsigned int dataFileDatasetIndex,
std::string &dataFileName) const
{
os << m_function;
if (m_title.size ())
os << " title '" << m_title << "'";
os << " title \"" << m_title << "\"";
if (m_extra.size ())
os << " " << m_extra;
}
void
Gnuplot3dFunction::Function3d::PrintDatafile (std::ostream &os) const
Gnuplot3dFunction::Function3d::PrintDataFile (std::ostream &os, bool generateOneOutputFile) const
{
}
bool
Gnuplot3dFunction::Function3d::IsEmpty () const
{
return false;
}
// --- Gnuplot3dFunction --------------------------------------------------- //
Gnuplot3dFunction::Gnuplot3dFunction (const std::string& title, const std::string& function)
@@ -565,10 +650,17 @@ Gnuplot3dFunction::SetFunction (const std::string& function)
Gnuplot::Gnuplot (const std::string& outputFilename, const std::string& title)
: m_outputFilename (outputFilename),
m_terminal ( DetectTerminal (outputFilename) ),
m_title (title)
m_title (title),
m_generateOneOutputFile (false),
m_dataFileDatasetIndex (0)
{
}
void Gnuplot::SetOutputFilename (const std::string& outputFilename)
{
m_outputFilename = outputFilename;
}
std::string Gnuplot::DetectTerminal (const std::string& filename)
{
std::string::size_type dotpos = filename.rfind ('.');
@@ -623,25 +715,38 @@ Gnuplot::AddDataset (const GnuplotDataset& dataset)
}
void
Gnuplot::GenerateOutput (std::ostream &os) const
Gnuplot::GenerateOutput (std::ostream &os)
{
// If this version of this function is called, it is assumed that a
// single output file is being generated.
m_generateOneOutputFile = true;
// Send the gnuplot metadata to the same stream as the data stream.
GenerateOutput (os, os, "");
}
void
Gnuplot::GenerateOutput (std::ostream &osControl,
std::ostream &osData,
std::string dataFileName)
{
if (m_terminal.size ())
os << "set terminal " << m_terminal << std::endl;
osControl << "set terminal " << m_terminal << std::endl;
if (m_outputFilename.size ())
os << "set output '" << m_outputFilename << "'" << std::endl;
osControl << "set output \"" << m_outputFilename << "\"" << std::endl;
if (m_title.size ())
os << "set title '" << m_title << "'" << std::endl;
osControl << "set title \"" << m_title << "\"" << std::endl;
if (m_xLegend.size ())
os << "set xlabel '" << m_xLegend << "'" << std::endl;
osControl << "set xlabel \"" << m_xLegend << "\"" << std::endl;
if (m_yLegend.size ())
os << "set ylabel '" << m_yLegend << "'" << std::endl;
osControl << "set ylabel \"" << m_yLegend << "\"" << std::endl;
if (m_extra.size ())
os << m_extra << std::endl;
osControl << m_extra << std::endl;
if (m_datasets.empty ())
return;
@@ -658,31 +763,49 @@ Gnuplot::GenerateOutput (std::ostream &os) const
"Cannot mix 'plot' and 'splot' GnuplotDatasets.");
}
os << command << " ";
osControl << command << " ";
// Print all dataset expressions
bool isDataEmpty;
for (Datasets::const_iterator i = m_datasets.begin (); i != m_datasets.end ();)
{
i->m_data->PrintExpression (os);
// Only print the dataset if it's not empty.
isDataEmpty = i->m_data->IsEmpty ();
if (!isDataEmpty)
{
// Print the appropriate expression based on whether we are
// generating separate output and date files.
i->m_data->PrintExpression (osControl,
m_generateOneOutputFile,
m_dataFileDatasetIndex,
dataFileName);
m_dataFileDatasetIndex++;
}
i++;
if (i != m_datasets.end ())
if (i != m_datasets.end () && !isDataEmpty)
{
os << ", ";
osControl << ", ";
}
}
os << std::endl;
osControl << 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);
i->m_data->PrintDataFile (osData, m_generateOneOutputFile);
}
}
void
Gnuplot::SetDataFileDatasetIndex (unsigned int index)
{
m_dataFileDatasetIndex = index;
}
// ------------------------------------------------------------------------- //
GnuplotCollection::GnuplotCollection (const std::string& outputFilename)
@@ -713,20 +836,42 @@ GnuplotCollection::GetPlot (unsigned int id)
}
void
GnuplotCollection::GenerateOutput (std::ostream &os) const
GnuplotCollection::GenerateOutput (std::ostream &os)
{
// If this version of this function is called, it is assumed that a
// single output file is being generated.
if (m_terminal.size ())
os << "set terminal " << m_terminal << std::endl;
if (m_outputFilename.size ())
os << "set output '" << m_outputFilename << "'" << std::endl;
os << "set output \"" << m_outputFilename << "\"" << std::endl;
for (Plots::const_iterator i = m_plots.begin (); i != m_plots.end (); ++i)
for (Plots::iterator i = m_plots.begin (); i != m_plots.end (); ++i)
{
i->GenerateOutput (os);
}
}
void
GnuplotCollection::GenerateOutput (std::ostream &osControl, std::ostream &osData,
std::string dataFileName)
{
// If this version of this function is called, it is assumed that
// separate output and date files are being generated.
if (m_terminal.size ())
osControl << "set terminal " << m_terminal << std::endl;
if (m_outputFilename.size ())
osControl << "set output \"" << m_outputFilename << "\"" << std::endl;
for (Plots::iterator i = m_plots.begin (); i != m_plots.end (); ++i)
{
i->GenerateOutput (osControl, osData, dataFileName);
}
}
// ------------------------------------------------------------------------- //
} // namespace ns3

View File

@@ -351,6 +351,13 @@ public:
*/
Gnuplot (const std::string& outputFilename="", const std::string& title = "");
/**
* \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.
*/
void SetOutputFilename (const std::string& outputFilename);
/**
* Crude attempt to auto-detect the correct terminal setting by inspecting
* the filename's extension.
@@ -391,10 +398,37 @@ public:
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.
* \param os the output stream on which the relevant gnuplot
* commands should be generated. Including output file and terminal
* headers.
*
* \brief Writes gnuplot commands and data values to a single
* output stream.
*/
void GenerateOutput (std::ostream &os) const;
void GenerateOutput (std::ostream &os);
/**
* \param osControl the output stream on which the relevant gnuplot
* contol commands should be generated. Including output file and
* terminal headers.
* \param osData the output stream on which the relevant gnuplot
* data values should be generated.
* \param dataFileName the name for the data file that will be
* written.
*
* \brief Writes gnuplot commands and data values to two
* different outputs streams.
*/
void GenerateOutput (std::ostream &osControl,
std::ostream &osData,
std::string dataFileName);
/**
* \param index the index for the data stream in the data file.
*
* \brief Sets the current data stream index in the data file.
*/
void SetDataFileDatasetIndex (unsigned int index);
private:
typedef std::vector<GnuplotDataset> Datasets;
@@ -408,6 +442,10 @@ private:
std::string m_xLegend;
std::string m_yLegend;
std::string m_extra;
bool m_generateOneOutputFile;
unsigned int m_dataFileDatasetIndex;
};
/**
@@ -446,8 +484,21 @@ public:
* \param os the output stream on which the relevant gnuplot commands should
* be generated.
*/
void GenerateOutput (std::ostream &os) const;
void GenerateOutput (std::ostream &os);
/**
* \param osControl the output stream on which the relevant gnuplot
* contol commands should be generated. Including output file and
* terminal headers.
* \param osData the output stream on which the relevant gnuplot
* data values should be generated.
* \param dataFileName the name for the data file that will be
* written.
*/
void GenerateOutput (std::ostream &osControl,
std::ostream &osData,
std::string dataFileName);
private:
typedef std::vector<Gnuplot> Plots;

71
src/stats/model/probe.cc Normal file
View File

@@ -0,0 +1,71 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*/
#include "ns3/probe.h"
#include "ns3/object.h"
#include "ns3/simulator.h"
#include "ns3/log.h"
NS_LOG_COMPONENT_DEFINE ("Probe");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (Probe);
TypeId
Probe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::Probe")
.SetParent<DataCollectionObject> ()
.AddAttribute ("Start",
"Time data collection starts",
TimeValue (Seconds (0)),
MakeTimeAccessor (&Probe::m_start),
MakeTimeChecker ())
.AddAttribute ("Stop",
"Time when data collection stops. The special time value of 0 disables this attribute",
TimeValue (Seconds (0)),
MakeTimeAccessor (&Probe::m_stop),
MakeTimeChecker ())
;
return tid;
}
Probe::Probe ()
{
NS_LOG_FUNCTION (this);
}
Probe::~Probe ()
{
NS_LOG_FUNCTION (this);
}
bool
Probe::IsEnabled (void) const
{
return (DataCollectionObject::IsEnabled ()
&& Simulator::Now () >= m_start
&& (m_stop == Seconds (0) || Simulator::Now () < m_stop));
}
} // namespace ns3

79
src/stats/model/probe.h Normal file
View File

@@ -0,0 +1,79 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*/
#ifndef PROBE_H
#define PROBE_H
#include "ns3/data-collection-object.h"
#include "ns3/nstime.h"
namespace ns3 {
/**
* Base class for probes.
*
* This class provides general functionality to control each
* probe and the data generated by it.
*/
class Probe : public DataCollectionObject
{
public:
static TypeId GetTypeId ();
Probe ();
virtual ~Probe ();
/**
* \return true if Probe is currently enabled
*/
virtual bool IsEnabled (void) const;
/**
* \brief connect to a trace source attribute provided by a given object
*
* \param traceSource the name of the attribute TraceSource to connect to
* \param obj ns3::Object to connect to
* \return true if the trace source was successfully connected
*/
virtual bool ConnectByObject (std::string traceSource, Ptr<Object> obj) = 0;
/**
* \brief connect to a trace source provided by a config path
*
* \param path Config path to bind to
*
* Note, if an invalid path is provided, the probe will not be connected
* to anything.
*/
virtual void ConnectByPath (std::string path) = 0;
protected:
/// Time when logging starts.
Time m_start;
/// Time when logging stops.
Time m_stop;
};
} // namespace ns3
#endif // PROBE_H

View File

@@ -0,0 +1,112 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#include <cmath>
#include <cfloat>
#include "ns3/time-series-adaptor.h"
#include "ns3/object.h"
#include "ns3/traced-value.h"
#include "ns3/log.h"
#include "ns3/simulator.h"
NS_LOG_COMPONENT_DEFINE ("TimeSeriesAdaptor");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (TimeSeriesAdaptor);
TypeId
TimeSeriesAdaptor::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TimeSeriesAdaptor")
.SetParent<DataCollectionObject> ()
.AddConstructor<TimeSeriesAdaptor> ()
.AddTraceSource ( "Output",
"The current simulation time versus the current value converted to a double",
MakeTraceSourceAccessor (&TimeSeriesAdaptor::m_output))
;
return tid;
}
TimeSeriesAdaptor::TimeSeriesAdaptor ()
{
NS_LOG_FUNCTION (this);
}
TimeSeriesAdaptor::~TimeSeriesAdaptor ()
{
NS_LOG_FUNCTION (this);
}
void
TimeSeriesAdaptor::TraceSinkDouble (double oldData, double newData)
{
NS_LOG_FUNCTION (this << oldData << newData);
// Don't do anything if the time series adaptor is not enabled.
if (!IsEnabled ())
{
NS_LOG_DEBUG ("Time series adaptor not enabled");
return;
}
// Time stamp the value with the current time in seconds.
m_output (Simulator::Now ().GetSeconds (), newData);
}
void
TimeSeriesAdaptor::TraceSinkBoolean (bool oldData, bool newData)
{
NS_LOG_FUNCTION (this << oldData << newData);
// Call the trace sink that actually does something.
TraceSinkDouble (oldData, newData);
}
void
TimeSeriesAdaptor::TraceSinkUinteger8 (uint8_t oldData, uint8_t newData)
{
NS_LOG_FUNCTION (this << oldData << newData);
// Call the trace sink that actually does something.
TraceSinkDouble (oldData, newData);
}
void
TimeSeriesAdaptor::TraceSinkUinteger16 (uint16_t oldData, uint16_t newData)
{
NS_LOG_FUNCTION (this << oldData << newData);
// Call the trace sink that actually does something.
TraceSinkDouble (oldData, newData);
}
void
TimeSeriesAdaptor::TraceSinkUinteger32 (uint32_t oldData, uint32_t newData)
{
NS_LOG_FUNCTION (this << oldData << newData);
// Call the trace sink that actually does something.
TraceSinkDouble (oldData, newData);
}
} // namespace ns3

View File

@@ -0,0 +1,115 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 University of Washington
*
* 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: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef TIME_SERIES_ADAPTOR_H
#define TIME_SERIES_ADAPTOR_H
#include "ns3/data-collection-object.h"
#include "ns3/object.h"
#include "ns3/type-id.h"
#include "ns3/traced-value.h"
namespace ns3 {
/**
* \brief Takes probed values of different types and outputs the
* current time plus the value with both converted to doubles.
*
* The role of the TimeSeriesAdaptor class is that of an adaptor
* class, to take raw-valued probe data of different types, and output
* a tuple of two double values. The first is a timestamp which may
* be set to different resolutions (e.g. Seconds, Milliseconds, etc.)
* in the future, but which presently is hardcoded to Seconds. The second
* is the conversion of
* a non-double value to a double value (possibly with loss of precision).
*
* It should be noted that time series adaptors convert
* Simulation Time objects to double values in its output.
*/
class TimeSeriesAdaptor : public DataCollectionObject
{
public:
static TypeId GetTypeId (void);
TimeSeriesAdaptor ();
virtual ~TimeSeriesAdaptor ();
/**
* \brief Trace sink for receiving data from double valued trace
* sources.
* \param oldData the original value.
* \param newData the new value.
*
* This method serves as a trace sink to double valued trace
* sources.
*/
void TraceSinkDouble (double oldData, double newData);
/**
* \brief Trace sink for receiving data from bool valued trace
* sources.
* \param oldData the original value.
* \param newData the new value.
*
* This method serves as a trace sink to bool valued trace
* sources.
*/
void TraceSinkBoolean (bool oldData, bool newData);
/**
* \brief Trace sink for receiving data from uint8_t valued trace
* sources.
* \param oldData the original value.
* \param newData the new value.
*
* This method serves as a trace sink to uint8_t valued trace
* sources.
*/
void TraceSinkUinteger8 (uint8_t oldData, uint8_t newData);
/**
* \brief Trace sink for receiving data from uint16_t valued trace
* sources.
* \param oldData the original value.
* \param newData the new value.
*
* This method serves as a trace sink to uint16_t valued trace
* sources.
*/
void TraceSinkUinteger16 (uint16_t oldData, uint16_t newData);
/**
* \brief Trace sink for receiving data from uint32_t valued trace
* sources.
* \param oldData the original value.
* \param newData the new value.
*
* This method serves as a trace sink to uint32_t valued trace
* sources.
*/
void TraceSinkUinteger32 (uint32_t oldData, uint32_t newData);
private:
TracedCallback<double, double> m_output;
};
} // namespace ns3
#endif // TIME_SERIES_ADAPTOR_H

View File

@@ -0,0 +1,109 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#include "ns3/uinteger-16-probe.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/config.h"
#include "ns3/trace-source-accessor.h"
NS_LOG_COMPONENT_DEFINE ("Uinteger16Probe");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (Uinteger16Probe);
TypeId
Uinteger16Probe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::Uinteger16Probe")
.SetParent<Probe> ()
.AddConstructor<Uinteger16Probe> ()
.AddTraceSource ( "Output",
"The uint16_t that serves as output for this probe",
MakeTraceSourceAccessor (&Uinteger16Probe::m_output))
;
return tid;
}
Uinteger16Probe::Uinteger16Probe ()
{
NS_LOG_FUNCTION (this);
m_output = 0;
}
Uinteger16Probe::~Uinteger16Probe ()
{
NS_LOG_FUNCTION (this);
}
uint16_t
Uinteger16Probe::GetValue (void) const
{
NS_LOG_FUNCTION (this);
return m_output;
}
void
Uinteger16Probe::SetValue (uint16_t newVal)
{
NS_LOG_FUNCTION (this << newVal);
m_output = newVal;
}
void
Uinteger16Probe::SetValueByPath (std::string path, uint16_t newVal)
{
NS_LOG_FUNCTION (path << newVal);
Ptr<Uinteger16Probe> probe = Names::Find<Uinteger16Probe> (path);
NS_ASSERT_MSG (probe, "Error: Can't find probe for path " << path);
probe->SetValue (newVal);
}
bool
Uinteger16Probe::ConnectByObject (std::string traceSource, Ptr<Object> obj)
{
NS_LOG_FUNCTION (this << traceSource << obj);
NS_LOG_DEBUG ("Name of probe (if any) in names database: " << Names::FindPath (obj));
bool connected = obj->TraceConnectWithoutContext (traceSource, MakeCallback (&ns3::Uinteger16Probe::TraceSink, this));
return connected;
}
void
Uinteger16Probe::ConnectByPath (std::string path)
{
NS_LOG_FUNCTION (this << path);
NS_LOG_DEBUG ("Name of probe to search for in config database: " << path);
Config::ConnectWithoutContext (path, MakeCallback (&ns3::Uinteger16Probe::TraceSink, this));
}
void
Uinteger16Probe::TraceSink (uint16_t oldData, uint16_t newData)
{
NS_LOG_FUNCTION (this << oldData << newData);
if (IsEnabled ())
{
m_output = newData;
}
}
} // namespace ns3

View File

@@ -0,0 +1,101 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef UINTEGER_16_PROBE_H
#define UINTEGER_16_PROBE_H
#include "ns3/callback.h"
#include "ns3/probe.h"
#include "ns3/traced-value.h"
namespace ns3 {
/**
* This class is designed to probe an underlying ns3 TraceSource exporting
* an uint16_t. This probe exports a trace source "Output" of type uint16_t.
* The Output trace source emits a value when either the trace source
* emits a new value, or when SetValue () is called.
*
* The current value of the probe can be polled with the GetValue () method.
*/
class Uinteger16Probe : public Probe
{
public:
static TypeId GetTypeId ();
Uinteger16Probe ();
virtual ~Uinteger16Probe ();
/**
* \return the most recent value
*/
uint16_t GetValue (void) const;
/**
* \param value set the traced uint16_t to a new value
*/
void SetValue (uint16_t value);
/**
* \brief Set a probe value by its name in the Config system
*
* \param path Config path to access the probe
* \param value set the traced uint16_t to a new value
*/
static void SetValueByPath (std::string path, uint16_t value);
/**
* \brief connect to a trace source attribute provided by a given object
*
* \param traceSource the name of the attribute TraceSource to connect to
* \param obj ns3::Object to connect to
* \return true if the trace source was successfully connected
*/
virtual bool ConnectByObject (std::string traceSource, Ptr<Object> obj);
/**
* \brief connect to a trace source provided by a config path
*
* \param path Config path to bind to
*
* Note, if an invalid path is provided, the probe will not be connected
* to anything.
*/
virtual void ConnectByPath (std::string path);
private:
/**
* \brief Method to connect to an underlying ns3::TraceSource of type uint16_t
*
* \param oldData previous value of the uint16_t
* \param newData new value of the uint16_t
*
* \internal
*/
void TraceSink (uint16_t oldData, uint16_t newData);
TracedValue<uint16_t> m_output;
};
} // namespace ns3
#endif // UINTEGER_16_PROBE_H

View File

@@ -0,0 +1,109 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#include "ns3/uinteger-32-probe.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/config.h"
#include "ns3/trace-source-accessor.h"
NS_LOG_COMPONENT_DEFINE ("Uinteger32Probe");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (Uinteger32Probe);
TypeId
Uinteger32Probe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::Uinteger32Probe")
.SetParent<Probe> ()
.AddConstructor<Uinteger32Probe> ()
.AddTraceSource ( "Output",
"The uint32_t that serves as output for this probe",
MakeTraceSourceAccessor (&Uinteger32Probe::m_output))
;
return tid;
}
Uinteger32Probe::Uinteger32Probe ()
{
NS_LOG_FUNCTION (this);
m_output = 0;
}
Uinteger32Probe::~Uinteger32Probe ()
{
NS_LOG_FUNCTION (this);
}
uint32_t
Uinteger32Probe::GetValue (void) const
{
NS_LOG_FUNCTION (this);
return m_output;
}
void
Uinteger32Probe::SetValue (uint32_t newVal)
{
NS_LOG_FUNCTION (this << newVal);
m_output = newVal;
}
void
Uinteger32Probe::SetValueByPath (std::string path, uint32_t newVal)
{
NS_LOG_FUNCTION (path << newVal);
Ptr<Uinteger32Probe> probe = Names::Find<Uinteger32Probe> (path);
NS_ASSERT_MSG (probe, "Error: Can't find probe for path " << path);
probe->SetValue (newVal);
}
bool
Uinteger32Probe::ConnectByObject (std::string traceSource, Ptr<Object> obj)
{
NS_LOG_FUNCTION (this << traceSource << obj);
NS_LOG_DEBUG ("Name of probe (if any) in names database: " << Names::FindPath (obj));
bool connected = obj->TraceConnectWithoutContext (traceSource, MakeCallback (&ns3::Uinteger32Probe::TraceSink, this));
return connected;
}
void
Uinteger32Probe::ConnectByPath (std::string path)
{
NS_LOG_FUNCTION (this << path);
NS_LOG_DEBUG ("Name of probe to search for in config database: " << path);
Config::ConnectWithoutContext (path, MakeCallback (&ns3::Uinteger32Probe::TraceSink, this));
}
void
Uinteger32Probe::TraceSink (uint32_t oldData, uint32_t newData)
{
NS_LOG_FUNCTION (this << oldData << newData);
if (IsEnabled ())
{
m_output = newData;
}
}
} // namespace ns3

View File

@@ -0,0 +1,101 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef UINTEGER_32_PROBE_H
#define UINTEGER_32_PROBE_H
#include "ns3/callback.h"
#include "ns3/probe.h"
#include "ns3/traced-value.h"
namespace ns3 {
/**
* This class is designed to probe an underlying ns3 TraceSource exporting
* an uint32_t. This probe exports a trace source "Output" of type uint32_t.
* The Output trace source emits a value when either the trace source
* emits a new value, or when SetValue () is called.
*
* The current value of the probe can be polled with the GetValue () method.
*/
class Uinteger32Probe : public Probe
{
public:
static TypeId GetTypeId ();
Uinteger32Probe ();
virtual ~Uinteger32Probe ();
/**
* \return the most recent value
*/
uint32_t GetValue (void) const;
/**
* \param value set the traced uint32_t to a new value
*/
void SetValue (uint32_t value);
/**
* \brief Set a probe value by its name in the Config system
*
* \param path Config path to access the probe
* \param value set the traced uint32_t to a new value
*/
static void SetValueByPath (std::string path, uint32_t value);
/**
* \brief connect to a trace source attribute provided by a given object
*
* \param traceSource the name of the attribute TraceSource to connect to
* \param obj ns3::Object to connect to
* \return true if the trace source was successfully connected
*/
virtual bool ConnectByObject (std::string traceSource, Ptr<Object> obj);
/**
* \brief connect to a trace source provided by a config path
*
* \param path Config path to bind to
*
* Note, if an invalid path is provided, the probe will not be connected
* to anything.
*/
virtual void ConnectByPath (std::string path);
private:
/**
* \brief Method to connect to an underlying ns3::TraceSource of type uint32_t
*
* \param oldData previous value of the uint32_t
* \param newData new value of the uint32_t
*
* \internal
*/
void TraceSink (uint32_t oldData, uint32_t newData);
TracedValue<uint32_t> m_output;
};
} // namespace ns3
#endif // UINTEGER_32_PROBE_H

View File

@@ -0,0 +1,109 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#include "ns3/uinteger-8-probe.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/config.h"
#include "ns3/trace-source-accessor.h"
NS_LOG_COMPONENT_DEFINE ("Uinteger8Probe");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (Uinteger8Probe);
TypeId
Uinteger8Probe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::Uinteger8Probe")
.SetParent<Probe> ()
.AddConstructor<Uinteger8Probe> ()
.AddTraceSource ( "Output",
"The uint8_t that serves as output for this probe",
MakeTraceSourceAccessor (&Uinteger8Probe::m_output))
;
return tid;
}
Uinteger8Probe::Uinteger8Probe ()
{
NS_LOG_FUNCTION (this);
m_output = 0;
}
Uinteger8Probe::~Uinteger8Probe ()
{
NS_LOG_FUNCTION (this);
}
uint8_t
Uinteger8Probe::GetValue (void) const
{
NS_LOG_FUNCTION (this);
return m_output;
}
void
Uinteger8Probe::SetValue (uint8_t newVal)
{
NS_LOG_FUNCTION (this << newVal);
m_output = newVal;
}
void
Uinteger8Probe::SetValueByPath (std::string path, uint8_t newVal)
{
NS_LOG_FUNCTION (path << newVal);
Ptr<Uinteger8Probe> probe = Names::Find<Uinteger8Probe> (path);
NS_ASSERT_MSG (probe, "Error: Can't find probe for path " << path);
probe->SetValue (newVal);
}
bool
Uinteger8Probe::ConnectByObject (std::string traceSource, Ptr<Object> obj)
{
NS_LOG_FUNCTION (this << traceSource << obj);
NS_LOG_DEBUG ("Name of probe (if any) in names database: " << Names::FindPath (obj));
bool connected = obj->TraceConnectWithoutContext (traceSource, MakeCallback (&ns3::Uinteger8Probe::TraceSink, this));
return connected;
}
void
Uinteger8Probe::ConnectByPath (std::string path)
{
NS_LOG_FUNCTION (this << path);
NS_LOG_DEBUG ("Name of probe to search for in config database: " << path);
Config::ConnectWithoutContext (path, MakeCallback (&ns3::Uinteger8Probe::TraceSink, this));
}
void
Uinteger8Probe::TraceSink (uint8_t oldData, uint8_t newData)
{
NS_LOG_FUNCTION (this << oldData << newData);
if (IsEnabled ())
{
m_output = newData;
}
}
} // namespace ns3

View File

@@ -0,0 +1,101 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Bucknell University
*
* 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: L. Felipe Perrone (perrone@bucknell.edu)
* Tiago G. Rodrigues (tgr002@bucknell.edu)
*
* Modified by: Mitch Watrous (watrous@u.washington.edu)
*/
#ifndef UINTEGER_8_PROBE_H
#define UINTEGER_8_PROBE_H
#include "ns3/callback.h"
#include "ns3/probe.h"
#include "ns3/traced-value.h"
namespace ns3 {
/**
* This class is designed to probe an underlying ns3 TraceSource exporting
* an uint8_t. This probe exports a trace source "Output" of type uint8_t.
* The Output trace source emits a value when either the trace source
* emits a new value, or when SetValue () is called.
*
* The current value of the probe can be polled with the GetValue () method.
*/
class Uinteger8Probe : public Probe
{
public:
static TypeId GetTypeId ();
Uinteger8Probe ();
virtual ~Uinteger8Probe ();
/**
* \return the most recent value
*/
uint8_t GetValue (void) const;
/**
* \param value set the traced uint8_t to a new value
*/
void SetValue (uint8_t value);
/**
* \brief Set a probe value by its name in the Config system
*
* \param path Config path to access the probe
* \param value set the traced uint8_t to a new value
*/
static void SetValueByPath (std::string path, uint8_t value);
/**
* \brief connect to a trace source attribute provided by a given object
*
* \param traceSource the name of the attribute TraceSource to connect to
* \param obj ns3::Object to connect to
* \return true if the trace source was successfully connected
*/
virtual bool ConnectByObject (std::string traceSource, Ptr<Object> obj);
/**
* \brief connect to a trace source provided by a config path
*
* \param path Config path to bind to
*
* Note, if an invalid path is provided, the probe will not be connected
* to anything.
*/
virtual void ConnectByPath (std::string path);
private:
/**
* \brief Method to connect to an underlying ns3::TraceSource of type uint8_t
*
* \param oldData previous value of the uint8_t
* \param newData new value of the uint8_t
*
* \internal
*/
void TraceSink (uint8_t oldData, uint8_t newData);
TracedValue<uint8_t> m_output;
};
} // namespace ns3
#endif // UINTEGER_8_PROBE_H

View File

@@ -0,0 +1,165 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
// Include a header file from your module to test.
#include "ns3/double-probe.h"
#include "ns3/test.h"
#include "ns3/core-module.h"
using namespace ns3;
class SampleEmitter : public Object
{
public:
static TypeId GetTypeId (void);
SampleEmitter ()
{
}
virtual ~SampleEmitter ()
{
}
void Start ()
{
Reschedule ();
}
void Reschedule ()
{
m_time = m_var.GetValue ();
Simulator::Schedule (Seconds (m_time), &SampleEmitter::Report, this);
m_time += Simulator::Now ().GetSeconds ();
}
double GetTime ()
{
return m_time;
}
double GetValue ()
{
return aux;
}
private:
void Report ()
{
aux = m_var.GetValue ();
m_trace = aux;
Reschedule ();
}
ExponentialVariable m_var;
double m_time;
TracedValue<double> m_trace;
double aux;
};
Ptr<SampleEmitter> s = CreateObject<SampleEmitter> ();
TypeId
SampleEmitter::GetTypeId (void)
{
static TypeId tid = TypeId ("SampleEmitter")
.SetParent<Object> ()
.AddTraceSource ("Emitter", "XX", MakeTraceSourceAccessor (&SampleEmitter::m_trace))
;
return tid;
}
class ProbeTestCase1 : public TestCase
{
public:
ProbeTestCase1 ();
virtual ~ProbeTestCase1 ();
private:
virtual void DoRun (void);
void TraceSink (std::string context, double oldValue, double newValue);
uint32_t m_objectProbed;
uint32_t m_pathProbed;
};
ProbeTestCase1::ProbeTestCase1 ()
: TestCase ("basic probe test case"),
m_objectProbed (0),
m_pathProbed (0)
{
}
ProbeTestCase1::~ProbeTestCase1 ()
{
}
void
ProbeTestCase1::TraceSink (std::string context, double oldValue, double newValue)
{
NS_TEST_ASSERT_MSG_GT (Simulator::Now (), Seconds (100), "Probed a value outside of the time window");
NS_TEST_ASSERT_MSG_LT (Simulator::Now (), Seconds (200), "Probed a value outside of the time window");
NS_TEST_ASSERT_MSG_EQ_TOL (s->GetValue (), newValue, 0.00001, "Value probed different than value in the variable");
if (context == "testProbe")
{
m_objectProbed++;
}
else if (context == "testProbe2")
{
m_pathProbed++;
}
}
void
ProbeTestCase1::DoRun (void)
{
// Test that all instances of probe data are between time window specified
// Check also that probes can be hooked to sources by Object and by path
Ptr<DoubleProbe> p = CreateObject<DoubleProbe> ();
p->SetName ("testProbe");
Simulator::Schedule (Seconds (1), &SampleEmitter::Start, s);
p->SetAttribute ("Start", TimeValue (Seconds (100.0)));
p->SetAttribute ("Stop", TimeValue (Seconds (200.0)));
Simulator::Stop (Seconds (300));
// Register our emitter object so we can fetch it by using the Config
// namespace
Names::Add ("/Names/SampleEmitter", s);
// Hook probe to the emitter.
p->ConnectByObject ("Emitter", s);
// Hook our test function to the probe trace source
p->TraceConnect ("Output", p->GetName (), MakeCallback (&ProbeTestCase1::TraceSink, this));
// Repeat but hook the probe to the object this time using the Config
// name set above
Ptr<DoubleProbe> p2 = CreateObject<DoubleProbe> ();
p2->SetName ("testProbe2");
p2->SetAttribute ("Start", TimeValue (Seconds (100.0)));
p2->SetAttribute ("Stop", TimeValue (Seconds (200.0)));
// Hook probe to the emitter.
p2->ConnectByPath ("/Names/SampleEmitter/Emitter");
// Hook our test function to the probe trace source
p2->TraceConnect ("Output", p2->GetName (), MakeCallback (&ProbeTestCase1::TraceSink, this));
Simulator::Run ();
// Check that each trace sink was called
NS_TEST_ASSERT_MSG_GT (m_objectProbed, 0, "Trace sink for object probe never called");
NS_TEST_ASSERT_MSG_GT (m_pathProbed, 0, "Trace sink for path probe never called");
Simulator::Destroy ();
}
class ProbeTestSuite : public TestSuite
{
public:
ProbeTestSuite ();
};
ProbeTestSuite::ProbeTestSuite ()
: TestSuite ("double-probe", UNIT)
{
AddTestCase (new ProbeTestCase1, TestCase::QUICK);
}
// Do not forget to allocate an instance of this TestSuite
static ProbeTestSuite probeTestSuite;

View File

@@ -8,7 +8,12 @@
#
# See test.py for more information.
cpp_examples = [
("double-probe-example", "True", "True"),
("file-aggregator-example", "True", "True"),
("file-helper-example", "True", "True"),
("gnuplot-aggregator-example", "True", "True"),
("gnuplot-example", "False", "False"),
("gnuplot-helper-example", "True", "True"),
]
# A list of Python examples to run in order to ensure that they remain

View File

@@ -11,29 +11,44 @@ def configure(conf):
"library 'sqlite3' not found")
def build(bld):
obj = bld.create_ns3_module('stats', ['network'])
obj = bld.create_ns3_module('stats', ['core'])
obj.source = [
'helper/delay-jitter-estimation.cc',
'helper/file-helper.cc',
'helper/gnuplot-helper.cc',
'model/data-calculator.cc',
'model/packet-data-calculators.cc',
'model/time-data-calculators.cc',
'model/data-output-interface.cc',
'model/omnet-data-output.cc',
'model/data-collector.cc',
'model/gnuplot.cc',
'helper/delay-jitter-estimation.cc',
'model/data-collection-object.cc',
'model/probe.cc',
'model/boolean-probe.cc',
'model/double-probe.cc',
'model/uinteger-8-probe.cc',
'model/uinteger-16-probe.cc',
'model/uinteger-32-probe.cc',
'model/time-series-adaptor.cc',
'model/file-aggregator.cc',
'model/gnuplot-aggregator.cc',
'model/get-wildcard-matches.cc',
]
module_test = bld.create_ns3_module_test_library('stats')
module_test.source = [
'test/basic-data-calculators-test-suite.cc',
'test/average-test-suite.cc',
'test/double-probe-test-suite.cc',
]
headers = bld(features='ns3header')
headers.module = 'stats'
headers.source = [
'helper/delay-jitter-estimation.h',
'helper/file-helper.h',
'helper/gnuplot-helper.h',
'model/data-calculator.h',
'model/packet-data-calculators.h',
'model/time-data-calculators.h',
'model/basic-data-calculators.h',
'model/data-output-interface.h',
@@ -41,7 +56,17 @@ def build(bld):
'model/data-collector.h',
'model/gnuplot.h',
'model/average.h',
'helper/delay-jitter-estimation.h',
'model/data-collection-object.h',
'model/probe.h',
'model/boolean-probe.h',
'model/double-probe.h',
'model/uinteger-8-probe.h',
'model/uinteger-16-probe.h',
'model/uinteger-32-probe.h',
'model/time-series-adaptor.h',
'model/file-aggregator.h',
'model/gnuplot-aggregator.h',
'model/get-wildcard-matches.h',
]
if bld.env['SQLITE_STATS']: