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 
34 NS_LOG_COMPONENT_DEFINE("SatDefaultSuperframeAllocator");
35 
36 namespace ns3
37 {
38 
39 NS_OBJECT_ENSURE_REGISTERED(SatDefaultSuperframeAllocator);
40 
41 TypeId
43 {
44  static TypeId tid =
45  TypeId("ns3::SatDefaultSuperframeAllocator")
46  .SetParent<SatSuperframeAllocator>()
47  .AddAttribute("TargetLoad",
48  "Target load limits upper bound of the symbols in a frame.",
49  DoubleValue(0.9),
51  MakeDoubleChecker<double>())
52  .AddAttribute("FcaEnabled",
53  "Free capacity allocation (FCA) enable status.",
54  BooleanValue(false),
55  MakeBooleanAccessor(&SatDefaultSuperframeAllocator::m_fcaEnabled),
56  MakeBooleanChecker())
57  .AddAttribute(
58  "RcBasedAllocationEnabled",
59  "Time slot generated per RC symbols instead of sum of UT symbols.",
60  BooleanValue(false),
62  MakeBooleanChecker());
63  return tid;
64 }
65 
66 TypeId
68 {
69  NS_LOG_FUNCTION(this);
70 
71  return GetTypeId();
72 }
73 
75  : SatSuperframeAllocator(superFrameConf),
76  m_targetLoad(0.0),
77  m_fcaEnabled(false),
78  m_minCarrierPayloadInBytes(0),
79  m_minimumRateBasedBytesLeft(0),
80  m_rcBasedAllocationEnabled(false),
81  m_totalBandwidth(0.0)
82 {
83  NS_LOG_FUNCTION(this);
84 
85  uint32_t currentMinCarrierPayloadInBytes = std::numeric_limits<uint32_t>::max();
86  uint32_t currentMostRobustSlotPayloadInBytes = std::numeric_limits<uint32_t>::max();
87 
88  Ptr<SatFrameConf> parentFrameConf = nullptr;
89  Ptr<SatFrameAllocator> parentFrameAllocator = nullptr;
90  for (uint8_t i = 0; i < superFrameConf->GetFrameCount(); i++)
91  {
92  Ptr<SatFrameConf> frameConf = superFrameConf->GetFrameConf(i);
93  if (!frameConf->IsRandomAccess())
94  {
95  Ptr<SatFrameConf> parentConf = frameConf->GetParent();
96  if (parentConf != parentFrameConf)
97  {
98  NS_ASSERT_MSG(parentConf == nullptr,
99  "Wrong ordering of frame confs. Need to have subdivided ones right "
100  "after their parents.");
101  parentFrameAllocator = nullptr;
102  }
103  parentFrameConf = frameConf;
104 
105  Ptr<SatFrameAllocator> frameAllocator =
106  Create<SatFrameAllocator>(frameConf,
107  i,
108  superFrameConf->GetConfigType(),
109  parentFrameAllocator);
110  m_frameAllocators.push_back(frameAllocator);
111  parentFrameAllocator = frameAllocator;
112 
113  uint32_t minCarrierPayloadInBytes = frameAllocator->GetCarrierMinPayloadInBytes();
114 
115  if (minCarrierPayloadInBytes < currentMinCarrierPayloadInBytes)
116  {
117  currentMinCarrierPayloadInBytes = minCarrierPayloadInBytes;
118  m_minCarrierPayloadInBytes = minCarrierPayloadInBytes;
119  }
120 
121  uint32_t mostRobustSlotPayloadInBytes =
122  frameAllocator->GetMostRobustWaveform()->GetPayloadInBytes();
123 
124  if (mostRobustSlotPayloadInBytes < currentMostRobustSlotPayloadInBytes)
125  {
126  currentMostRobustSlotPayloadInBytes = mostRobustSlotPayloadInBytes;
127  m_mostRobustSlotPayloadInBytes = mostRobustSlotPayloadInBytes;
128  }
129 
131  frameAllocator->GetCarrierCount() * minCarrierPayloadInBytes;
132  m_totalBandwidth += frameAllocator->GetCarrierBandwidthHz(true);
133  }
134  }
135 }
136 
138 {
139  NS_LOG_FUNCTION(this);
140 }
141 
142 void
145 {
146  NS_LOG_FUNCTION(this << &allocReqs);
147 
148  std::map<Ptr<SatFrameAllocator>, uint32_t> wsrDemand;
149 
150  NS_LOG_LOGIC("Select best carrier for each terminal request");
151  for (auto& allocRequest : allocReqs)
152  {
153  uint32_t bestWaveFormId = 0;
154  Ptr<SatFrameAllocator> selectedFrameAllocator =
155  SelectBestCarrier(allocRequest->m_cno, bestWaveFormId);
156  if (selectedFrameAllocator != nullptr)
157  {
158  for (auto& request : allocRequest->m_reqPerRc)
159  {
160  wsrDemand[selectedFrameAllocator] +=
161  request.m_craBytes + std::max(request.m_minRbdcBytes, request.m_rbdcBytes) +
162  request.m_vbdcBytes;
163  }
164  }
165  else
166  {
167  NS_LOG_WARN("SatDefaultSuperframeAllocator::SelectCarriers: No suitable frame and "
168  "waveform found for "
169  "terminal at "
170  << allocRequest->m_address << " with C/N0 of " << allocRequest->m_cno
171  << ". "
172  "Ignoring this terminal in carrier selection.");
173  }
174  }
175 
176  NS_LOG_LOGIC("Calculate Load Coefficient");
177  double requestedBandwidth = 0.0;
178  for (auto& demand : wsrDemand)
179  {
180  requestedBandwidth +=
181  demand.first->GetCarrierBandwidthHz() * demand.second / demand.first->GetVolumeBytes();
182  }
183  double loadCoefficient = std::min(std::max(0.1, m_totalBandwidth / requestedBandwidth), 10.0);
184  NS_LOG_INFO("" << allocReqs.size() << " requested " << requestedBandwidth << "Hz through "
185  << wsrDemand.size() << " subdivision levels; giving a load coefficient of "
186  << loadCoefficient);
187 
188  std::map<Ptr<SatFrameAllocator>, double, SatFrameAllocator::BandwidthComparator> scaledDemand;
189  for (auto& demand : wsrDemand)
190  {
191  scaledDemand[demand.first] =
192  loadCoefficient * demand.second / demand.first->GetVolumeBytes() + 1;
193  }
194 
195  NS_LOG_LOGIC("Zero-out old carrier selection");
196  for (auto& frameAllocator : m_frameAllocators)
197  {
198  uint16_t zeroReference = 0;
199  frameAllocator->SelectCarriers(zeroReference, 0);
200  }
201 
202  NS_LOG_LOGIC("Allocate carriers in subdivision levels");
203  while (!scaledDemand.empty())
204  {
205  NS_LOG_LOGIC("Find bandwidth of the original frame");
206  Ptr<SatFrameAllocator> frameAllocator = scaledDemand.begin()->first;
207  while (frameAllocator->GetParent() != nullptr)
208  {
209  frameAllocator = frameAllocator->GetParent();
210  }
211  double remainingBandwidth = frameAllocator->GetCarrierBandwidthHz(true);
212  NS_ASSERT_MSG(remainingBandwidth != 0.0, "Could not find bandwidth of original frame");
213 
214  // Select carriers from the most subdivided version of the frame up to the original
215  frameAllocator = scaledDemand.begin()->first;
216  uint16_t offset = 0;
217  while (frameAllocator != nullptr)
218  {
219  auto frameDemand = scaledDemand.find(frameAllocator);
220  uint16_t demand = 0;
221  if (frameDemand != scaledDemand.end())
222  {
223  demand = frameDemand->second;
224  scaledDemand.erase(frameDemand);
225  }
226  NS_LOG_LOGIC(demand << " carriers requested on (subdivided) frame "
227  << frameAllocator->GetCarrierBandwidthHz());
228  uint16_t carriersCount = 0;
229  double carrierBandwidth = frameAllocator->GetCarrierBandwidthHz();
230  if (frameAllocator->GetParent() != nullptr)
231  {
232  // Select requested carriers of subdivided frames
233  uint16_t remainingCarriers = remainingBandwidth / carrierBandwidth;
234  carriersCount = std::max(uint16_t(0), std::min(demand, remainingCarriers));
235  }
236 
237  frameAllocator->SelectCarriers(carriersCount, offset);
238  remainingBandwidth -= carriersCount * carrierBandwidth;
239  NS_LOG_INFO("Remaining bandwidth on non-subdivided frame: " << remainingBandwidth);
240  offset = (carriersCount + offset) / 2;
241  frameAllocator = frameAllocator->GetParent();
242  }
243 
244  if (remainingBandwidth < 0.0)
245  {
246  NS_FATAL_ERROR(
247  "SatDefaultSuperframeAllocator::SelectCarriers: remaining bandwidth is negative");
248  }
249  }
250 }
251 
252 Ptr<SatFrameAllocator>
253 SatDefaultSuperframeAllocator::SelectBestCarrier(double cno, uint32_t& bestWaveFormId)
254 {
255  NS_LOG_FUNCTION(this << cno);
256 
257  double cnoDiff = std::numeric_limits<double>::infinity();
258  Ptr<SatFrameAllocator> selectedFrameAllocator = nullptr;
259 
260  for (auto& frameAllocator : m_frameAllocators)
261  {
262  uint32_t waveFormId;
263  double waveformCNo;
264  if (frameAllocator->GetBestWaveform(cno, waveFormId, waveformCNo))
265  {
266  double diff = cno - waveformCNo;
267  if (diff < cnoDiff)
268  {
269  cnoDiff = diff;
270  bestWaveFormId = waveFormId;
271  selectedFrameAllocator = frameAllocator;
272  }
273  }
274  }
275 
276  return selectedFrameAllocator;
277 }
278 
279 void
281 {
282  NS_LOG_FUNCTION(this);
283 
284  for (FrameAllocatorContainer_t::iterator it = m_frameAllocators.begin();
285  it != m_frameAllocators.end();
286  it++)
287  {
288  (*it)->Reset();
289  }
290 }
291 
292 void
295  uint32_t maxSizeInBytes,
297  TracedCallback<uint32_t> waveformTrace,
298  TracedCallback<uint32_t, uint32_t> utLoadTrace,
299  TracedCallback<uint32_t, double> loadTrace)
300 {
301  NS_LOG_FUNCTION(this);
302 
303  if (tbtpContainer.empty())
304  {
305  NS_FATAL_ERROR("TBTP container must contain at least one message.");
306  }
307 
308  for (FrameAllocatorContainer_t::iterator it = m_frameAllocators.begin();
309  it != m_frameAllocators.end();
310  it++)
311  {
312  (*it)->GenerateTimeSlots(tbtpContainer,
313  maxSizeInBytes,
314  utAllocContainer,
316  waveformTrace,
317  utLoadTrace,
318  loadTrace);
319  }
320 }
321 
322 void
325 {
326  NS_LOG_FUNCTION(this);
327 
328  if (m_superframeConf->GetConfigType() == SatSuperframeConf::CONFIG_TYPE_3)
329  {
330  SelectCarriers(allocReqs);
331  }
332 
334 
335  for (SatFrameAllocator::SatFrameAllocContainer_t::iterator itReq = allocReqs.begin();
336  itReq != allocReqs.end();
337  itReq++)
338  {
339  AllocateToFrame(*itReq);
340  }
341 
342  for (FrameAllocatorContainer_t::iterator it = m_frameAllocators.begin();
343  it != m_frameAllocators.end();
344  it++)
345  {
346  (*it)->PreAllocateSymbols(m_targetLoad, m_fcaEnabled);
347  }
348 }
349 
350 void
352  bool controlSlotsEnabled)
353 {
354  NS_LOG_FUNCTION(this << minimumRateBytes);
355 
356  uint32_t rateBasedByteToCheck = minimumRateBytes;
357 
358  if (controlSlotsEnabled)
359  {
360  rateBasedByteToCheck += m_mostRobustSlotPayloadInBytes;
361  }
362 
363  if (rateBasedByteToCheck > m_minCarrierPayloadInBytes)
364  {
365  NS_FATAL_ERROR("Minimum requested bytes ("
366  << minimumRateBytes << ") for UT is greater than bytes in minimum carrier ("
367  << m_minCarrierPayloadInBytes << ")");
368  }
369  else if (rateBasedByteToCheck > m_minimumRateBasedBytesLeft)
370  {
371  NS_FATAL_ERROR("Minimum requested bytes ("
372  << minimumRateBytes << ") for UT is greater than minimum bytes left ("
373  << m_minimumRateBasedBytesLeft << ")");
374  }
375  else
376  {
377  m_minimumRateBasedBytesLeft -= minimumRateBytes;
378  }
379 }
380 
381 void
383  bool controlSlotsEnabled)
384 {
385  NS_LOG_FUNCTION(this << minimumRateBytes);
386 
387  uint32_t rateBasedByteToCheck = minimumRateBytes;
388 
389  if (controlSlotsEnabled)
390  {
391  rateBasedByteToCheck += m_mostRobustSlotPayloadInBytes;
392  }
393 
394  if (rateBasedByteToCheck > m_minCarrierPayloadInBytes)
395  {
396  NS_FATAL_ERROR("Minimum released bytes ("
397  << minimumRateBytes << ") for UT is greater than bytes in minimum carrier ("
398  << m_minCarrierPayloadInBytes << ")");
399  }
400  else
401  {
402  m_minimumRateBasedBytesLeft += minimumRateBytes;
403  }
404 }
405 
406 bool
408 {
409  NS_LOG_FUNCTION(this);
410 
411  bool allocated = false;
412 
413  SupportedFramesMap_t supportedFrames;
414 
415  // find supported symbol rates (frames)
416  for (auto& frameAllocator : m_frameAllocators)
417  {
418  uint32_t waveformId = 0;
419  double cnoThreshold = std::numeric_limits<double>::quiet_NaN();
420  if (frameAllocator->GetCarrierCount() &&
421  frameAllocator->GetBestWaveform(allocReq->m_cno, waveformId, cnoThreshold))
422  {
423  supportedFrames.insert(std::make_pair(frameAllocator, waveformId));
424  }
425  }
426 
427  NS_LOG_INFO("Terminal with C/N0 of " << allocReq->m_cno << " found " << supportedFrames.size()
428  << " supported frames.");
429 
430  if (!supportedFrames.empty())
431  {
432  // allocate with CC level CRA + RBDC + VBDC
433  allocated =
435 
436  if (!allocated)
437  {
438  // allocate with CC level CRA + RBDC
439  allocated =
440  AllocateBasedOnCc(SatFrameAllocator::CC_LEVEL_CRA_RBDC, allocReq, supportedFrames);
441 
442  if (!allocated)
443  {
444  // allocate with CC level CRA + MIM RBDC
446  allocReq,
447  supportedFrames);
448 
449  if (!allocated)
450  {
451  // allocate with CC level CRA
453  allocReq,
454  supportedFrames);
455  }
456  }
457  }
458  }
459 
460  return allocated;
461 }
462 
463 bool
466  const SupportedFramesMap_t& frames)
467 {
468  NS_LOG_FUNCTION(this << ccLevel);
469 
470  double loadInSymbols = 0;
471  SupportedFramesMap_t::const_iterator selectedFrame = frames.begin();
472 
473  if (frames.empty())
474  {
475  NS_FATAL_ERROR("Tried to allocate without frames!!!");
476  }
477 
478  // find the lowest load frame
479  for (SupportedFramesMap_t::const_iterator it = frames.begin(); it != frames.end(); it++)
480  {
481  if (it == frames.begin())
482  {
483  loadInSymbols = it->first->GetCcLoad(ccLevel);
484  }
485  else if (it->first->GetCcLoad(ccLevel) < loadInSymbols)
486  {
487  selectedFrame = it;
488  loadInSymbols = it->first->GetCcLoad(ccLevel);
489  }
490  }
491 
492  return selectedFrame->first->Allocate(ccLevel, allocReq, selectedFrame->second);
493 }
494 
495 } // 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.