A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
flow-monitor.cc
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 //
3 // Copyright (c) 2009 INESC Porto
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License version 2 as
7 // published by the Free Software Foundation;
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 //
18 // Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt> <gjcarneiro@gmail.com>
19 //
20 
21 #include "flow-monitor.h"
22 #include "ns3/simulator.h"
23 #include "ns3/log.h"
24 #include "ns3/double.h"
25 #include <fstream>
26 #include <sstream>
27 
28 #define INDENT(level) for (int __xpto = 0; __xpto < level; __xpto++) os << ' ';
29 
30 #define PERIODIC_CHECK_INTERVAL (Seconds (1))
31 
32 namespace ns3 {
33 
34 NS_LOG_COMPONENT_DEFINE ("FlowMonitor");
35 
36 NS_OBJECT_ENSURE_REGISTERED (FlowMonitor);
37 
38 
39 TypeId
40 FlowMonitor::GetTypeId (void)
41 {
42  static TypeId tid = TypeId ("ns3::FlowMonitor")
43  .SetParent<Object> ()
44  .AddConstructor<FlowMonitor> ()
45  .AddAttribute ("MaxPerHopDelay", ("The maximum per-hop delay that should be considered. "
46  "Packets still not received after this delay are to be considered lost."),
47  TimeValue (Seconds (10.0)),
48  MakeTimeAccessor (&FlowMonitor::m_maxPerHopDelay),
49  MakeTimeChecker ())
50  .AddAttribute ("StartTime", ("The time when the monitoring starts."),
51  TimeValue (Seconds (0.0)),
52  MakeTimeAccessor (&FlowMonitor::Start),
53  MakeTimeChecker ())
54  .AddAttribute ("DelayBinWidth", ("The width used in the delay histogram."),
55  DoubleValue (0.001),
56  MakeDoubleAccessor (&FlowMonitor::m_delayBinWidth),
57  MakeDoubleChecker <double> ())
58  .AddAttribute ("JitterBinWidth", ("The width used in the jitter histogram."),
59  DoubleValue (0.001),
60  MakeDoubleAccessor (&FlowMonitor::m_jitterBinWidth),
61  MakeDoubleChecker <double> ())
62  .AddAttribute ("PacketSizeBinWidth", ("The width used in the packetSize histogram."),
63  DoubleValue (20),
64  MakeDoubleAccessor (&FlowMonitor::m_packetSizeBinWidth),
65  MakeDoubleChecker <double> ())
66  .AddAttribute ("FlowInterruptionsBinWidth", ("The width used in the flowInterruptions histogram."),
67  DoubleValue (0.250),
68  MakeDoubleAccessor (&FlowMonitor::m_flowInterruptionsBinWidth),
69  MakeDoubleChecker <double> ())
70  .AddAttribute ("FlowInterruptionsMinTime", ("The minimum inter-arrival time that is considered a flow interruption."),
71  TimeValue (Seconds (0.5)),
72  MakeTimeAccessor (&FlowMonitor::m_flowInterruptionsMinTime),
73  MakeTimeChecker ())
74  ;
75  return tid;
76 }
77 
78 TypeId
80 {
81  return GetTypeId ();
82 }
83 
84 FlowMonitor::FlowMonitor ()
85  : m_enabled (false)
86 {
87  // m_histogramBinWidth=DEFAULT_BIN_WIDTH;
88 }
89 
90 void
92 {
93  m_classifier = 0;
94  for (uint32_t i = 0; i < m_flowProbes.size (); i++)
95  {
96  m_flowProbes[i]->Dispose ();
97  m_flowProbes[i] = 0;
98  }
100 }
101 
103 FlowMonitor::GetStatsForFlow (FlowId flowId)
104 {
105  std::map<FlowId, FlowStats>::iterator iter;
106  iter = m_flowStats.find (flowId);
107  if (iter == m_flowStats.end ())
108  {
109  FlowMonitor::FlowStats &ref = m_flowStats[flowId];
110  ref.delaySum = Seconds (0);
111  ref.jitterSum = Seconds (0);
112  ref.lastDelay = Seconds (0);
113  ref.txBytes = 0;
114  ref.rxBytes = 0;
115  ref.txPackets = 0;
116  ref.rxPackets = 0;
117  ref.lostPackets = 0;
118  ref.timesForwarded = 0;
119  ref.delayHistogram.SetDefaultBinWidth (m_delayBinWidth);
120  ref.jitterHistogram.SetDefaultBinWidth (m_jitterBinWidth);
121  ref.packetSizeHistogram.SetDefaultBinWidth (m_packetSizeBinWidth);
122  ref.flowInterruptionsHistogram.SetDefaultBinWidth (m_flowInterruptionsBinWidth);
123  return ref;
124  }
125  else
126  {
127  return iter->second;
128  }
129 }
130 
131 
132 void
133 FlowMonitor::ReportFirstTx (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
134 {
135  if (!m_enabled)
136  {
137  return;
138  }
139  Time now = Simulator::Now ();
140  TrackedPacket &tracked = m_trackedPackets[std::make_pair (flowId, packetId)];
141  tracked.firstSeenTime = now;
142  tracked.lastSeenTime = tracked.firstSeenTime;
143  tracked.timesForwarded = 0;
144  NS_LOG_DEBUG ("ReportFirstTx: adding tracked packet (flowId=" << flowId << ", packetId=" << packetId
145  << ").");
146 
147  probe->AddPacketStats (flowId, packetSize, Seconds (0));
148 
149  FlowStats &stats = GetStatsForFlow (flowId);
150  stats.txBytes += packetSize;
151  stats.txPackets++;
152  if (stats.txPackets == 1)
153  {
154  stats.timeFirstTxPacket = now;
155  }
156  stats.timeLastTxPacket = now;
157 }
158 
159 
160 void
161 FlowMonitor::ReportForwarding (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
162 {
163  if (!m_enabled)
164  {
165  return;
166  }
167  std::pair<FlowId, FlowPacketId> key (flowId, packetId);
168  TrackedPacketMap::iterator tracked = m_trackedPackets.find (key);
169  if (tracked == m_trackedPackets.end ())
170  {
171  NS_LOG_WARN ("Received packet forward report (flowId=" << flowId << ", packetId=" << packetId
172  << ") but not known to be transmitted.");
173  return;
174  }
175 
176  tracked->second.timesForwarded++;
177  tracked->second.lastSeenTime = Simulator::Now ();
178 
179  Time delay = (Simulator::Now () - tracked->second.firstSeenTime);
180  probe->AddPacketStats (flowId, packetSize, delay);
181 }
182 
183 
184 void
185 FlowMonitor::ReportLastRx (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
186 {
187  if (!m_enabled)
188  {
189  return;
190  }
191  TrackedPacketMap::iterator tracked = m_trackedPackets.find (std::make_pair (flowId, packetId));
192  if (tracked == m_trackedPackets.end ())
193  {
194  NS_LOG_WARN ("Received packet last-tx report (flowId=" << flowId << ", packetId=" << packetId
195  << ") but not known to be transmitted.");
196  return;
197  }
198 
199  Time now = Simulator::Now ();
200  Time delay = (now - tracked->second.firstSeenTime);
201  probe->AddPacketStats (flowId, packetSize, delay);
202 
203  FlowStats &stats = GetStatsForFlow (flowId);
204  stats.delaySum += delay;
205  stats.delayHistogram.AddValue (delay.GetSeconds ());
206  if (stats.rxPackets > 0 )
207  {
208  Time jitter = stats.lastDelay - delay;
209  if (jitter > Seconds (0))
210  {
211  stats.jitterSum += jitter;
212  stats.jitterHistogram.AddValue (jitter.GetSeconds ());
213  }
214  else
215  {
216  stats.jitterSum -= jitter;
217  stats.jitterHistogram.AddValue (-jitter.GetSeconds ());
218  }
219  }
220  stats.lastDelay = delay;
221 
222  stats.rxBytes += packetSize;
223  stats.packetSizeHistogram.AddValue ((double) packetSize);
224  stats.rxPackets++;
225  if (stats.rxPackets == 1)
226  {
227  stats.timeFirstRxPacket = now;
228  }
229  else
230  {
231  // measure possible flow interruptions
232  Time interArrivalTime = now - stats.timeLastRxPacket;
233  if (interArrivalTime > m_flowInterruptionsMinTime)
234  {
235  stats.flowInterruptionsHistogram.AddValue (interArrivalTime.GetSeconds ());
236  }
237  }
238  stats.timeLastRxPacket = now;
239  stats.timesForwarded += tracked->second.timesForwarded;
240 
241  NS_LOG_DEBUG ("ReportLastTx: removing tracked packet (flowId="
242  << flowId << ", packetId=" << packetId << ").");
243 
244  m_trackedPackets.erase (tracked); // we don't need to track this packet anymore
245 }
246 
247 void
248 FlowMonitor::ReportDrop (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize,
249  uint32_t reasonCode)
250 {
251  if (!m_enabled)
252  {
253  return;
254  }
255 
256  probe->AddPacketDropStats (flowId, packetSize, reasonCode);
257 
258  FlowStats &stats = GetStatsForFlow (flowId);
259  stats.lostPackets++;
260  if (stats.packetsDropped.size () < reasonCode + 1)
261  {
262  stats.packetsDropped.resize (reasonCode + 1, 0);
263  stats.bytesDropped.resize (reasonCode + 1, 0);
264  }
265  ++stats.packetsDropped[reasonCode];
266  stats.bytesDropped[reasonCode] += packetSize;
267  NS_LOG_DEBUG ("++stats.packetsDropped[" << reasonCode<< "]; // becomes: " << stats.packetsDropped[reasonCode]);
268 
269  TrackedPacketMap::iterator tracked = m_trackedPackets.find (std::make_pair (flowId, packetId));
270  if (tracked != m_trackedPackets.end ())
271  {
272  // we don't need to track this packet anymore
273  // FIXME: this will not necessarily be true with broadcast/multicast
274  NS_LOG_DEBUG ("ReportDrop: removing tracked packet (flowId="
275  << flowId << ", packetId=" << packetId << ").");
276  m_trackedPackets.erase (tracked);
277  }
278 }
279 
280 std::map<FlowId, FlowMonitor::FlowStats>
282 {
283  return m_flowStats;
284 }
285 
286 
287 void
289 {
290  Time now = Simulator::Now ();
291 
292  for (TrackedPacketMap::iterator iter = m_trackedPackets.begin ();
293  iter != m_trackedPackets.end (); )
294  {
295  if (now - iter->second.lastSeenTime >= maxDelay)
296  {
297  // packet is considered lost, add it to the loss statistics
298  std::map<FlowId, FlowStats>::iterator
299  flow = m_flowStats.find (iter->first.first);
300  NS_ASSERT (flow != m_flowStats.end ());
301  flow->second.lostPackets++;
302 
303  // we won't track it anymore
304  m_trackedPackets.erase (iter++);
305  }
306  else
307  {
308  iter++;
309  }
310  }
311 }
312 
313 void
315 {
316  CheckForLostPackets (m_maxPerHopDelay);
317 }
318 
319 void
320 FlowMonitor::PeriodicCheckForLostPackets ()
321 {
323  Simulator::Schedule (PERIODIC_CHECK_INTERVAL, &FlowMonitor::PeriodicCheckForLostPackets, this);
324 }
325 
326 void
328 {
330  Simulator::Schedule (PERIODIC_CHECK_INTERVAL, &FlowMonitor::PeriodicCheckForLostPackets, this);
331 }
332 
333 void
335 {
336  m_flowProbes.push_back (probe);
337 }
338 
339 std::vector< Ptr<FlowProbe> >
341 {
342  return m_flowProbes;
343 }
344 
345 
346 void
348 {
349  if (m_enabled)
350  {
351  return;
352  }
353  Simulator::Cancel (m_startEvent);
354  m_startEvent = Simulator::Schedule (time, &FlowMonitor::StartRightNow, this);
355 }
356 
357 void
358 FlowMonitor::Stop (const Time &time)
359 {
360  if (!m_enabled)
361  {
362  return;
363  }
364  Simulator::Cancel (m_stopEvent);
365  m_stopEvent = Simulator::Schedule (time, &FlowMonitor::StopRightNow, this);
366 }
367 
368 
369 void
371 {
372  if (m_enabled)
373  {
374  return;
375  }
376  m_enabled = true;
377 }
378 
379 
380 void
382 {
383  if (!m_enabled)
384  {
385  return;
386  }
387  m_enabled = false;
389 }
390 
391 void
393 {
394  m_classifier = classifier;
395 }
396 
397 void
398 FlowMonitor::SerializeToXmlStream (std::ostream &os, int indent, bool enableHistograms, bool enableProbes)
399 {
401 
402  INDENT (indent); os << "<FlowMonitor>\n";
403  indent += 2;
404  INDENT (indent); os << "<FlowStats>\n";
405  indent += 2;
406  for (std::map<FlowId, FlowStats>::const_iterator flowI = m_flowStats.begin ();
407  flowI != m_flowStats.end (); flowI++)
408  {
409 
410  INDENT (indent);
411 #define ATTRIB(name) << " " # name "=\"" << flowI->second.name << "\""
412  os << "<Flow flowId=\"" << flowI->first << "\""
413  ATTRIB (timeFirstTxPacket)
414  ATTRIB (timeFirstRxPacket)
415  ATTRIB (timeLastTxPacket)
416  ATTRIB (timeLastRxPacket)
417  ATTRIB (delaySum)
418  ATTRIB (jitterSum)
419  ATTRIB (lastDelay)
420  ATTRIB (txBytes)
421  ATTRIB (rxBytes)
422  ATTRIB (txPackets)
423  ATTRIB (rxPackets)
424  ATTRIB (lostPackets)
425  ATTRIB (timesForwarded)
426  << ">\n";
427 #undef ATTRIB
428 
429 
430  indent += 2;
431  for (uint32_t reasonCode = 0; reasonCode < flowI->second.packetsDropped.size (); reasonCode++)
432  {
433  INDENT (indent);
434  os << "<packetsDropped reasonCode=\"" << reasonCode << "\""
435  << " number=\"" << flowI->second.packetsDropped[reasonCode]
436  << "\" />\n";
437  }
438  for (uint32_t reasonCode = 0; reasonCode < flowI->second.bytesDropped.size (); reasonCode++)
439  {
440  INDENT (indent);
441  os << "<bytesDropped reasonCode=\"" << reasonCode << "\""
442  << " bytes=\"" << flowI->second.bytesDropped[reasonCode]
443  << "\" />\n";
444  }
445  if (enableHistograms)
446  {
447  flowI->second.delayHistogram.SerializeToXmlStream (os, indent, "delayHistogram");
448  flowI->second.jitterHistogram.SerializeToXmlStream (os, indent, "jitterHistogram");
449  flowI->second.packetSizeHistogram.SerializeToXmlStream (os, indent, "packetSizeHistogram");
450  flowI->second.flowInterruptionsHistogram.SerializeToXmlStream (os, indent, "flowInterruptionsHistogram");
451  }
452  indent -= 2;
453 
454  INDENT (indent); os << "</Flow>\n";
455  }
456  indent -= 2;
457  INDENT (indent); os << "</FlowStats>\n";
458 
459  m_classifier->SerializeToXmlStream (os, indent);
460 
461  if (enableProbes)
462  {
463  INDENT (indent); os << "<FlowProbes>\n";
464  indent += 2;
465  for (uint32_t i = 0; i < m_flowProbes.size (); i++)
466  {
467  m_flowProbes[i]->SerializeToXmlStream (os, indent, i);
468  }
469  indent -= 2;
470  INDENT (indent); os << "</FlowProbes>\n";
471  }
472 
473  indent -= 2;
474  INDENT (indent); os << "</FlowMonitor>\n";
475 }
476 
477 
478 std::string
479 FlowMonitor::SerializeToXmlString (int indent, bool enableHistograms, bool enableProbes)
480 {
481  std::ostringstream os;
482  SerializeToXmlStream (os, indent, enableHistograms, enableProbes);
483  return os.str ();
484 }
485 
486 
487 void
488 FlowMonitor::SerializeToXmlFile (std::string fileName, bool enableHistograms, bool enableProbes)
489 {
490  std::ofstream os (fileName.c_str (), std::ios::out|std::ios::binary);
491  os << "<?xml version=\"1.0\" ?>\n";
492  SerializeToXmlStream (os, 0, enableHistograms, enableProbes);
493  os.close ();
494 }
495 
496 
497 } // namespace ns3
498 
keep track of time unit.
Definition: nstime.h:149
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:59
void CheckForLostPackets()
Check right now for packets that appear to be lost.
void StartRightNow()
Begin monitoring flows right now
uint32_t rxPackets
Total number of received packets for the flow.
Definition: flow-monitor.h:89
uint32_t txPackets
Total number of transmitted packets for the flow.
Definition: flow-monitor.h:87
#define NS_ASSERT(condition)
Definition: assert.h:64
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
void ReportDrop(Ptr< FlowProbe > probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize, uint32_t reasonCode)
virtual void DoDispose(void)
Definition: object.cc:335
static void Cancel(const EventId &id)
Definition: simulator.cc:267
static EventId Schedule(Time const &time, MEM mem_ptr, OBJ obj)
Definition: simulator.h:820
std::vector< uint64_t > bytesDropped
Definition: flow-monitor.h:125
void ReportFirstTx(Ptr< FlowProbe > probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize)
void SetFlowClassifier(Ptr< FlowClassifier > classifier)
Set the FlowClassifier to be used by the flow monitor.
std::map< FlowId, FlowStats > GetFlowStats() const
void SerializeToXmlStream(std::ostream &os, int indent, bool enableHistograms, bool enableProbes)
double GetSeconds(void) const
Definition: nstime.h:262
std::string SerializeToXmlString(int indent, bool enableHistograms, bool enableProbes)
virtual void NotifyConstructionCompleted(void)
Definition: object-base.cc:59
virtual void NotifyConstructionCompleted()
void Stop(const Time &time)
Set the time, counting from the current time, from which to stop monitoring flows.
static Time Now(void)
Definition: simulator.cc:179
void StopRightNow()
End monitoring flows right now
Time Seconds(double seconds)
create ns3::Time instances in units of seconds.
Definition: nstime.h:586
#define NS_LOG_WARN(msg)
Definition: log.h:246
Histogram delayHistogram
Histogram of the packet delays.
Definition: flow-monitor.h:103
void SerializeToXmlFile(std::string fileName, bool enableHistograms, bool enableProbes)
std::vector< Ptr< FlowProbe > > GetAllProbes() const
Get a list of all FlowProbe's associated with this FlowMonitor.
#define NS_LOG_DEBUG(msg)
Definition: log.h:255
virtual void DoDispose(void)
Definition: flow-monitor.cc:91
uint64_t txBytes
Total number of transmitted bytes for the flow.
Definition: flow-monitor.h:83
Structure that represents the measured metrics of an individual packet flow.
Definition: flow-monitor.h:46
Histogram jitterHistogram
Histogram of the packet jitters.
Definition: flow-monitor.h:105
void Start(const Time &time)
Set the time, counting from the current time, from which to start monitoring flows.
void ReportForwarding(Ptr< FlowProbe > probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize)
uint64_t rxBytes
Total number of received bytes for the flow.
Definition: flow-monitor.h:85
void AddProbe(Ptr< FlowProbe > probe)
void ReportLastRx(Ptr< FlowProbe > probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize)
Histogram packetSizeHistogram
Histogram of the packet sizes.
Definition: flow-monitor.h:107
TypeId GetInstanceTypeId() const
Definition: flow-monitor.cc:79
std::vector< uint32_t > packetsDropped
Definition: flow-monitor.h:121