A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
rtt-estimator.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 //
3 // Copyright (c) 2006 Georgia Tech Research Corporation
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: Rajib Bhattacharjea<raj.b@gatech.edu>
19 //
20 
21 
22 // Ported from:
23 // Georgia Tech Network Simulator - Round Trip Time Estimation Class
24 // George F. Riley. Georgia Tech, Spring 2002
25 
26 // Implements several variations of round trip time estimators
27 
28 #include <iostream>
29 
30 #include "rtt-estimator.h"
31 #include "ns3/simulator.h"
32 #include "ns3/double.h"
33 #include "ns3/integer.h"
34 #include "ns3/uinteger.h"
35 #include "ns3/log.h"
36 
37 NS_LOG_COMPONENT_DEFINE ("RttEstimator");
38 
39 namespace ns3 {
40 
41 NS_OBJECT_ENSURE_REGISTERED (RttEstimator);
42 
43 TypeId
45 {
46  static TypeId tid = TypeId ("ns3::RttEstimator")
47  .SetParent<Object> ()
48  .AddAttribute ("MaxMultiplier",
49  "Maximum RTO Multiplier",
50  UintegerValue (64),
51  MakeUintegerAccessor (&RttEstimator::m_maxMultiplier),
52  MakeUintegerChecker<uint16_t> ())
53  .AddAttribute ("InitialEstimation",
54  "Initial RTT estimation",
55  TimeValue (Seconds (1.0)),
56  MakeTimeAccessor (&RttEstimator::m_initialEstimatedRtt),
57  MakeTimeChecker ())
58  .AddAttribute ("MinRTO",
59  "Minimum retransmit timeout value",
60  TimeValue (Seconds (0.2)), // RFC2988 says min RTO=1 sec, but Linux uses 200ms. See http://www.postel.org/pipermail/end2end-interest/2004-November/004402.html
61  MakeTimeAccessor (&RttEstimator::SetMinRto,
63  MakeTimeChecker ())
64  ;
65  return tid;
66 }
67 
68 void
70 {
71  NS_LOG_FUNCTION (this << minRto);
72  m_minRto = minRto;
73 }
74 Time
76 {
77  return m_minRto;
78 }
79 void
81 {
82  NS_LOG_FUNCTION (this << estimate);
83  m_currentEstimatedRtt = estimate;
84 }
85 Time
87 {
88  return m_currentEstimatedRtt;
89 }
90 
91 
92 //RttHistory methods
94  : seq (s), count (c), time (t), retx (false)
95 {
96  NS_LOG_FUNCTION (this);
97 }
98 
100  : seq (h.seq), count (h.count), time (h.time), retx (h.retx)
101 {
102  NS_LOG_FUNCTION (this);
103 }
104 
105 // Base class methods
106 
108  : m_next (1), m_history (),
109  m_nSamples (0),
110  m_multiplier (1)
111 {
112  NS_LOG_FUNCTION (this);
113  //note next=1 everywhere since first segment will have sequence 1
114 
115  // We need attributes initialized here, not later, so use the
116  // ConstructSelf() technique documented in the manual
119  NS_LOG_DEBUG ("Initialize m_currentEstimatedRtt to " << m_currentEstimatedRtt.GetSeconds () << " sec.");
120 }
121 
123  : Object (c), m_next (c.m_next), m_history (c.m_history),
124  m_maxMultiplier (c.m_maxMultiplier),
125  m_initialEstimatedRtt (c.m_initialEstimatedRtt),
126  m_currentEstimatedRtt (c.m_currentEstimatedRtt), m_minRto (c.m_minRto),
127  m_nSamples (c.m_nSamples), m_multiplier (c.m_multiplier)
128 {
129  NS_LOG_FUNCTION (this);
130 }
131 
133 {
134  NS_LOG_FUNCTION (this);
135 }
136 
137 void RttEstimator::SentSeq (SequenceNumber32 seq, uint32_t size)
138 {
139  NS_LOG_FUNCTION (this << seq << size);
140  // Note that a particular sequence has been sent
141  if (seq == m_next)
142  { // This is the next expected one, just log at end
143  m_history.push_back (RttHistory (seq, size, Simulator::Now () ));
144  m_next = seq + SequenceNumber32 (size); // Update next expected
145  }
146  else
147  { // This is a retransmit, find in list and mark as re-tx
148  for (RttHistory_t::iterator i = m_history.begin (); i != m_history.end (); ++i)
149  {
150  if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32 (i->count))))
151  { // Found it
152  i->retx = true;
153  // One final test..be sure this re-tx does not extend "next"
154  if ((seq + SequenceNumber32 (size)) > m_next)
155  {
156  m_next = seq + SequenceNumber32 (size);
157  i->count = ((seq + SequenceNumber32 (size)) - i->seq); // And update count in hist
158  }
159  break;
160  }
161  }
162  }
163 }
164 
166 {
167  NS_LOG_FUNCTION (this << ackSeq);
168  // An ack has been received, calculate rtt and log this measurement
169  // Note we use a linear search (O(n)) for this since for the common
170  // case the ack'ed packet will be at the head of the list
171  Time m = Seconds (0.0);
172  if (m_history.size () == 0) return (m); // No pending history, just exit
173  RttHistory& h = m_history.front ();
174  if (!h.retx && ackSeq >= (h.seq + SequenceNumber32 (h.count)))
175  { // Ok to use this sample
176  m = Simulator::Now () - h.time; // Elapsed time
177  Measurement (m); // Log the measurement
178  ResetMultiplier (); // Reset multiplier on valid measurement
179  }
180  // Now delete all ack history with seq <= ack
181  while(m_history.size () > 0)
182  {
183  RttHistory& h = m_history.front ();
184  if ((h.seq + SequenceNumber32 (h.count)) > ackSeq) break; // Done removing
185  m_history.pop_front (); // Remove
186  }
187  return m;
188 }
189 
191 {
192  NS_LOG_FUNCTION (this);
193  // Clear all history entries
194  m_next = 1;
195  m_history.clear ();
196 }
197 
199 {
200  NS_LOG_FUNCTION (this);
202  NS_LOG_DEBUG ("Multiplier increased to " << m_multiplier);
203 }
204 
206 {
207  NS_LOG_FUNCTION (this);
208  m_multiplier = 1;
209 }
210 
212 {
213  NS_LOG_FUNCTION (this);
214  // Reset to initial state
215  m_next = 1;
217  m_history.clear (); // Remove all info from the history
218  m_nSamples = 0;
219  ResetMultiplier ();
220 }
221 
222 
223 
224 //-----------------------------------------------------------------------------
225 //-----------------------------------------------------------------------------
226 // Mean-Deviation Estimator
227 
229 
230 TypeId
232 {
233  static TypeId tid = TypeId ("ns3::RttMeanDeviation")
235  .AddConstructor<RttMeanDeviation> ()
236  .AddAttribute ("Gain",
237  "Gain used in estimating the RTT, must be 0 < Gain < 1",
238  DoubleValue (0.1),
239  MakeDoubleAccessor (&RttMeanDeviation::m_gain),
240  MakeDoubleChecker<double> ())
241  ;
242  return tid;
243 }
244 
246  m_variance (0)
247 {
248  NS_LOG_FUNCTION (this);
249 }
250 
252  : RttEstimator (c), m_gain (c.m_gain), m_variance (c.m_variance)
253 {
254  NS_LOG_FUNCTION (this);
255 }
256 
258 {
259  NS_LOG_FUNCTION (this << m);
260  if (m_nSamples)
261  { // Not first
262  Time err (m - m_currentEstimatedRtt);
263  double gErr = err.ToDouble (Time::S) * m_gain;
265  Time difference = Abs (err) - m_variance;
266  NS_LOG_DEBUG ("m_variance += " << Time::FromDouble (difference.ToDouble (Time::S) * m_gain, Time::S));
268  }
269  else
270  { // First sample
271  m_currentEstimatedRtt = m; // Set estimate to current
272  //variance = sample / 2; // And variance to current / 2
273  m_variance = m; // try this
274  NS_LOG_DEBUG ("(first sample) m_variance += " << m);
275  }
276  m_nSamples++;
277 }
278 
280 {
281  NS_LOG_FUNCTION (this);
282  NS_LOG_DEBUG ("RetransmitTimeout: var " << m_variance.GetSeconds () << " est " << m_currentEstimatedRtt.GetSeconds () << " multiplier " << m_multiplier);
283  // RTO = srtt + 4* rttvar
285  if (temp < m_minRto.ToInteger (Time::MS))
286  {
287  temp = m_minRto.ToInteger (Time::MS);
288  }
289  temp = temp * m_multiplier; // Apply backoff
290  Time retval = Time::FromInteger (temp, Time::MS);
291  NS_LOG_DEBUG ("RetransmitTimeout: return " << retval.GetSeconds ());
292  return (retval);
293 }
294 
296 {
297  NS_LOG_FUNCTION (this);
298  return CopyObject<RttMeanDeviation> (this);
299 }
300 
302 {
303  NS_LOG_FUNCTION (this);
304  // Reset to initial state
305  m_variance = Seconds (0);
307 }
308 void RttMeanDeviation::Gain (double g)
309 {
310  NS_LOG_FUNCTION (this);
311  NS_ASSERT_MSG( (g > 0) && (g < 1), "RttMeanDeviation: Gain must be less than 1 and greater than 0" );
312  m_gain = g;
313 }
314 
315 } //namespace ns3