satellite-default-superframe-allocator.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014 Magister Solutions Ltd
4  * Copyright (c) 2019 CNES
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation;
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Author: Sami Rantanen <sami.rantanen@magister.fi>
20  * Author: Joaquin Muguerza <jmuguerza@viveris.fr>
21  */
22 
24 
25 #include "satellite-utils.h"
26 
27 #include <ns3/boolean.h>
28 #include <ns3/double.h>
29 #include <ns3/log.h>
30 
31 #include <algorithm>
32 #include <limits>
33 #include <map>
34 #include <utility>
35 
36 NS_LOG_COMPONENT_DEFINE("SatDefaultSuperframeAllocator");
37 
38 namespace ns3
39 {
40 
41 NS_OBJECT_ENSURE_REGISTERED(SatDefaultSuperframeAllocator);
42 
43 TypeId
45 {
46  static TypeId tid =
47  TypeId("ns3::SatDefaultSuperframeAllocator")
48  .SetParent<SatSuperframeAllocator>()
49  .AddAttribute("TargetLoad",
50  "Target load limits upper bound of the symbols in a frame.",
51  DoubleValue(0.9),
53  MakeDoubleChecker<double>())
54  .AddAttribute("FcaEnabled",
55  "Free capacity allocation (FCA) enable status.",
56  BooleanValue(false),
57  MakeBooleanAccessor(&SatDefaultSuperframeAllocator::m_fcaEnabled),
58  MakeBooleanChecker())
59  .AddAttribute(
60  "RcBasedAllocationEnabled",
61  "Time slot generated per RC symbols instead of sum of UT symbols.",
62  BooleanValue(false),
64  MakeBooleanChecker());
65  return tid;
66 }
67 
68 TypeId
70 {
71  NS_LOG_FUNCTION(this);
72 
73  return GetTypeId();
74 }
75 
77  : SatSuperframeAllocator(superFrameConf),
78  m_targetLoad(0.0),
79  m_fcaEnabled(false),
80  m_minCarrierPayloadInBytes(0),
81  m_minimumRateBasedBytesLeft(0),
82  m_rcBasedAllocationEnabled(false),
83  m_totalBandwidth(0.0)
84 {
85  NS_LOG_FUNCTION(this);
86 
87  uint32_t currentMinCarrierPayloadInBytes = std::numeric_limits<uint32_t>::max();
88  uint32_t currentMostRobustSlotPayloadInBytes = std::numeric_limits<uint32_t>::max();
89 
90  Ptr<SatFrameConf> parentFrameConf = nullptr;
91  Ptr<SatFrameAllocator> parentFrameAllocator = nullptr;
92  for (uint8_t i = 0; i < superFrameConf->GetFrameCount(); i++)
93  {
94  Ptr<SatFrameConf> frameConf = superFrameConf->GetFrameConf(i);
95  if (!frameConf->IsRandomAccess())
96  {
97  Ptr<SatFrameConf> parentConf = frameConf->GetParent();
98  if (parentConf != parentFrameConf)
99  {
100  NS_ASSERT_MSG(parentConf == nullptr,
101  "Wrong ordering of frame confs. Need to have subdivided ones right "
102  "after their parents.");
103  parentFrameAllocator = nullptr;
104  }
105  parentFrameConf = frameConf;
106 
107  Ptr<SatFrameAllocator> frameAllocator =
108  Create<SatFrameAllocator>(frameConf,
109  i,
110  superFrameConf->GetConfigType(),
111  parentFrameAllocator);
112  m_frameAllocators.push_back(frameAllocator);
113  parentFrameAllocator = frameAllocator;
114 
115  uint32_t minCarrierPayloadInBytes = frameAllocator->GetCarrierMinPayloadInBytes();
116 
117  if (minCarrierPayloadInBytes < currentMinCarrierPayloadInBytes)
118  {
119  currentMinCarrierPayloadInBytes = minCarrierPayloadInBytes;
120  m_minCarrierPayloadInBytes = minCarrierPayloadInBytes;
121  }
122 
123  uint32_t mostRobustSlotPayloadInBytes =
124  frameAllocator->GetMostRobustWaveform()->GetPayloadInBytes();
125 
126  if (mostRobustSlotPayloadInBytes < currentMostRobustSlotPayloadInBytes)
127  {
128  currentMostRobustSlotPayloadInBytes = mostRobustSlotPayloadInBytes;
129  m_mostRobustSlotPayloadInBytes = mostRobustSlotPayloadInBytes;
130  }
131 
133  frameAllocator->GetCarrierCount() * minCarrierPayloadInBytes;
134  m_totalBandwidth += frameAllocator->GetCarrierBandwidthHz(true);
135  }
136  }
137 }
138 
140 {
141  NS_LOG_FUNCTION(this);
142 }
143 
144 void
147 {
148  NS_LOG_FUNCTION(this << &allocReqs);
149 
150  std::map<Ptr<SatFrameAllocator>, uint32_t> wsrDemand;
151 
152  NS_LOG_LOGIC("Select best carrier for each terminal request");
153  for (auto& allocRequest : allocReqs)
154  {
155  uint32_t bestWaveFormId = 0;
156  Ptr<SatFrameAllocator> selectedFrameAllocator =
157  SelectBestCarrier(allocRequest->m_cno, bestWaveFormId);
158  if (selectedFrameAllocator != nullptr)
159  {
160  for (auto& request : allocRequest->m_reqPerRc)
161  {
162  wsrDemand[selectedFrameAllocator] +=
163  request.m_craBytes + std::max(request.m_minRbdcBytes, request.m_rbdcBytes) +
164  request.m_vbdcBytes;
165  }
166  }
167  else
168  {
169  NS_LOG_WARN("SatDefaultSuperframeAllocator::SelectCarriers: No suitable frame and "
170  "waveform found for "
171  "terminal at "
172  << allocRequest->m_address << " with C/N0 of " << allocRequest->m_cno
173  << ". "
174  "Ignoring this terminal in carrier selection.");
175  }
176  }
177 
178  NS_LOG_LOGIC("Calculate Load Coefficient");
179  double requestedBandwidth = 0.0;
180  for (auto& demand : wsrDemand)
181  {
182  requestedBandwidth +=
183  demand.first->GetCarrierBandwidthHz() * demand.second / demand.first->GetVolumeBytes();
184  }
185  double loadCoefficient = std::min(std::max(0.1, m_totalBandwidth / requestedBandwidth), 10.0);
186  NS_LOG_INFO("" << allocReqs.size() << " requested " << requestedBandwidth << "Hz through "
187  << wsrDemand.size() << " subdivision levels; giving a load coefficient of "
188  << loadCoefficient);
189 
190  std::map<Ptr<SatFrameAllocator>, double, SatFrameAllocator::BandwidthComparator> scaledDemand;
191  for (auto& demand : wsrDemand)
192  {
193  scaledDemand[demand.first] =
194  loadCoefficient * demand.second / demand.first->GetVolumeBytes() + 1;
195  }
196 
197  NS_LOG_LOGIC("Zero-out old carrier selection");
198  for (auto& frameAllocator : m_frameAllocators)
199  {
200  uint16_t zeroReference = 0;
201  frameAllocator->SelectCarriers(zeroReference, 0);
202  }
203 
204  NS_LOG_LOGIC("Allocate carriers in subdivision levels");
205  while (!scaledDemand.empty())
206  {
207  NS_LOG_LOGIC("Find bandwidth of the original frame");
208  Ptr<SatFrameAllocator> frameAllocator = scaledDemand.begin()->first;
209  while (frameAllocator->GetParent() != nullptr)
210  {
211  frameAllocator = frameAllocator->GetParent();
212  }
213  double remainingBandwidth = frameAllocator->GetCarrierBandwidthHz(true);
214  NS_ASSERT_MSG(remainingBandwidth != 0.0, "Could not find bandwidth of original frame");
215 
216  // Select carriers from the most subdivided version of the frame up to the original
217  frameAllocator = scaledDemand.begin()->first;
218  uint16_t offset = 0;
219  while (frameAllocator != nullptr)
220  {
221  auto frameDemand = scaledDemand.find(frameAllocator);
222  uint16_t demand = 0;
223  if (frameDemand != scaledDemand.end())
224  {
225  demand = frameDemand->second;
226  scaledDemand.erase(frameDemand);
227  }
228  NS_LOG_LOGIC(demand << " carriers requested on (subdivided) frame "
229  << frameAllocator->GetCarrierBandwidthHz());
230  uint16_t carriersCount = 0;
231  double carrierBandwidth = frameAllocator->GetCarrierBandwidthHz();
232  if (frameAllocator->GetParent() != nullptr)
233  {
234  // Select requested carriers of subdivided frames
235  uint16_t remainingCarriers = remainingBandwidth / carrierBandwidth;
236  carriersCount = std::max(uint16_t(0), std::min(demand, remainingCarriers));
237  }
238 
239  frameAllocator->SelectCarriers(carriersCount, offset);
240  remainingBandwidth -= carriersCount * carrierBandwidth;
241  NS_LOG_INFO("Remaining bandwidth on non-subdivided frame: " << remainingBandwidth);
242  offset = (carriersCount + offset) / 2;
243  frameAllocator = frameAllocator->GetParent();
244  }
245 
246  if (remainingBandwidth < 0.0)
247  {
248  NS_FATAL_ERROR(
249  "SatDefaultSuperframeAllocator::SelectCarriers: remaining bandwidth is negative");
250  }
251  }
252 }
253 
254 Ptr<SatFrameAllocator>
255 SatDefaultSuperframeAllocator::SelectBestCarrier(double cno, uint32_t& bestWaveFormId)
256 {
257  NS_LOG_FUNCTION(this << cno);
258 
259  double cnoDiff = std::numeric_limits<double>::infinity();
260  Ptr<SatFrameAllocator> selectedFrameAllocator = nullptr;
261 
262  for (auto& frameAllocator : m_frameAllocators)
263  {
264  uint32_t waveFormId;
265  double waveformCNo;
266  if (frameAllocator->GetBestWaveform(cno, waveFormId, waveformCNo))
267  {
268  double diff = cno - waveformCNo;
269  if (diff < cnoDiff)
270  {
271  cnoDiff = diff;
272  bestWaveFormId = waveFormId;
273  selectedFrameAllocator = frameAllocator;
274  }
275  }
276  }
277 
278  return selectedFrameAllocator;
279 }
280 
281 void
283 {
284  NS_LOG_FUNCTION(this);
285 
286  for (FrameAllocatorContainer_t::iterator it = m_frameAllocators.begin();
287  it != m_frameAllocators.end();
288  it++)
289  {
290  (*it)->Reset();
291  }
292 }
293 
294 void
297  uint32_t maxSizeInBytes,
299  TracedCallback<uint32_t> waveformTrace,
300  TracedCallback<uint32_t, uint32_t> utLoadTrace,
301  TracedCallback<uint32_t, double> loadTrace)
302 {
303  NS_LOG_FUNCTION(this);
304 
305  if (tbtpContainer.empty())
306  {
307  NS_FATAL_ERROR("TBTP container must contain at least one message.");
308  }
309 
310  for (FrameAllocatorContainer_t::iterator it = m_frameAllocators.begin();
311  it != m_frameAllocators.end();
312  it++)
313  {
314  (*it)->GenerateTimeSlots(tbtpContainer,
315  maxSizeInBytes,
316  utAllocContainer,
318  waveformTrace,
319  utLoadTrace,
320  loadTrace);
321  }
322 }
323 
324 void
327 {
328  NS_LOG_FUNCTION(this);
329 
330  if (m_superframeConf->GetConfigType() == SatSuperframeConf::CONFIG_TYPE_3)
331  {
332  SelectCarriers(allocReqs);
333  }
334 
336 
337  for (SatFrameAllocator::SatFrameAllocContainer_t::iterator itReq = allocReqs.begin();
338  itReq != allocReqs.end();
339  itReq++)
340  {
341  AllocateToFrame(*itReq);
342  }
343 
344  for (FrameAllocatorContainer_t::iterator it = m_frameAllocators.begin();
345  it != m_frameAllocators.end();
346  it++)
347  {
348  (*it)->PreAllocateSymbols(m_targetLoad, m_fcaEnabled);
349  }
350 }
351 
352 void
354  bool controlSlotsEnabled)
355 {
356  NS_LOG_FUNCTION(this << minimumRateBytes);
357 
358  uint32_t rateBasedByteToCheck = minimumRateBytes;
359 
360  if (controlSlotsEnabled)
361  {
362  rateBasedByteToCheck += m_mostRobustSlotPayloadInBytes;
363  }
364 
365  if (rateBasedByteToCheck > m_minCarrierPayloadInBytes)
366  {
367  NS_FATAL_ERROR("Minimum requested bytes ("
368  << minimumRateBytes << ") for UT is greater than bytes in minimum carrier ("
369  << m_minCarrierPayloadInBytes << ")");
370  }
371  else if (rateBasedByteToCheck > m_minimumRateBasedBytesLeft)
372  {
373  NS_FATAL_ERROR("Minimum requested bytes ("
374  << minimumRateBytes << ") for UT is greater than minimum bytes left ("
375  << m_minimumRateBasedBytesLeft << ")");
376  }
377  else
378  {
379  m_minimumRateBasedBytesLeft -= minimumRateBytes;
380  }
381 }
382 
383 void
385  bool controlSlotsEnabled)
386 {
387  NS_LOG_FUNCTION(this << minimumRateBytes);
388 
389  uint32_t rateBasedByteToCheck = minimumRateBytes;
390 
391  if (controlSlotsEnabled)
392  {
393  rateBasedByteToCheck += m_mostRobustSlotPayloadInBytes;
394  }
395 
396  if (rateBasedByteToCheck > m_minCarrierPayloadInBytes)
397  {
398  NS_FATAL_ERROR("Minimum released bytes ("
399  << minimumRateBytes << ") for UT is greater than bytes in minimum carrier ("
400  << m_minCarrierPayloadInBytes << ")");
401  }
402  else
403  {
404  m_minimumRateBasedBytesLeft += minimumRateBytes;
405  }
406 }
407 
408 bool
410 {
411  NS_LOG_FUNCTION(this);
412 
413  bool allocated = false;
414 
415  SupportedFramesMap_t supportedFrames;
416 
417  // find supported symbol rates (frames)
418  for (auto& frameAllocator : m_frameAllocators)
419  {
420  uint32_t waveformId = 0;
421  double cnoThreshold = std::numeric_limits<double>::quiet_NaN();
422  if (frameAllocator->GetCarrierCount() &&
423  frameAllocator->GetBestWaveform(allocReq->m_cno, waveformId, cnoThreshold))
424  {
425  supportedFrames.insert(std::make_pair(frameAllocator, waveformId));
426  }
427  }
428 
429  NS_LOG_INFO("Terminal with C/N0 of " << allocReq->m_cno << " found " << supportedFrames.size()
430  << " supported frames.");
431 
432  if (!supportedFrames.empty())
433  {
434  // allocate with CC level CRA + RBDC + VBDC
435  allocated =
437 
438  if (!allocated)
439  {
440  // allocate with CC level CRA + RBDC
441  allocated =
442  AllocateBasedOnCc(SatFrameAllocator::CC_LEVEL_CRA_RBDC, allocReq, supportedFrames);
443 
444  if (!allocated)
445  {
446  // allocate with CC level CRA + MIM RBDC
448  allocReq,
449  supportedFrames);
450 
451  if (!allocated)
452  {
453  // allocate with CC level CRA
455  allocReq,
456  supportedFrames);
457  }
458  }
459  }
460  }
461 
462  return allocated;
463 }
464 
465 bool
468  const SupportedFramesMap_t& frames)
469 {
470  NS_LOG_FUNCTION(this << ccLevel);
471 
472  double loadInSymbols = 0;
473  SupportedFramesMap_t::const_iterator selectedFrame = frames.begin();
474 
475  if (frames.empty())
476  {
477  NS_FATAL_ERROR("Tried to allocate without frames!!!");
478  }
479 
480  // find the lowest load frame
481  for (SupportedFramesMap_t::const_iterator it = frames.begin(); it != frames.end(); it++)
482  {
483  if (it == frames.begin())
484  {
485  loadInSymbols = it->first->GetCcLoad(ccLevel);
486  }
487  else if (it->first->GetCcLoad(ccLevel) < loadInSymbols)
488  {
489  selectedFrame = it;
490  loadInSymbols = it->first->GetCcLoad(ccLevel);
491  }
492  }
493 
494  return selectedFrame->first->Allocate(ccLevel, allocReq, selectedFrame->second);
495 }
496 
497 } // namespace ns3
bool AllocateBasedOnCc(SatFrameAllocator::CcLevel_t ccLevel, SatFrameAllocator::SatFrameAllocReq *allocReq, const SupportedFramesMap_t &frames)
Allocate given request according to type.
bool AllocateToFrame(SatFrameAllocator::SatFrameAllocReq *allocReq)
Allocate a request to a frame.
void PreAllocateSymbols(SatFrameAllocator::SatFrameAllocContainer_t &allocReqs)
Preallocate symbols for given to UTs in superframe.
void ReleaseMinimumRate(uint32_t minimumRateBytes, bool controlSlotsEnabled)
Release minimum rate from the allocator.
SatDefaultSuperframeAllocator(Ptr< SatSuperframeConf > superFrameConf)
Construct SatDefaultSuperframeAllocator.
void RemoveAllocations()
Remove allocations from all frames maintained by frame allocator.
virtual TypeId GetInstanceTypeId(void) const
Get the type ID of instance.
Ptr< SatFrameAllocator > SelectBestCarrier(double cno, uint32_t &bestWaveFormId)
Select which carrier is the best suited for handling requests of a terminal communicating at the give...
void SelectCarriers(SatFrameAllocator::SatFrameAllocContainer_t &allocReqs)
Select which carriers to use from the underlying frames.
void GenerateTimeSlots(SatFrameAllocator::TbtpMsgContainer_t &tbtpContainer, uint32_t maxSizeInBytes, SatFrameAllocator::UtAllocInfoContainer_t &utAllocContainer, TracedCallback< uint32_t > waveformTrace, TracedCallback< uint32_t, uint32_t > utLoadTrace, TracedCallback< uint32_t, double > loadTrace)
Generate time slots in TBTP(s) for the UT/RC.
~SatDefaultSuperframeAllocator()
Destruct SatDefaultSuperframeAllocator.
static TypeId GetTypeId(void)
derived from object
std::map< Ptr< SatFrameAllocator >, uint32_t > SupportedFramesMap_t
Container for the supported SatFrameAllocator (frames).
void ReserveMinimumRate(uint32_t minimumRateBytes, bool controlSlotsEnabled)
Reserve minimum rate from the allocator.
SatFrameAllocReq is used to define frame allocation parameters when requesting allocation from SatFra...
std::vector< SatFrameAllocReq * > SatFrameAllocContainer_t
Container to store SatFrameAllocReq item pointers.
std::vector< Ptr< SatTbtpMessage > > TbtpMsgContainer_t
Container to store generated TBTP messages.
@ CC_LEVEL_CRA_RBDC
CC level CRA + RBDC.
@ CC_LEVEL_CRA_RBDC_VBDC
CC level CRA + RBDC + VBDC.
@ CC_LEVEL_CRA_MIN_RBDC
CC level CRA + Minimum RBDC.
std::map< Address, UtAllocInfoItem_t > UtAllocInfoContainer_t
Map container to store UT allocation information.
helper class for Satellite Beam Scheduler.
@ CONFIG_TYPE_3
Configuration type 3.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.
BandwidthComparator is a custom functor meant as comparison function for std::map.