|
45 |
{ |
45 |
{ |
46 |
static TypeId tid = TypeId ("ns3::RttEstimator") |
46 |
static TypeId tid = TypeId ("ns3::RttEstimator") |
47 |
.SetParent<Object> () |
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", |
48 |
.AddAttribute ("InitialEstimation", |
54 |
"Initial RTT estimation", |
49 |
"Initial RTT estimation", |
55 |
TimeValue (Seconds (1.0)), |
50 |
TimeValue (Seconds (1.0)), |
56 |
MakeTimeAccessor (&RttEstimator::m_initialEstimatedRtt), |
51 |
MakeTimeAccessor (&RttEstimator::m_initialEstimatedRtt), |
57 |
MakeTimeChecker ()) |
52 |
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, |
62 |
&RttEstimator::GetMinRto), |
63 |
MakeTimeChecker ()) |
64 |
; |
53 |
; |
65 |
return tid; |
54 |
return tid; |
66 |
} |
55 |
} |
67 |
|
56 |
|
68 |
void |
57 |
Time |
69 |
RttEstimator::SetMinRto (Time minRto) |
58 |
RttEstimator::GetEstimate (void) const |
70 |
{ |
59 |
{ |
71 |
NS_LOG_FUNCTION (this << minRto); |
60 |
return m_estimatedRtt; |
72 |
m_minRto = minRto; |
|
|
73 |
} |
74 |
Time |
75 |
RttEstimator::GetMinRto (void) const |
76 |
{ |
77 |
return m_minRto; |
78 |
} |
79 |
void |
80 |
RttEstimator::SetCurrentEstimate (Time estimate) |
81 |
{ |
82 |
NS_LOG_FUNCTION (this << estimate); |
83 |
m_currentEstimatedRtt = estimate; |
84 |
} |
85 |
Time |
86 |
RttEstimator::GetCurrentEstimate (void) const |
87 |
{ |
88 |
return m_currentEstimatedRtt; |
89 |
} |
61 |
} |
90 |
|
62 |
|
91 |
|
63 |
Time |
92 |
//RttHistory methods |
64 |
RttEstimator::GetEstimateVariation (void) const |
93 |
RttHistory::RttHistory (SequenceNumber32 s, uint32_t c, Time t) |
|
|
94 |
: seq (s), count (c), time (t), retx (false) |
95 |
{ |
65 |
{ |
96 |
NS_LOG_FUNCTION (this); |
66 |
return m_estimatedRttVariation; |
97 |
} |
67 |
} |
98 |
|
68 |
|
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 |
|
69 |
|
105 |
// Base class methods |
70 |
// Base class methods |
106 |
|
71 |
|
107 |
RttEstimator::RttEstimator () |
72 |
RttEstimator::RttEstimator () |
108 |
: m_next (1), m_history (), |
73 |
: m_nSamples (0) |
109 |
m_nSamples (0), |
|
|
110 |
m_multiplier (1) |
111 |
{ |
74 |
{ |
112 |
NS_LOG_FUNCTION (this); |
75 |
NS_LOG_FUNCTION (this); |
113 |
//note next=1 everywhere since first segment will have sequence 1 |
|
|
114 |
|
76 |
|
115 |
// We need attributes initialized here, not later, so use the |
77 |
// We need attributes initialized here, not later, so use the |
116 |
// ConstructSelf() technique documented in the manual |
78 |
// ConstructSelf() technique documented in the manual |
117 |
ObjectBase::ConstructSelf (AttributeConstructionList ()); |
79 |
ObjectBase::ConstructSelf (AttributeConstructionList ()); |
118 |
m_currentEstimatedRtt = m_initialEstimatedRtt; |
80 |
m_estimatedRtt = m_initialEstimatedRtt; |
119 |
NS_LOG_DEBUG ("Initialize m_currentEstimatedRtt to " << m_currentEstimatedRtt.GetSeconds () << " sec."); |
81 |
NS_LOG_DEBUG ("Initialize m_estimatedRtt to " << m_estimatedRtt.GetSeconds () << " sec."); |
120 |
} |
82 |
} |
121 |
|
83 |
|
122 |
RttEstimator::RttEstimator (const RttEstimator& c) |
84 |
RttEstimator::RttEstimator (const RttEstimator& c) |
123 |
: Object (c), m_next (c.m_next), m_history (c.m_history), |
85 |
: Object (c), |
124 |
m_maxMultiplier (c.m_maxMultiplier), |
|
|
125 |
m_initialEstimatedRtt (c.m_initialEstimatedRtt), |
86 |
m_initialEstimatedRtt (c.m_initialEstimatedRtt), |
126 |
m_currentEstimatedRtt (c.m_currentEstimatedRtt), m_minRto (c.m_minRto), |
87 |
m_estimatedRtt (c.m_estimatedRtt), |
127 |
m_nSamples (c.m_nSamples), m_multiplier (c.m_multiplier) |
88 |
m_estimatedRttVariation (c.m_estimatedRttVariation), |
|
|
89 |
m_nSamples (c.m_nSamples) |
128 |
{ |
90 |
{ |
129 |
NS_LOG_FUNCTION (this); |
91 |
NS_LOG_FUNCTION (this); |
130 |
} |
92 |
} |
|
140 |
return GetTypeId (); |
102 |
return GetTypeId (); |
141 |
} |
103 |
} |
142 |
|
104 |
|
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 |
|
171 |
Time RttEstimator::EstimateRttFromSeq (SequenceNumber32 ackSeq) |
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 |
|
196 |
void RttEstimator::ClearSent () |
197 |
{ |
198 |
NS_LOG_FUNCTION (this); |
199 |
// Clear all history entries |
200 |
m_next = 1; |
201 |
m_history.clear (); |
202 |
} |
203 |
|
204 |
void RttEstimator::IncreaseMultiplier () |
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 |
|
211 |
void RttEstimator::ResetMultiplier () |
212 |
{ |
213 |
NS_LOG_FUNCTION (this); |
214 |
m_multiplier = 1; |
215 |
} |
216 |
|
217 |
void RttEstimator::Reset () |
105 |
void RttEstimator::Reset () |
218 |
{ |
106 |
{ |
219 |
NS_LOG_FUNCTION (this); |
107 |
NS_LOG_FUNCTION (this); |
220 |
// Reset to initial state |
108 |
// Reset to initial state |
221 |
m_next = 1; |
109 |
m_estimatedRtt = m_initialEstimatedRtt; |
222 |
m_currentEstimatedRtt = m_initialEstimatedRtt; |
110 |
m_estimatedRttVariation = Time (0); |
223 |
m_history.clear (); // Remove all info from the history |
|
|
224 |
m_nSamples = 0; |
111 |
m_nSamples = 0; |
225 |
ResetMultiplier (); |
|
|
226 |
} |
112 |
} |
227 |
|
113 |
|
228 |
|
|
|
229 |
|
230 |
//----------------------------------------------------------------------------- |
114 |
//----------------------------------------------------------------------------- |
231 |
//----------------------------------------------------------------------------- |
115 |
//----------------------------------------------------------------------------- |
232 |
// Mean-Deviation Estimator |
116 |
// Mean-Deviation Estimator |
|
239 |
static TypeId tid = TypeId ("ns3::RttMeanDeviation") |
123 |
static TypeId tid = TypeId ("ns3::RttMeanDeviation") |
240 |
.SetParent<RttEstimator> () |
124 |
.SetParent<RttEstimator> () |
241 |
.AddConstructor<RttMeanDeviation> () |
125 |
.AddConstructor<RttMeanDeviation> () |
242 |
.AddAttribute ("Gain", |
126 |
.AddAttribute ("Alpha", |
243 |
"Gain used in estimating the RTT, must be 0 < Gain < 1", |
127 |
"Gain used in estimating the RTT, must be 0 < alpha < 1", |
244 |
DoubleValue (0.1), |
128 |
DoubleValue (0.125), |
245 |
MakeDoubleAccessor (&RttMeanDeviation::m_gain), |
129 |
MakeDoubleAccessor (&RttMeanDeviation::m_alpha), |
|
|
130 |
MakeDoubleChecker<double> ()) |
131 |
.AddAttribute ("Beta", |
132 |
"Gain used in estimating the RTT variance, must be 0 < beta < 1", |
133 |
DoubleValue (0.25), |
134 |
MakeDoubleAccessor (&RttMeanDeviation::m_beta), |
246 |
MakeDoubleChecker<double> ()) |
135 |
MakeDoubleChecker<double> ()) |
247 |
; |
136 |
; |
248 |
return tid; |
137 |
return tid; |
249 |
} |
138 |
} |
250 |
|
139 |
|
251 |
RttMeanDeviation::RttMeanDeviation() : |
140 |
RttMeanDeviation::RttMeanDeviation() |
252 |
m_variance (0) |
141 |
{ |
253 |
{ |
|
|
254 |
NS_LOG_FUNCTION (this); |
142 |
NS_LOG_FUNCTION (this); |
255 |
} |
143 |
} |
256 |
|
144 |
|
257 |
RttMeanDeviation::RttMeanDeviation (const RttMeanDeviation& c) |
145 |
RttMeanDeviation::RttMeanDeviation (const RttMeanDeviation& c) |
258 |
: RttEstimator (c), m_gain (c.m_gain), m_variance (c.m_variance) |
146 |
: RttEstimator (c), m_alpha (c.m_alpha), m_beta (c.m_beta) |
259 |
{ |
147 |
{ |
260 |
NS_LOG_FUNCTION (this); |
148 |
NS_LOG_FUNCTION (this); |
261 |
} |
149 |
} |
|
270 |
{ |
158 |
{ |
271 |
NS_LOG_FUNCTION (this << m); |
159 |
NS_LOG_FUNCTION (this << m); |
272 |
if (m_nSamples) |
160 |
if (m_nSamples) |
273 |
{ // Not first |
161 |
{ // Not first sample |
274 |
Time err (m - m_currentEstimatedRtt); |
162 |
Time err (m - m_estimatedRtt); |
275 |
double gErr = err.ToDouble (Time::S) * m_gain; |
163 |
double gErr = err.ToDouble (Time::S) * m_alpha; |
276 |
m_currentEstimatedRtt += Time::FromDouble (gErr, Time::S); |
164 |
m_estimatedRtt += Time::FromDouble (gErr, Time::S); |
277 |
Time difference = Abs (err) - m_variance; |
165 |
|
278 |
NS_LOG_DEBUG ("m_variance += " << Time::FromDouble (difference.ToDouble (Time::S) * m_gain, Time::S)); |
166 |
Time difference = Abs (err) - m_estimatedRttVariation; |
279 |
m_variance += Time::FromDouble (difference.ToDouble (Time::S) * m_gain, Time::S); |
167 |
NS_LOG_DEBUG ("m_estimatedRttVariation += " << Time::FromDouble (difference.ToDouble (Time::S) * m_beta, Time::S)); |
|
|
168 |
m_estimatedRttVariation += Time::FromDouble (difference.ToDouble (Time::S) * m_beta, Time::S); |
280 |
} |
169 |
} |
281 |
else |
170 |
else |
282 |
{ // First sample |
171 |
{ // First sample |
283 |
m_currentEstimatedRtt = m; // Set estimate to current |
172 |
m_estimatedRtt = m; // Set estimate to current |
284 |
//variance = sample / 2; // And variance to current / 2 |
173 |
m_estimatedRttVariation = m / 2; // And variation to current / 2 |
285 |
m_variance = m; // try this |
174 |
NS_LOG_DEBUG ("(first sample) m_estimatedRttVariation += " << m); |
286 |
NS_LOG_DEBUG ("(first sample) m_variance += " << m); |
|
|
287 |
} |
175 |
} |
288 |
m_nSamples++; |
176 |
m_nSamples++; |
289 |
} |
177 |
} |
290 |
|
178 |
|
291 |
Time RttMeanDeviation::RetransmitTimeout () |
179 |
//Time RttMeanDeviation::RetransmitTimeout () |
292 |
{ |
180 |
//{ |
293 |
NS_LOG_FUNCTION (this); |
181 |
// NS_LOG_FUNCTION (this); |
294 |
NS_LOG_DEBUG ("RetransmitTimeout: var " << m_variance.GetSeconds () << " est " << m_currentEstimatedRtt.GetSeconds () << " multiplier " << m_multiplier); |
182 |
// NS_LOG_DEBUG ("RetransmitTimeout: var " << m_variance.GetSeconds () << " est " << m_currentEstimatedRtt.GetSeconds () << " multiplier " << m_multiplier); |
295 |
// RTO = srtt + 4* rttvar |
183 |
// // RTO = srtt + 4* rttvar |
296 |
int64_t temp = m_currentEstimatedRtt.ToInteger (Time::MS) + 4 * m_variance.ToInteger (Time::MS); |
184 |
// int64_t temp = m_currentEstimatedRtt.ToInteger (Time::MS) + 4 * m_variance.ToInteger (Time::MS); |
297 |
if (temp < m_minRto.ToInteger (Time::MS)) |
185 |
// if (temp < m_minRto.ToInteger (Time::MS)) |
298 |
{ |
186 |
// { |
299 |
temp = m_minRto.ToInteger (Time::MS); |
187 |
// temp = m_minRto.ToInteger (Time::MS); |
300 |
} |
188 |
// } |
301 |
temp = temp * m_multiplier; // Apply backoff |
189 |
// temp = temp * m_multiplier; // Apply backoff |
302 |
Time retval = Time::FromInteger (temp, Time::MS); |
190 |
// Time retval = Time::FromInteger (temp, Time::MS); |
303 |
NS_LOG_DEBUG ("RetransmitTimeout: return " << retval.GetSeconds ()); |
191 |
// NS_LOG_DEBUG ("RetransmitTimeout: return " << retval.GetSeconds ()); |
304 |
return (retval); |
192 |
// return (retval); |
305 |
} |
193 |
//} |
306 |
|
194 |
|
307 |
Ptr<RttEstimator> RttMeanDeviation::Copy () const |
195 |
Ptr<RttEstimator> RttMeanDeviation::Copy () const |
308 |
{ |
196 |
{ |
|
313 |
void RttMeanDeviation::Reset () |
201 |
void RttMeanDeviation::Reset () |
314 |
{ |
202 |
{ |
315 |
NS_LOG_FUNCTION (this); |
203 |
NS_LOG_FUNCTION (this); |
316 |
// Reset to initial state |
|
|
317 |
m_variance = Seconds (0); |
318 |
RttEstimator::Reset (); |
204 |
RttEstimator::Reset (); |
319 |
} |
205 |
} |
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 |
|
206 |
|
327 |
} //namespace ns3 |
207 |
} //namespace ns3 |