Files
unison/src/flow-monitor/model/flow-monitor.cc

570 lines
17 KiB
C++
Raw Normal View History

2009-08-31 18:50:38 +01:00
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
//
// Copyright (c) 2009 INESC Porto
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation;
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt> <gjcarneiro@gmail.com>
//
#include "flow-monitor.h"
#include "ns3/simulator.h"
#include "ns3/log.h"
#include "ns3/double.h"
#include <fstream>
#include <sstream>
#define PERIODIC_CHECK_INTERVAL (Seconds (1))
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("FlowMonitor");
NS_OBJECT_ENSURE_REGISTERED (FlowMonitor);
2011-05-13 14:54:37 -04:00
2009-08-31 18:50:38 +01:00
TypeId
FlowMonitor::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::FlowMonitor")
.SetParent<Object> ()
2015-03-29 11:30:06 +02:00
.SetGroupName ("FlowMonitor")
2009-08-31 18:50:38 +01:00
.AddConstructor<FlowMonitor> ()
.AddAttribute ("MaxPerHopDelay", ("The maximum per-hop delay that should be considered. "
"Packets still not received after this delay are to be considered lost."),
TimeValue (Seconds (10.0)),
MakeTimeAccessor (&FlowMonitor::m_maxPerHopDelay),
MakeTimeChecker ())
.AddAttribute ("StartTime", ("The time when the monitoring starts."),
TimeValue (Seconds (0.0)),
MakeTimeAccessor (&FlowMonitor::Start),
MakeTimeChecker ())
.AddAttribute ("DelayBinWidth", ("The width used in the delay histogram."),
DoubleValue (0.001),
MakeDoubleAccessor (&FlowMonitor::m_delayBinWidth),
MakeDoubleChecker <double> ())
.AddAttribute ("JitterBinWidth", ("The width used in the jitter histogram."),
DoubleValue (0.001),
MakeDoubleAccessor (&FlowMonitor::m_jitterBinWidth),
2011-05-13 14:54:37 -04:00
MakeDoubleChecker <double> ())
2009-08-31 18:50:38 +01:00
.AddAttribute ("PacketSizeBinWidth", ("The width used in the packetSize histogram."),
DoubleValue (20),
MakeDoubleAccessor (&FlowMonitor::m_packetSizeBinWidth),
MakeDoubleChecker <double> ())
.AddAttribute ("FlowInterruptionsBinWidth", ("The width used in the flowInterruptions histogram."),
DoubleValue (0.250),
MakeDoubleAccessor (&FlowMonitor::m_flowInterruptionsBinWidth),
MakeDoubleChecker <double> ())
.AddAttribute ("FlowInterruptionsMinTime", ("The minimum inter-arrival time that is considered a flow interruption."),
TimeValue (Seconds (0.5)),
MakeTimeAccessor (&FlowMonitor::m_flowInterruptionsMinTime),
MakeTimeChecker ())
2011-05-13 14:54:37 -04:00
;
2009-08-31 18:50:38 +01:00
return tid;
}
TypeId
FlowMonitor::GetInstanceTypeId (void) const
{
return GetTypeId ();
}
FlowMonitor::FlowMonitor ()
2011-05-13 14:54:37 -04:00
: m_enabled (false)
2009-08-31 18:50:38 +01:00
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this);
#ifdef NS3_MTP
m_lock.store (false, std::memory_order_relaxed);
#endif
2009-08-31 18:50:38 +01:00
}
void
FlowMonitor::DoDispose (void)
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this);
Simulator::Cancel (m_startEvent);
Simulator::Cancel (m_stopEvent);
for (std::list<Ptr<FlowClassifier> >::iterator iter = m_classifiers.begin ();
iter != m_classifiers.end ();
iter ++)
{
*iter = 0;
}
for (uint32_t i = 0; i < m_flowProbes.size (); i++)
{
m_flowProbes[i]->Dispose ();
m_flowProbes[i] = 0;
}
Object::DoDispose ();
}
2009-08-31 18:50:38 +01:00
inline FlowMonitor::FlowStats&
FlowMonitor::GetStatsForFlow (FlowId flowId)
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this);
FlowStatsContainerI iter;
2009-08-31 18:50:38 +01:00
iter = m_flowStats.find (flowId);
if (iter == m_flowStats.end ())
{
FlowMonitor::FlowStats &ref = m_flowStats[flowId];
ref.delaySum = Seconds (0);
ref.jitterSum = Seconds (0);
ref.lastDelay = Seconds (0);
ref.txBytes = 0;
ref.rxBytes = 0;
ref.txPackets = 0;
ref.rxPackets = 0;
ref.lostPackets = 0;
ref.timesForwarded = 0;
ref.delayHistogram.SetDefaultBinWidth (m_delayBinWidth);
ref.jitterHistogram.SetDefaultBinWidth (m_jitterBinWidth);
ref.packetSizeHistogram.SetDefaultBinWidth (m_packetSizeBinWidth);
ref.flowInterruptionsHistogram.SetDefaultBinWidth (m_flowInterruptionsBinWidth);
2009-08-31 18:50:38 +01:00
return ref;
}
else
{
return iter->second;
}
}
void
FlowMonitor::ReportFirstTx (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this << probe << flowId << packetId << packetSize);
2009-08-31 18:50:38 +01:00
if (!m_enabled)
{
2019-01-29 10:27:12 -08:00
NS_LOG_DEBUG ("FlowMonitor not enabled; returning");
2009-08-31 18:50:38 +01:00
return;
}
Time now = Simulator::Now ();
#ifdef NS3_MTP
while (m_lock.exchange (true, std::memory_order_acquire))
;
#endif
2009-08-31 18:50:38 +01:00
TrackedPacket &tracked = m_trackedPackets[std::make_pair (flowId, packetId)];
tracked.firstSeenTime = now;
tracked.lastSeenTime = tracked.firstSeenTime;
tracked.timesForwarded = 0;
NS_LOG_DEBUG ("ReportFirstTx: adding tracked packet (flowId=" << flowId << ", packetId=" << packetId
2011-05-13 14:54:37 -04:00
<< ").");
2009-08-31 18:50:38 +01:00
probe->AddPacketStats (flowId, packetSize, Seconds (0));
FlowStats &stats = GetStatsForFlow (flowId);
stats.txBytes += packetSize;
stats.txPackets++;
if (stats.txPackets == 1)
{
stats.timeFirstTxPacket = now;
}
stats.timeLastTxPacket = now;
#ifdef NS3_MTP
m_lock.store (false, std::memory_order_release);
#endif
2009-08-31 18:50:38 +01:00
}
void
FlowMonitor::ReportForwarding (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this << probe << flowId << packetId << packetSize);
2009-08-31 18:50:38 +01:00
if (!m_enabled)
{
2019-01-29 10:27:12 -08:00
NS_LOG_DEBUG ("FlowMonitor not enabled; returning");
2009-08-31 18:50:38 +01:00
return;
}
#ifdef NS3_MTP
while (m_lock.exchange (true, std::memory_order_acquire))
;
#endif
2009-08-31 18:50:38 +01:00
std::pair<FlowId, FlowPacketId> key (flowId, packetId);
TrackedPacketMap::iterator tracked = m_trackedPackets.find (key);
if (tracked == m_trackedPackets.end ())
{
NS_LOG_WARN ("Received packet forward report (flowId=" << flowId << ", packetId=" << packetId
2011-05-13 14:54:37 -04:00
<< ") but not known to be transmitted.");
2009-08-31 18:50:38 +01:00
return;
}
tracked->second.timesForwarded++;
tracked->second.lastSeenTime = Simulator::Now ();
Time delay = (Simulator::Now () - tracked->second.firstSeenTime);
probe->AddPacketStats (flowId, packetSize, delay);
#ifdef NS3_MTP
m_lock.store (false, std::memory_order_release);
#endif
2009-08-31 18:50:38 +01:00
}
void
FlowMonitor::ReportLastRx (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this << probe << flowId << packetId << packetSize);
2009-08-31 18:50:38 +01:00
if (!m_enabled)
{
2019-01-29 10:27:12 -08:00
NS_LOG_DEBUG ("FlowMonitor not enabled; returning");
2009-08-31 18:50:38 +01:00
return;
}
#ifdef NS3_MTP
while (m_lock.exchange (true, std::memory_order_acquire))
;
#endif
2009-08-31 18:50:38 +01:00
TrackedPacketMap::iterator tracked = m_trackedPackets.find (std::make_pair (flowId, packetId));
if (tracked == m_trackedPackets.end ())
{
NS_LOG_WARN ("Received packet last-tx report (flowId=" << flowId << ", packetId=" << packetId
2011-05-13 14:54:37 -04:00
<< ") but not known to be transmitted.");
2009-08-31 18:50:38 +01:00
return;
}
Time now = Simulator::Now ();
Time delay = (now - tracked->second.firstSeenTime);
probe->AddPacketStats (flowId, packetSize, delay);
FlowStats &stats = GetStatsForFlow (flowId);
stats.delaySum += delay;
stats.delayHistogram.AddValue (delay.GetSeconds ());
if (stats.rxPackets > 0 )
{
Time jitter = stats.lastDelay - delay;
if (jitter > Seconds (0))
2011-05-13 14:54:37 -04:00
{
stats.jitterSum += jitter;
stats.jitterHistogram.AddValue (jitter.GetSeconds ());
}
2009-08-31 18:50:38 +01:00
else
2011-05-13 14:54:37 -04:00
{
stats.jitterSum -= jitter;
stats.jitterHistogram.AddValue (-jitter.GetSeconds ());
2011-05-13 14:54:37 -04:00
}
2009-08-31 18:50:38 +01:00
}
stats.lastDelay = delay;
2011-05-13 14:54:37 -04:00
2009-08-31 18:50:38 +01:00
stats.rxBytes += packetSize;
stats.packetSizeHistogram.AddValue ((double) packetSize);
stats.rxPackets++;
if (stats.rxPackets == 1)
{
stats.timeFirstRxPacket = now;
}
else
{
// measure possible flow interruptions
Time interArrivalTime = now - stats.timeLastRxPacket;
if (interArrivalTime > m_flowInterruptionsMinTime)
{
stats.flowInterruptionsHistogram.AddValue (interArrivalTime.GetSeconds ());
}
}
2009-08-31 18:50:38 +01:00
stats.timeLastRxPacket = now;
stats.timesForwarded += tracked->second.timesForwarded;
NS_LOG_DEBUG ("ReportLastTx: removing tracked packet (flowId="
<< flowId << ", packetId=" << packetId << ").");
m_trackedPackets.erase (tracked); // we don't need to track this packet anymore
#ifdef NS3_MTP
m_lock.store (false, std::memory_order_release);
#endif
2009-08-31 18:50:38 +01:00
}
void
FlowMonitor::ReportDrop (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize,
uint32_t reasonCode)
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this << probe << flowId << packetId << packetSize << reasonCode);
2009-08-31 18:50:38 +01:00
if (!m_enabled)
{
2019-01-29 10:27:12 -08:00
NS_LOG_DEBUG ("FlowMonitor not enabled; returning");
2009-08-31 18:50:38 +01:00
return;
}
#ifdef NS3_MTP
while (m_lock.exchange (true, std::memory_order_acquire))
;
#endif
2009-08-31 18:50:38 +01:00
probe->AddPacketDropStats (flowId, packetSize, reasonCode);
FlowStats &stats = GetStatsForFlow (flowId);
stats.lostPackets++;
if (stats.packetsDropped.size () < reasonCode + 1)
{
stats.packetsDropped.resize (reasonCode + 1, 0);
stats.bytesDropped.resize (reasonCode + 1, 0);
}
++stats.packetsDropped[reasonCode];
stats.bytesDropped[reasonCode] += packetSize;
NS_LOG_DEBUG ("++stats.packetsDropped[" << reasonCode<< "]; // becomes: " << stats.packetsDropped[reasonCode]);
TrackedPacketMap::iterator tracked = m_trackedPackets.find (std::make_pair (flowId, packetId));
if (tracked != m_trackedPackets.end ())
{
// we don't need to track this packet anymore
// FIXME: this will not necessarily be true with broadcast/multicast
NS_LOG_DEBUG ("ReportDrop: removing tracked packet (flowId="
<< flowId << ", packetId=" << packetId << ").");
m_trackedPackets.erase (tracked);
}
#ifdef NS3_MTP
m_lock.store (false, std::memory_order_release);
#endif
2009-08-31 18:50:38 +01:00
}
const FlowMonitor::FlowStatsContainer&
2009-08-31 18:50:38 +01:00
FlowMonitor::GetFlowStats () const
{
return m_flowStats;
}
void
FlowMonitor::CheckForLostPackets (Time maxDelay)
{
NS_LOG_FUNCTION (this << maxDelay.As (Time::S));
2009-08-31 18:50:38 +01:00
Time now = Simulator::Now ();
2011-05-13 14:54:37 -04:00
2009-08-31 18:50:38 +01:00
for (TrackedPacketMap::iterator iter = m_trackedPackets.begin ();
iter != m_trackedPackets.end (); )
{
if (now - iter->second.lastSeenTime >= maxDelay)
{
// packet is considered lost, add it to the loss statistics
FlowStatsContainerI flow = m_flowStats.find (iter->first.first);
2009-08-31 18:50:38 +01:00
NS_ASSERT (flow != m_flowStats.end ());
flow->second.lostPackets++;
// we won't track it anymore
m_trackedPackets.erase (iter++);
}
else
{
iter++;
}
}
}
void
FlowMonitor::CheckForLostPackets ()
{
CheckForLostPackets (m_maxPerHopDelay);
}
void
FlowMonitor::PeriodicCheckForLostPackets ()
{
CheckForLostPackets ();
Simulator::Schedule (PERIODIC_CHECK_INTERVAL, &FlowMonitor::PeriodicCheckForLostPackets, this);
}
void
FlowMonitor::NotifyConstructionCompleted ()
{
Object::NotifyConstructionCompleted ();
Simulator::Schedule (PERIODIC_CHECK_INTERVAL, &FlowMonitor::PeriodicCheckForLostPackets, this);
}
void
FlowMonitor::AddProbe (Ptr<FlowProbe> probe)
{
m_flowProbes.push_back (probe);
}
const FlowMonitor::FlowProbeContainer&
2009-08-31 18:50:38 +01:00
FlowMonitor::GetAllProbes () const
{
return m_flowProbes;
}
void
FlowMonitor::Start (const Time &time)
{
NS_LOG_FUNCTION (this << time.As (Time::S));
2009-08-31 18:50:38 +01:00
if (m_enabled)
{
2019-01-29 10:27:12 -08:00
NS_LOG_DEBUG ("FlowMonitor already enabled; returning");
2009-08-31 18:50:38 +01:00
return;
}
Simulator::Cancel (m_startEvent);
NS_LOG_DEBUG ("Scheduling start at " << time.As (Time::S));
m_startEvent = Simulator::Schedule (time, &FlowMonitor::StartRightNow, this);
2009-08-31 18:50:38 +01:00
}
void
FlowMonitor::Stop (const Time &time)
{
NS_LOG_FUNCTION (this << time.As (Time::S));
2009-08-31 18:50:38 +01:00
Simulator::Cancel (m_stopEvent);
NS_LOG_DEBUG ("Scheduling stop at " << time.As (Time::S));
m_stopEvent = Simulator::Schedule (time, &FlowMonitor::StopRightNow, this);
2009-08-31 18:50:38 +01:00
}
void
FlowMonitor::StartRightNow ()
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this);
2009-08-31 18:50:38 +01:00
if (m_enabled)
{
2019-01-29 10:27:12 -08:00
NS_LOG_DEBUG ("FlowMonitor already enabled; returning");
2009-08-31 18:50:38 +01:00
return;
}
m_enabled = true;
}
void
FlowMonitor::StopRightNow ()
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this);
2009-08-31 18:50:38 +01:00
if (!m_enabled)
{
2019-01-29 10:27:12 -08:00
NS_LOG_DEBUG ("FlowMonitor not enabled; returning");
2009-08-31 18:50:38 +01:00
return;
}
m_enabled = false;
CheckForLostPackets ();
}
void
FlowMonitor::AddFlowClassifier (Ptr<FlowClassifier> classifier)
2009-08-31 18:50:38 +01:00
{
m_classifiers.push_back (classifier);
2009-08-31 18:50:38 +01:00
}
void
FlowMonitor::SerializeToXmlStream (std::ostream &os, uint16_t indent, bool enableHistograms, bool enableProbes)
2009-08-31 18:50:38 +01:00
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this << indent << enableHistograms << enableProbes);
2009-08-31 18:50:38 +01:00
CheckForLostPackets ();
2011-05-13 14:54:37 -04:00
os << std::string ( indent, ' ' ) << "<FlowMonitor>\n";
2009-08-31 18:50:38 +01:00
indent += 2;
os << std::string ( indent, ' ' ) << "<FlowStats>\n";
2009-08-31 18:50:38 +01:00
indent += 2;
for (FlowStatsContainerCI flowI = m_flowStats.begin ();
2009-08-31 18:50:38 +01:00
flowI != m_flowStats.end (); flowI++)
{
os << std::string ( indent, ' ' );
2011-05-13 14:54:37 -04:00
#define ATTRIB(name) << " " # name "=\"" << flowI->second.name << "\""
#define ATTRIB_TIME(name) << " " #name "=\"" << flowI->second.name.As (Time::NS) << "\""
2009-08-31 18:50:38 +01:00
os << "<Flow flowId=\"" << flowI->first << "\""
ATTRIB_TIME (timeFirstTxPacket)
ATTRIB_TIME (timeFirstRxPacket)
ATTRIB_TIME (timeLastTxPacket)
ATTRIB_TIME (timeLastRxPacket)
ATTRIB_TIME (delaySum)
ATTRIB_TIME (jitterSum)
ATTRIB_TIME (lastDelay)
ATTRIB (txBytes)
ATTRIB (rxBytes)
ATTRIB (txPackets)
ATTRIB (rxPackets)
ATTRIB (lostPackets)
ATTRIB (timesForwarded)
<< ">\n";
#undef ATTRIB_TIME
2009-08-31 18:50:38 +01:00
#undef ATTRIB
indent += 2;
for (uint32_t reasonCode = 0; reasonCode < flowI->second.packetsDropped.size (); reasonCode++)
{
os << std::string ( indent, ' ' );
2009-08-31 18:50:38 +01:00
os << "<packetsDropped reasonCode=\"" << reasonCode << "\""
<< " number=\"" << flowI->second.packetsDropped[reasonCode]
<< "\" />\n";
2009-08-31 18:50:38 +01:00
}
for (uint32_t reasonCode = 0; reasonCode < flowI->second.bytesDropped.size (); reasonCode++)
{
os << std::string ( indent, ' ' );
2009-08-31 18:50:38 +01:00
os << "<bytesDropped reasonCode=\"" << reasonCode << "\""
<< " bytes=\"" << flowI->second.bytesDropped[reasonCode]
<< "\" />\n";
2009-08-31 18:50:38 +01:00
}
if (enableHistograms)
{
flowI->second.delayHistogram.SerializeToXmlStream (os, indent, "delayHistogram");
flowI->second.jitterHistogram.SerializeToXmlStream (os, indent, "jitterHistogram");
flowI->second.packetSizeHistogram.SerializeToXmlStream (os, indent, "packetSizeHistogram");
flowI->second.flowInterruptionsHistogram.SerializeToXmlStream (os, indent, "flowInterruptionsHistogram");
2009-08-31 18:50:38 +01:00
}
indent -= 2;
os << std::string ( indent, ' ' ) << "</Flow>\n";
2009-08-31 18:50:38 +01:00
}
indent -= 2;
os << std::string ( indent, ' ' ) << "</FlowStats>\n";
2009-08-31 18:50:38 +01:00
for (std::list<Ptr<FlowClassifier> >::iterator iter = m_classifiers.begin ();
iter != m_classifiers.end ();
iter ++)
{
(*iter)->SerializeToXmlStream (os, indent);
}
2009-08-31 18:50:38 +01:00
if (enableProbes)
{
os << std::string ( indent, ' ' ) << "<FlowProbes>\n";
2009-08-31 18:50:38 +01:00
indent += 2;
for (uint32_t i = 0; i < m_flowProbes.size (); i++)
{
m_flowProbes[i]->SerializeToXmlStream (os, indent, i);
}
indent -= 2;
os << std::string ( indent, ' ' ) << "</FlowProbes>\n";
2009-08-31 18:50:38 +01:00
}
indent -= 2;
os << std::string ( indent, ' ' ) << "</FlowMonitor>\n";
2009-08-31 18:50:38 +01:00
}
2011-05-13 14:54:37 -04:00
2009-08-31 18:50:38 +01:00
std::string
FlowMonitor::SerializeToXmlString (uint16_t indent, bool enableHistograms, bool enableProbes)
2009-08-31 18:50:38 +01:00
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this << indent << enableHistograms << enableProbes);
2009-08-31 18:50:38 +01:00
std::ostringstream os;
SerializeToXmlStream (os, indent, enableHistograms, enableProbes);
return os.str ();
}
void
FlowMonitor::SerializeToXmlFile (std::string fileName, bool enableHistograms, bool enableProbes)
{
2019-01-29 10:27:12 -08:00
NS_LOG_FUNCTION (this << fileName << enableHistograms << enableProbes);
2009-08-31 18:50:38 +01:00
std::ofstream os (fileName.c_str (), std::ios::out|std::ios::binary);
os << "<?xml version=\"1.0\" ?>\n";
SerializeToXmlStream (os, 0, enableHistograms, enableProbes);
os.close ();
}
} // namespace ns3