blob: 22427407cd2e6609059131aee7e59439f7ddebe1 [file] [log] [blame]
Eric Newberry8821d3e2018-07-04 16:42:01 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2011-2018 Regents of the University of California.
4 *
5 * This file is part of ndnSIM. See AUTHORS for complete list of ndnSIM authors and
6 * contributors.
7 *
8 * ndnSIM is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * ndnSIM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * ndnSIM, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 **/
19
20#include "ndn-consumer-pcon.hpp"
21
22NS_LOG_COMPONENT_DEFINE("ndn.ConsumerPcon");
23
24namespace ns3 {
25namespace ndn {
26
27NS_OBJECT_ENSURE_REGISTERED(ConsumerPcon);
28
schneiderklausaf97d0f2018-07-18 18:58:14 -070029constexpr double ConsumerPcon::CUBIC_C;
30constexpr uint32_t ConsumerPcon::BIC_MAX_INCREMENT;
31constexpr uint32_t ConsumerPcon::BIC_LOW_WINDOW;
32
Eric Newberry8821d3e2018-07-04 16:42:01 -040033TypeId
34ConsumerPcon::GetTypeId()
35{
36 static TypeId tid =
37 TypeId("ns3::ndn::ConsumerPcon")
38 .SetGroupName("Ndn")
39 .SetParent<ConsumerWindow>()
40 .AddConstructor<ConsumerPcon>()
41
schneiderklausaf97d0f2018-07-18 18:58:14 -070042 .AddAttribute("CcAlgorithm",
43 "Specify which window adaptation algorithm to use (AIMD, BIC, or CUBIC)",
Alexander Afanasyev65c49062018-07-25 11:55:25 -040044 EnumValue(CcAlgorithm::AIMD),
schneiderklausaf97d0f2018-07-18 18:58:14 -070045 MakeEnumAccessor(&ConsumerPcon::m_ccAlgorithm),
Alexander Afanasyev65c49062018-07-25 11:55:25 -040046 MakeEnumChecker(CcAlgorithm::AIMD, "AIMD", CcAlgorithm::BIC, "BIC",
47 CcAlgorithm::CUBIC, "CUBIC"))
schneiderklausaf97d0f2018-07-18 18:58:14 -070048
49 .AddAttribute("Beta",
50 "TCP Multiplicative Decrease factor",
Eric Newberry8821d3e2018-07-04 16:42:01 -040051 DoubleValue(0.5),
52 MakeDoubleAccessor(&ConsumerPcon::m_beta),
53 MakeDoubleChecker<double>())
54
schneiderklausaf97d0f2018-07-18 18:58:14 -070055 .AddAttribute("CubicBeta",
56 "TCP CUBIC Multiplicative Decrease factor",
57 DoubleValue(0.8),
58 MakeDoubleAccessor(&ConsumerPcon::m_cubicBeta),
Eric Newberry8821d3e2018-07-04 16:42:01 -040059 MakeDoubleChecker<double>())
60
schneiderklausaf97d0f2018-07-18 18:58:14 -070061 .AddAttribute("AddRttSuppress",
62 "Minimum number of RTTs (1 + this factor) between window decreases",
63 DoubleValue(0.5), // This default value was chosen after manual testing
64 MakeDoubleAccessor(&ConsumerPcon::m_addRttSuppress),
65 MakeDoubleChecker<double>())
66
67 .AddAttribute("ReactToCongestionMarks",
68 "If true, process received congestion marks",
Eric Newberry8821d3e2018-07-04 16:42:01 -040069 BooleanValue(true),
schneiderklausaf97d0f2018-07-18 18:58:14 -070070 MakeBooleanAccessor(&ConsumerPcon::m_reactToCongestionMarks),
Eric Newberry8821d3e2018-07-04 16:42:01 -040071 MakeBooleanChecker())
72
schneiderklausaf97d0f2018-07-18 18:58:14 -070073 .AddAttribute("UseCwa",
74 "If true, use Conservative Window Adaptation",
Eric Newberry8821d3e2018-07-04 16:42:01 -040075 BooleanValue(true),
schneiderklausaf97d0f2018-07-18 18:58:14 -070076 MakeBooleanAccessor(&ConsumerPcon::m_useCwa),
77 MakeBooleanChecker())
78
79 .AddAttribute("UseCubicFastConvergence",
80 "If true, use TCP CUBIC Fast Convergence",
81 BooleanValue(false),
82 MakeBooleanAccessor(&ConsumerPcon::m_useCubicFastConv),
Eric Newberry8821d3e2018-07-04 16:42:01 -040083 MakeBooleanChecker());
84
85 return tid;
86}
87
88ConsumerPcon::ConsumerPcon()
89 : m_ssthresh(std::numeric_limits<double>::max())
90 , m_highData(0)
91 , m_recPoint(0.0)
schneiderklausaf97d0f2018-07-18 18:58:14 -070092 , m_cubicWmax(0)
93 , m_cubicLastWmax(0)
94 , m_cubicLastDecrease(time::steady_clock::now())
95 , m_bicMinWin(0)
96 , m_bicMaxWin(std::numeric_limits<double>::max())
97 , m_bicTargetWin(0)
98 , m_bicSsCwnd(0)
99 , m_bicSsTarget(0)
100 , m_isBicSs(false)
Eric Newberry8821d3e2018-07-04 16:42:01 -0400101{
102}
103
104void
105ConsumerPcon::OnData(shared_ptr<const Data> data)
106{
107 Consumer::OnData(data);
108
schneiderklausaf97d0f2018-07-18 18:58:14 -0700109 uint64_t sequenceNum = data->getName().get(-1).toSequenceNumber();
Eric Newberry8821d3e2018-07-04 16:42:01 -0400110
111 // Set highest received Data to sequence number
112 if (m_highData < sequenceNum) {
113 m_highData = sequenceNum;
114 }
115
116 if (data->getCongestionMark() > 0) {
schneiderklausaf97d0f2018-07-18 18:58:14 -0700117 if (m_reactToCongestionMarks) {
Eric Newberry8821d3e2018-07-04 16:42:01 -0400118 NS_LOG_DEBUG("Received congestion mark: " << data->getCongestionMark());
119 WindowDecrease();
120 }
121 else {
122 NS_LOG_DEBUG("Ignored received congestion mark: " << data->getCongestionMark());
123 }
124 }
125 else {
126 WindowIncrease();
127 }
128
129 if (m_inFlight > static_cast<uint32_t>(0)) {
130 m_inFlight--;
131 }
132
133 NS_LOG_DEBUG("Window: " << m_window << ", InFlight: " << m_inFlight);
134
135 ScheduleNextPacket();
136}
137
138void
139ConsumerPcon::OnTimeout(uint32_t sequenceNum)
140{
141 WindowDecrease();
142
143 if (m_inFlight > static_cast<uint32_t>(0)) {
144 m_inFlight--;
145 }
146
147 NS_LOG_DEBUG("Window: " << m_window << ", InFlight: " << m_inFlight);
148
149 Consumer::OnTimeout(sequenceNum);
150}
151
152void
153ConsumerPcon::WindowIncrease()
154{
Alexander Afanasyev65c49062018-07-25 11:55:25 -0400155 if (m_ccAlgorithm == CcAlgorithm::AIMD) {
schneiderklausaf97d0f2018-07-18 18:58:14 -0700156 if (m_window < m_ssthresh) {
157 m_window += 1.0;
158 }
159 else {
160 m_window += (1.0 / m_window);
161 }
162 }
Alexander Afanasyev65c49062018-07-25 11:55:25 -0400163 else if (m_ccAlgorithm == CcAlgorithm::CUBIC) {
schneiderklausaf97d0f2018-07-18 18:58:14 -0700164 CubicIncrease();
165 }
Alexander Afanasyev65c49062018-07-25 11:55:25 -0400166 else if (m_ccAlgorithm == CcAlgorithm::BIC) {
schneiderklausaf97d0f2018-07-18 18:58:14 -0700167 BicIncrease();
Eric Newberry8821d3e2018-07-04 16:42:01 -0400168 }
169 else {
schneiderklausaf97d0f2018-07-18 18:58:14 -0700170 BOOST_ASSERT_MSG(false, "Unknown CC Algorithm");
Eric Newberry8821d3e2018-07-04 16:42:01 -0400171 }
Eric Newberry8821d3e2018-07-04 16:42:01 -0400172 NS_LOG_DEBUG("Window size increased to " << m_window);
173}
174
175void
176ConsumerPcon::WindowDecrease()
177{
schneiderklausaf97d0f2018-07-18 18:58:14 -0700178 if (!m_useCwa || m_highData > m_recPoint) {
Eric Newberry8821d3e2018-07-04 16:42:01 -0400179 const double diff = m_seq - m_highData;
schneiderklausaf97d0f2018-07-18 18:58:14 -0700180 BOOST_ASSERT(diff > 0);
Eric Newberry8821d3e2018-07-04 16:42:01 -0400181
schneiderklausaf97d0f2018-07-18 18:58:14 -0700182 m_recPoint = m_seq + (m_addRttSuppress * diff);
Eric Newberry8821d3e2018-07-04 16:42:01 -0400183
Alexander Afanasyev65c49062018-07-25 11:55:25 -0400184 if (m_ccAlgorithm == CcAlgorithm::AIMD) {
schneiderklausaf97d0f2018-07-18 18:58:14 -0700185 // Normal TCP Decrease:
186 m_ssthresh = m_window * m_beta;
187 m_window = m_ssthresh;
188 }
Alexander Afanasyev65c49062018-07-25 11:55:25 -0400189 else if (m_ccAlgorithm == CcAlgorithm::CUBIC) {
schneiderklausaf97d0f2018-07-18 18:58:14 -0700190 CubicDecrease();
191 }
Alexander Afanasyev65c49062018-07-25 11:55:25 -0400192 else if (m_ccAlgorithm == CcAlgorithm::BIC) {
schneiderklausaf97d0f2018-07-18 18:58:14 -0700193 BicDecrease();
194 }
195 else {
196 BOOST_ASSERT_MSG(false, "Unknown CC Algorithm");
197 }
Eric Newberry8821d3e2018-07-04 16:42:01 -0400198
199 // Window size cannot be reduced below initial size
200 if (m_window < m_initialWindow) {
201 m_window = m_initialWindow;
202 }
203
204 NS_LOG_DEBUG("Window size decreased to " << m_window);
205 }
206 else {
207 NS_LOG_DEBUG("Window decrease suppressed, HighData: " << m_highData << ", RecPoint: " << m_recPoint);
208 }
209}
210
schneiderklausaf97d0f2018-07-18 18:58:14 -0700211
212void
213ConsumerPcon::BicIncrease()
214{
215 if (m_window < BIC_LOW_WINDOW) {
216 // Normal TCP AIMD behavior
217 if (m_window < m_ssthresh) {
218 m_window = m_window + 1;
219 }
220 else {
221 m_window = m_window + 1.0 / m_window;
222 }
223 }
224 else if (!m_isBicSs) {
225 // Binary increase
226 if (m_bicTargetWin - m_window < BIC_MAX_INCREMENT) { // Binary search
227 m_window += (m_bicTargetWin - m_window) / m_window;
228 }
229 else {
230 m_window += BIC_MAX_INCREMENT / m_window; // Additive increase
231 }
232 // FIX for equal double values.
233 if (m_window + 0.00001 < m_bicMaxWin) {
234 m_bicMinWin = m_window;
235 m_bicTargetWin = (m_bicMaxWin + m_bicMinWin) / 2;
236 }
237 else {
238 m_isBicSs = true;
239 m_bicSsCwnd = 1;
240 m_bicSsTarget = m_window + 1.0;
241 m_bicMaxWin = std::numeric_limits<double>::max();
242 }
243 }
244 else {
245 // BIC slow start
246 m_window += m_bicSsCwnd / m_window;
247 if (m_window >= m_bicSsTarget) {
248 m_bicSsCwnd = 2 * m_bicSsCwnd;
249 m_bicSsTarget = m_window + m_bicSsCwnd;
250 }
251 if (m_bicSsCwnd >= BIC_MAX_INCREMENT) {
252 m_isBicSs = false;
253 }
254 }
255}
256
257void
258ConsumerPcon::BicDecrease()
259{
260 // BIC Decrease
261 if (m_window >= BIC_LOW_WINDOW) {
262 auto prev_max = m_bicMaxWin;
263 m_bicMaxWin = m_window;
264 m_window = m_window * m_cubicBeta;
265 m_bicMinWin = m_window;
266 if (prev_max > m_bicMaxWin) {
267 // Fast Convergence
268 m_bicMaxWin = (m_bicMaxWin + m_bicMinWin) / 2;
269 }
270 m_bicTargetWin = (m_bicMaxWin + m_bicMinWin) / 2;
271 }
272 else {
273 // Normal TCP Decrease:
274 m_ssthresh = m_window * m_cubicBeta;
275 m_window = m_ssthresh;
276 }
277}
278
279
280void
281ConsumerPcon::CubicIncrease()
282{
283 // 1. Time since last congestion event in Seconds
284 const double t = time::duration_cast<time::microseconds>(
285 time::steady_clock::now() - m_cubicLastDecrease).count() / 1e6;
286
287 // 2. Time it takes to increase the window to cubic_wmax
288 // K = cubic_root(W_max*(1-beta_cubic)/C) (Eq. 2)
289 const double k = std::cbrt(m_cubicWmax * (1 - m_cubicBeta) / CUBIC_C);
290
291 // 3. Target: W_cubic(t) = C*(t-K)^3 + W_max (Eq. 1)
292 const double w_cubic = CUBIC_C * std::pow(t - k, 3) + m_cubicWmax;
293
294 // 4. Estimate of Reno Increase (Currently Disabled)
295 // const double rtt = m_rtt->GetCurrentEstimate().GetSeconds();
296 // const double w_est = m_cubic_wmax*m_beta + (3*(1-m_beta)/(1+m_beta)) * (t/rtt);
297 constexpr double w_est = 0.0;
298
299 // Actual adaptation
300 if (m_window < m_ssthresh) {
301 m_window += 1.0;
302 }
303 else {
304 BOOST_ASSERT(m_cubicWmax > 0);
305
306 double cubic_increment = std::max(w_cubic, w_est) - m_window;
307 // Cubic increment must be positive:
308 // Note: This change is not part of the RFC, but I added it to improve performance.
309 if (cubic_increment < 0) {
310 cubic_increment = 0.0;
311 }
312 m_window += cubic_increment / m_window;
313 }
314}
315
316
317void
318ConsumerPcon::CubicDecrease()
319{
320 // This implementation is ported from https://datatracker.ietf.org/doc/rfc8312/
321
322 const double FAST_CONV_DIFF = 1.0; // In percent
323
324 // A flow remembers the last value of W_max,
325 // before it updates W_max for the current congestion event.
326
327 // Current w_max < last_wmax
328 if (m_useCubicFastConv && m_window < m_cubicLastWmax * (1 - FAST_CONV_DIFF / 100)) {
329 m_cubicLastWmax = m_window;
330 m_cubicWmax = m_window * (1.0 + m_cubicBeta) / 2.0;
331 }
332 else {
333 // Save old cwnd as w_max:
334 m_cubicLastWmax = m_window;
335 m_cubicWmax = m_window;
336 }
337
338 m_ssthresh = m_window * m_cubicBeta;
339 m_ssthresh = std::max<double>(m_ssthresh, m_initialWindow);
340 m_window = m_ssthresh;
341
342 m_cubicLastDecrease = time::steady_clock::now();
343}
344
Eric Newberry8821d3e2018-07-04 16:42:01 -0400345} // namespace ndn
346} // namespace ns3