A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
rtt-estimator.cc
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
44 RttEstimator::GetTypeId (void)
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
93 RttHistory::RttHistory (SequenceNumber32 s, uint32_t c, Time t)
94  : seq (s), count (c), time (t), retx (false)
95 {
96  NS_LOG_FUNCTION (this);
97 }
98 
99 RttHistory::RttHistory (const RttHistory& h)
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 
107 RttEstimator::RttEstimator ()
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
117  ObjectBase::ConstructSelf (AttributeConstructionList ());
118  m_currentEstimatedRtt = m_initialEstimatedRtt;
119  NS_LOG_DEBUG ("Initialize m_currentEstimatedRtt to " << m_currentEstimatedRtt.GetSeconds () << " sec.");
120 }
121 
122 RttEstimator::RttEstimator (const RttEstimator& c)
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 
132 RttEstimator::~RttEstimator ()
133 {
134  NS_LOG_FUNCTION (this);
135 }
136 
137 TypeId
139 {
140  return GetTypeId ();
141 }
142 
143 void RttEstimator::SentSeq (SequenceNumber32 seq, uint32_t size)
144 {
145  NS_LOG_FUNCTION (this << seq << size);
146  // Note that a particular sequence has been sent
147  if (seq == m_next)
148  { // This is the next expected one, just log at end
149  m_history.push_back (RttHistory (seq, size, Simulator::Now () ));
150  m_next = seq + SequenceNumber32 (size); // Update next expected
151  }
152  else
153  { // This is a retransmit, find in list and mark as re-tx
154  for (RttHistory_t::iterator i = m_history.begin (); i != m_history.end (); ++i)
155  {
156  if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32 (i->count))))
157  { // Found it
158  i->retx = true;
159  // One final test..be sure this re-tx does not extend "next"
160  if ((seq + SequenceNumber32 (size)) > m_next)
161  {
162  m_next = seq + SequenceNumber32 (size);
163  i->count = ((seq + SequenceNumber32 (size)) - i->seq); // And update count in hist
164  }
165  break;
166  }
167  }
168  }
169 }
170 
172 {
173  NS_LOG_FUNCTION (this << ackSeq);
174  // An ack has been received, calculate rtt and log this measurement
175  // Note we use a linear search (O(n)) for this since for the common
176  // case the ack'ed packet will be at the head of the list
177  Time m = Seconds (0.0);
178  if (m_history.size () == 0) return (m); // No pending history, just exit
179  RttHistory& h = m_history.front ();
180  if (!h.retx && ackSeq >= (h.seq + SequenceNumber32 (h.count)))
181  { // Ok to use this sample
182  m = Simulator::Now () - h.time; // Elapsed time
183  Measurement (m); // Log the measurement
184  ResetMultiplier (); // Reset multiplier on valid measurement
185  }
186  // Now delete all ack history with seq <= ack
187  while(m_history.size () > 0)
188  {
189  RttHistory& h = m_history.front ();
190  if ((h.seq + SequenceNumber32 (h.count)) > ackSeq) break; // Done removing
191  m_history.pop_front (); // Remove
192  }
193  return m;
194 }
195 
197 {
198  NS_LOG_FUNCTION (this);
199  // Clear all history entries
200  m_next = 1;
201  m_history.clear ();
202 }
203 
205 {
206  NS_LOG_FUNCTION (this);
207  m_multiplier = (m_multiplier*2 < m_maxMultiplier) ? m_multiplier*2 : m_maxMultiplier;
208  NS_LOG_DEBUG ("Multiplier increased to " << m_multiplier);
209 }
210 
212 {
213  NS_LOG_FUNCTION (this);
214  m_multiplier = 1;
215 }
216 
218 {
219  NS_LOG_FUNCTION (this);
220  // Reset to initial state
221  m_next = 1;
222  m_currentEstimatedRtt = m_initialEstimatedRtt;
223  m_history.clear (); // Remove all info from the history
224  m_nSamples = 0;
225  ResetMultiplier ();
226 }
227 
228 
229 
230 //-----------------------------------------------------------------------------
231 //-----------------------------------------------------------------------------
232 // Mean-Deviation Estimator
233 
234 NS_OBJECT_ENSURE_REGISTERED (RttMeanDeviation);
235 
236 TypeId
237 RttMeanDeviation::GetTypeId (void)
238 {
239  static TypeId tid = TypeId ("ns3::RttMeanDeviation")
241  .AddConstructor<RttMeanDeviation> ()
242  .AddAttribute ("Gain",
243  "Gain used in estimating the RTT, must be 0 < Gain < 1",
244  DoubleValue (0.1),
245  MakeDoubleAccessor (&RttMeanDeviation::m_gain),
246  MakeDoubleChecker<double> ())
247  ;
248  return tid;
249 }
250 
251 RttMeanDeviation::RttMeanDeviation() :
252  m_variance (0)
253 {
254  NS_LOG_FUNCTION (this);
255 }
256 
257 RttMeanDeviation::RttMeanDeviation (const RttMeanDeviation& c)
258  : RttEstimator (c), m_gain (c.m_gain), m_variance (c.m_variance)
259 {
260  NS_LOG_FUNCTION (this);
261 }
262 
263 TypeId
265 {
266  return GetTypeId ();
267 }
268 
270 {
271  NS_LOG_FUNCTION (this << m);
272  if (m_nSamples)
273  { // Not first
274  Time err (m - m_currentEstimatedRtt);
275  double gErr = err.ToDouble (Time::S) * m_gain;
276  m_currentEstimatedRtt += Time::FromDouble (gErr, Time::S);
277  Time difference = Abs (err) - m_variance;
278  NS_LOG_DEBUG ("m_variance += " << Time::FromDouble (difference.ToDouble (Time::S) * m_gain, Time::S));
279  m_variance += Time::FromDouble (difference.ToDouble (Time::S) * m_gain, Time::S);
280  }
281  else
282  { // First sample
283  m_currentEstimatedRtt = m; // Set estimate to current
284  //variance = sample / 2; // And variance to current / 2
285  m_variance = m; // try this
286  NS_LOG_DEBUG ("(first sample) m_variance += " << m);
287  }
288  m_nSamples++;
289 }
290 
292 {
293  NS_LOG_FUNCTION (this);
294  NS_LOG_DEBUG ("RetransmitTimeout: var " << m_variance.GetSeconds () << " est " << m_currentEstimatedRtt.GetSeconds () << " multiplier " << m_multiplier);
295  // RTO = srtt + 4* rttvar
296  int64_t temp = m_currentEstimatedRtt.ToInteger (Time::MS) + 4 * m_variance.ToInteger (Time::MS);
297  if (temp < m_minRto.ToInteger (Time::MS))
298  {
299  temp = m_minRto.ToInteger (Time::MS);
300  }
301  temp = temp * m_multiplier; // Apply backoff
302  Time retval = Time::FromInteger (temp, Time::MS);
303  NS_LOG_DEBUG ("RetransmitTimeout: return " << retval.GetSeconds ());
304  return (retval);
305 }
306 
307 Ptr<RttEstimator> RttMeanDeviation::Copy () const
308 {
309  NS_LOG_FUNCTION (this);
310  return CopyObject<RttMeanDeviation> (this);
311 }
312 
314 {
315  NS_LOG_FUNCTION (this);
316  // Reset to initial state
317  m_variance = Seconds (0);
319 }
320 void RttMeanDeviation::Gain (double g)
321 {
322  NS_LOG_FUNCTION (this);
323  NS_ASSERT_MSG( (g > 0) && (g < 1), "RttMeanDeviation: Gain must be less than 1 and greater than 0" );
324  m_gain = g;
325 }
326 
327 } //namespace ns3
keep track of time unit.
Definition: nstime.h:149
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:59
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:311
double ToDouble(enum Unit timeUnit) const
Definition: nstime.h:399
int64_t ToInteger(enum Unit timeUnit) const
Definition: nstime.h:367
The "Mean--Deviation" RTT estimator, as discussed by Van Jacobson.
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
virtual TypeId GetInstanceTypeId(void) const
static Time FromDouble(double value, enum Unit timeUnit)
Definition: nstime.h:388
double GetSeconds(void) const
Definition: nstime.h:262
virtual void ResetMultiplier()
Resets the estimation multiplier to 1.
Time GetCurrentEstimate(void) const
gets the current RTT estimate.
Base class for all RTT Estimators.
Definition: rtt-estimator.h:58
virtual void Measurement(Time t)=0
Add a new measurement to the estimator. Pure virtual function.
virtual void SentSeq(SequenceNumber32 seq, uint32_t size)
Note that a particular sequence has been sent.
void ConstructSelf(const AttributeConstructionList &attributes)
Definition: object-base.cc:65
Time GetMinRto(void) const
Get the Minimum RTO.
Time RetransmitTimeout()
Returns the estimated RTO.
void SetMinRto(Time minRto)
Sets the Minimum RTO.
virtual void Reset()
Resets the estimation to its initial state.
static Time Now(void)
Definition: simulator.cc:179
void Reset()
Resets sthe estimator.
virtual void IncreaseMultiplier()
Increase the estimation multiplier up to MaxMultiplier.
#define NS_ASSERT_MSG(condition, message)
Definition: assert.h:86
static Time FromInteger(uint64_t value, enum Unit timeUnit)
Definition: nstime.h:347
void Measurement(Time measure)
Add a new measurement to the estimator.
virtual TypeId GetInstanceTypeId(void) const
Time Seconds(double seconds)
create ns3::Time instances in units of seconds.
Definition: nstime.h:586
Helper class to store RTT measurements.
Definition: rtt-estimator.h:40
void SetCurrentEstimate(Time estimate)
Sets the current RTT estimate (forcefully).
#define NS_LOG_DEBUG(msg)
Definition: log.h:255
virtual void ClearSent()
Clear all history entries.
void Gain(double g)
Sets the estimator Gain.
Hold an floating point type.
Definition: double.h:41
a unique identifier for an interface.
Definition: type-id.h:44
TypeId SetParent(TypeId tid)
Definition: type-id.cc:471
virtual Time AckSeq(SequenceNumber32 ackSeq)
Note that a particular ack sequence has been received.