NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
ndn-consumer-pcon.cpp
Go to the documentation of this file.
1 /* -*- 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 
22 NS_LOG_COMPONENT_DEFINE("ndn.ConsumerPcon");
23 
24 namespace ns3 {
25 namespace ndn {
26 
28 
29 constexpr double ConsumerPcon::CUBIC_C;
30 constexpr uint32_t ConsumerPcon::BIC_MAX_INCREMENT;
31 constexpr uint32_t ConsumerPcon::BIC_LOW_WINDOW;
32 
33 TypeId
35 {
36  static TypeId tid =
37  TypeId("ns3::ndn::ConsumerPcon")
38  .SetGroupName("Ndn")
39  .SetParent<ConsumerWindow>()
40  .AddConstructor<ConsumerPcon>()
41 
42  .AddAttribute("CcAlgorithm",
43  "Specify which window adaptation algorithm to use (AIMD, BIC, or CUBIC)",
44  EnumValue(CcAlgorithm::AIMD),
45  MakeEnumAccessor(&ConsumerPcon::m_ccAlgorithm),
46  MakeEnumChecker(CcAlgorithm::AIMD, "AIMD", CcAlgorithm::BIC, "BIC",
47  CcAlgorithm::CUBIC, "CUBIC"))
48 
49  .AddAttribute("Beta",
50  "TCP Multiplicative Decrease factor",
51  DoubleValue(0.5),
52  MakeDoubleAccessor(&ConsumerPcon::m_beta),
53  MakeDoubleChecker<double>())
54 
55  .AddAttribute("CubicBeta",
56  "TCP CUBIC Multiplicative Decrease factor",
57  DoubleValue(0.8),
58  MakeDoubleAccessor(&ConsumerPcon::m_cubicBeta),
59  MakeDoubleChecker<double>())
60 
61  .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",
69  BooleanValue(true),
70  MakeBooleanAccessor(&ConsumerPcon::m_reactToCongestionMarks),
71  MakeBooleanChecker())
72 
73  .AddAttribute("UseCwa",
74  "If true, use Conservative Window Adaptation",
75  BooleanValue(true),
76  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),
83  MakeBooleanChecker());
84 
85  return tid;
86 }
87 
89  : m_ssthresh(std::numeric_limits<double>::max())
90  , m_highData(0)
91  , m_recPoint(0.0)
92  , 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)
101 {
102 }
103 
104 void
105 ConsumerPcon::OnData(shared_ptr<const Data> data)
106 {
107  Consumer::OnData(data);
108 
109  uint64_t sequenceNum = data->getName().get(-1).toSequenceNumber();
110 
111  // Set highest received Data to sequence number
112  if (m_highData < sequenceNum) {
113  m_highData = sequenceNum;
114  }
115 
116  if (data->getCongestionMark() > 0) {
117  if (m_reactToCongestionMarks) {
118  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 
136 }
137 
138 void
139 ConsumerPcon::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 
152 void
153 ConsumerPcon::WindowIncrease()
154 {
155  if (m_ccAlgorithm == CcAlgorithm::AIMD) {
156  if (m_window < m_ssthresh) {
157  m_window += 1.0;
158  }
159  else {
160  m_window += (1.0 / m_window);
161  }
162  }
163  else if (m_ccAlgorithm == CcAlgorithm::CUBIC) {
164  CubicIncrease();
165  }
166  else if (m_ccAlgorithm == CcAlgorithm::BIC) {
167  BicIncrease();
168  }
169  else {
170  BOOST_ASSERT_MSG(false, "Unknown CC Algorithm");
171  }
172  NS_LOG_DEBUG("Window size increased to " << m_window);
173 }
174 
175 void
176 ConsumerPcon::WindowDecrease()
177 {
178  if (!m_useCwa || m_highData > m_recPoint) {
179  const double diff = m_seq - m_highData;
180  BOOST_ASSERT(diff > 0);
181 
182  m_recPoint = m_seq + (m_addRttSuppress * diff);
183 
184  if (m_ccAlgorithm == CcAlgorithm::AIMD) {
185  // Normal TCP Decrease:
186  m_ssthresh = m_window * m_beta;
187  m_window = m_ssthresh;
188  }
189  else if (m_ccAlgorithm == CcAlgorithm::CUBIC) {
190  CubicDecrease();
191  }
192  else if (m_ccAlgorithm == CcAlgorithm::BIC) {
193  BicDecrease();
194  }
195  else {
196  BOOST_ASSERT_MSG(false, "Unknown CC Algorithm");
197  }
198 
199  // Window size cannot be reduced below initial size
200  if (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 
211 
212 void
213 ConsumerPcon::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 
257 void
258 ConsumerPcon::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 
280 void
281 ConsumerPcon::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 
317 void
318 ConsumerPcon::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 
345 } // namespace ndn
346 } // namespace ns3
virtual void OnData(shared_ptr< const Data > data) override
Method that will be called every time new Data arrives.
virtual void OnTimeout(uint32_t sequenceNum) override
Timeout event.
virtual void OnTimeout(uint32_t sequenceNumber)
Timeout event.
Copyright (c) 2011-2015 Regents of the University of California.
Ndn application for sending out Interest packets (window-based)
NS_OBJECT_ENSURE_REGISTERED(ContentStore)
static time_point now() noexcept
Definition: time.cpp:80
uint32_t m_seq
currently requested sequence number
TracedValue< double > m_window
virtual void ScheduleNextPacket()
Constructs the Interest packet and sends it using a callback to the underlying NDN protocol.
virtual void OnData(shared_ptr< const Data > contentObject)
Method that will be called every time new Data arrives.
Copyright (c) 2011-2015 Regents of the University of California.
TracedValue< uint32_t > m_inFlight
ndn ConsumerPcon