A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
flow-monitor.cc
Go to the documentation of this file.
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
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 
85  : m_enabled (false)
86 {
87  // m_histogramBinWidth=DEFAULT_BIN_WIDTH;
88 }
89 
90 
93 {
94  std::map<FlowId, FlowStats>::iterator iter;
95  iter = m_flowStats.find (flowId);
96  if (iter == m_flowStats.end ())
97  {
98  FlowMonitor::FlowStats &ref = m_flowStats[flowId];
99  ref.delaySum = Seconds (0);
100  ref.jitterSum = Seconds (0);
101  ref.lastDelay = Seconds (0);
102  ref.txBytes = 0;
103  ref.rxBytes = 0;
104  ref.txPackets = 0;
105  ref.rxPackets = 0;
106  ref.lostPackets = 0;
107  ref.timesForwarded = 0;
112  return ref;
113  }
114  else
115  {
116  return iter->second;
117  }
118 }
119 
120 
121 void
122 FlowMonitor::ReportFirstTx (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
123 {
124  if (!m_enabled)
125  {
126  return;
127  }
128  Time now = Simulator::Now ();
129  TrackedPacket &tracked = m_trackedPackets[std::make_pair (flowId, packetId)];
130  tracked.firstSeenTime = now;
131  tracked.lastSeenTime = tracked.firstSeenTime;
132  tracked.timesForwarded = 0;
133  NS_LOG_DEBUG ("ReportFirstTx: adding tracked packet (flowId=" << flowId << ", packetId=" << packetId
134  << ").");
135 
136  probe->AddPacketStats (flowId, packetSize, Seconds (0));
137 
138  FlowStats &stats = GetStatsForFlow (flowId);
139  stats.txBytes += packetSize;
140  stats.txPackets++;
141  if (stats.txPackets == 1)
142  {
143  stats.timeFirstTxPacket = now;
144  }
145  stats.timeLastTxPacket = now;
146 }
147 
148 
149 void
150 FlowMonitor::ReportForwarding (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
151 {
152  if (!m_enabled)
153  {
154  return;
155  }
156  std::pair<FlowId, FlowPacketId> key (flowId, packetId);
157  TrackedPacketMap::iterator tracked = m_trackedPackets.find (key);
158  if (tracked == m_trackedPackets.end ())
159  {
160  NS_LOG_WARN ("Received packet forward report (flowId=" << flowId << ", packetId=" << packetId
161  << ") but not known to be transmitted.");
162  return;
163  }
164 
165  tracked->second.timesForwarded++;
166  tracked->second.lastSeenTime = Simulator::Now ();
167 
168  Time delay = (Simulator::Now () - tracked->second.firstSeenTime);
169  probe->AddPacketStats (flowId, packetSize, delay);
170 }
171 
172 
173 void
174 FlowMonitor::ReportLastRx (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
175 {
176  if (!m_enabled)
177  {
178  return;
179  }
180  TrackedPacketMap::iterator tracked = m_trackedPackets.find (std::make_pair (flowId, packetId));
181  if (tracked == m_trackedPackets.end ())
182  {
183  NS_LOG_WARN ("Received packet last-tx report (flowId=" << flowId << ", packetId=" << packetId
184  << ") but not known to be transmitted.");
185  return;
186  }
187 
188  Time now = Simulator::Now ();
189  Time delay = (now - tracked->second.firstSeenTime);
190  probe->AddPacketStats (flowId, packetSize, delay);
191 
192  FlowStats &stats = GetStatsForFlow (flowId);
193  stats.delaySum += delay;
194  stats.delayHistogram.AddValue (delay.GetSeconds ());
195  if (stats.rxPackets > 0 )
196  {
197  Time jitter = stats.lastDelay - delay;
198  if (jitter > Seconds (0))
199  {
200  stats.jitterSum += jitter;
201  stats.jitterHistogram.AddValue (jitter.GetSeconds ());
202  }
203  else
204  {
205  stats.jitterSum -= jitter;
206  stats.jitterHistogram.AddValue (-jitter.GetSeconds ());
207  }
208  }
209  stats.lastDelay = delay;
210 
211  stats.rxBytes += packetSize;
212  stats.packetSizeHistogram.AddValue ((double) packetSize);
213  stats.rxPackets++;
214  if (stats.rxPackets == 1)
215  {
216  stats.timeFirstRxPacket = now;
217  }
218  else
219  {
220  // measure possible flow interruptions
221  Time interArrivalTime = now - stats.timeLastRxPacket;
222  if (interArrivalTime > m_flowInterruptionsMinTime)
223  {
224  stats.flowInterruptionsHistogram.AddValue (interArrivalTime.GetSeconds ());
225  }
226  }
227  stats.timeLastRxPacket = now;
228  stats.timesForwarded += tracked->second.timesForwarded;
229 
230  NS_LOG_DEBUG ("ReportLastTx: removing tracked packet (flowId="
231  << flowId << ", packetId=" << packetId << ").");
232 
233  m_trackedPackets.erase (tracked); // we don't need to track this packet anymore
234 }
235 
236 void
237 FlowMonitor::ReportDrop (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize,
238  uint32_t reasonCode)
239 {
240  if (!m_enabled)
241  {
242  return;
243  }
244 
245  probe->AddPacketDropStats (flowId, packetSize, reasonCode);
246 
247  FlowStats &stats = GetStatsForFlow (flowId);
248  stats.lostPackets++;
249  if (stats.packetsDropped.size () < reasonCode + 1)
250  {
251  stats.packetsDropped.resize (reasonCode + 1, 0);
252  stats.bytesDropped.resize (reasonCode + 1, 0);
253  }
254  ++stats.packetsDropped[reasonCode];
255  stats.bytesDropped[reasonCode] += packetSize;
256  NS_LOG_DEBUG ("++stats.packetsDropped[" << reasonCode<< "]; // becomes: " << stats.packetsDropped[reasonCode]);
257 
258  TrackedPacketMap::iterator tracked = m_trackedPackets.find (std::make_pair (flowId, packetId));
259  if (tracked != m_trackedPackets.end ())
260  {
261  // we don't need to track this packet anymore
262  // FIXME: this will not necessarily be true with broadcast/multicast
263  NS_LOG_DEBUG ("ReportDrop: removing tracked packet (flowId="
264  << flowId << ", packetId=" << packetId << ").");
265  m_trackedPackets.erase (tracked);
266  }
267 }
268 
269 std::map<FlowId, FlowMonitor::FlowStats>
271 {
272  return m_flowStats;
273 }
274 
275 
276 void
278 {
279  Time now = Simulator::Now ();
280 
281  for (TrackedPacketMap::iterator iter = m_trackedPackets.begin ();
282  iter != m_trackedPackets.end (); )
283  {
284  if (now - iter->second.lastSeenTime >= maxDelay)
285  {
286  // packet is considered lost, add it to the loss statistics
287  std::map<FlowId, FlowStats>::iterator
288  flow = m_flowStats.find (iter->first.first);
289  NS_ASSERT (flow != m_flowStats.end ());
290  flow->second.lostPackets++;
291 
292  // we won't track it anymore
293  m_trackedPackets.erase (iter++);
294  }
295  else
296  {
297  iter++;
298  }
299  }
300 }
301 
302 void
304 {
306 }
307 
308 void
310 {
313 }
314 
315 void
317 {
320 }
321 
322 void
324 {
325  m_flowProbes.push_back (probe);
326 }
327 
328 std::vector< Ptr<FlowProbe> >
330 {
331  return m_flowProbes;
332 }
333 
334 
335 void
337 {
338  if (m_enabled)
339  {
340  return;
341  }
344 }
345 
346 void
347 FlowMonitor::Stop (const Time &time)
348 {
349  if (!m_enabled)
350  {
351  return;
352  }
355 }
356 
357 
358 void
360 {
361  if (m_enabled)
362  {
363  return;
364  }
365  m_enabled = true;
366 }
367 
368 
369 void
371 {
372  if (!m_enabled)
373  {
374  return;
375  }
376  m_enabled = false;
378 }
379 
380 void
382 {
383  m_classifier = classifier;
384 }
385 
386 void
387 FlowMonitor::SerializeToXmlStream (std::ostream &os, int indent, bool enableHistograms, bool enableProbes)
388 {
390 
391  INDENT (indent); os << "<FlowMonitor>\n";
392  indent += 2;
393  INDENT (indent); os << "<FlowStats>\n";
394  indent += 2;
395  for (std::map<FlowId, FlowStats>::const_iterator flowI = m_flowStats.begin ();
396  flowI != m_flowStats.end (); flowI++)
397  {
398 
399  INDENT (indent);
400 #define ATTRIB(name) << " " # name "=\"" << flowI->second.name << "\""
401  os << "<Flow flowId=\"" << flowI->first << "\""
402  ATTRIB (timeFirstTxPacket)
403  ATTRIB (timeFirstRxPacket)
404  ATTRIB (timeLastTxPacket)
405  ATTRIB (timeLastRxPacket)
406  ATTRIB (delaySum)
407  ATTRIB (jitterSum)
408  ATTRIB (lastDelay)
409  ATTRIB (txBytes)
410  ATTRIB (rxBytes)
411  ATTRIB (txPackets)
412  ATTRIB (rxPackets)
413  ATTRIB (lostPackets)
414  ATTRIB (timesForwarded)
415  << ">\n";
416 #undef ATTRIB
417 
418 
419  indent += 2;
420  for (uint32_t reasonCode = 0; reasonCode < flowI->second.packetsDropped.size (); reasonCode++)
421  {
422  INDENT (indent);
423  os << "<packetsDropped reasonCode=\"" << reasonCode << "\""
424  << " number=\"" << flowI->second.packetsDropped[reasonCode]
425  << "\" />\n";
426  }
427  for (uint32_t reasonCode = 0; reasonCode < flowI->second.bytesDropped.size (); reasonCode++)
428  {
429  INDENT (indent);
430  os << "<bytesDropped reasonCode=\"" << reasonCode << "\""
431  << " bytes=\"" << flowI->second.bytesDropped[reasonCode]
432  << "\" />\n";
433  }
434  if (enableHistograms)
435  {
436  flowI->second.delayHistogram.SerializeToXmlStream (os, indent, "delayHistogram");
437  flowI->second.jitterHistogram.SerializeToXmlStream (os, indent, "jitterHistogram");
438  flowI->second.packetSizeHistogram.SerializeToXmlStream (os, indent, "packetSizeHistogram");
439  flowI->second.flowInterruptionsHistogram.SerializeToXmlStream (os, indent, "flowInterruptionsHistogram");
440  }
441  indent -= 2;
442 
443  INDENT (indent); os << "</Flow>\n";
444  }
445  indent -= 2;
446  INDENT (indent); os << "</FlowStats>\n";
447 
448  m_classifier->SerializeToXmlStream (os, indent);
449 
450  if (enableProbes)
451  {
452  INDENT (indent); os << "<FlowProbes>\n";
453  indent += 2;
454  for (uint32_t i = 0; i < m_flowProbes.size (); i++)
455  {
456  m_flowProbes[i]->SerializeToXmlStream (os, indent, i);
457  }
458  indent -= 2;
459  INDENT (indent); os << "</FlowProbes>\n";
460  }
461 
462  indent -= 2;
463  INDENT (indent); os << "</FlowMonitor>\n";
464 }
465 
466 
467 std::string
468 FlowMonitor::SerializeToXmlString (int indent, bool enableHistograms, bool enableProbes)
469 {
470  std::ostringstream os;
471  SerializeToXmlStream (os, indent, enableHistograms, enableProbes);
472  return os.str ();
473 }
474 
475 
476 void
477 FlowMonitor::SerializeToXmlFile (std::string fileName, bool enableHistograms, bool enableProbes)
478 {
479  std::ofstream os (fileName.c_str (), std::ios::out|std::ios::binary);
480  os << "<?xml version=\"1.0\" ?>\n";
481  SerializeToXmlStream (os, 0, enableHistograms, enableProbes);
482  os.close ();
483 }
484 
485 
486 } // namespace ns3
487