5#define NS_LOG_APPEND_CONTEXT \
8 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
11#include "nr-mac-scheduler-ofdma.h"
13#include "nr-fh-control.h"
22NS_LOG_COMPONENT_DEFINE(
"NrMacSchedulerOfdma");
23NS_OBJECT_ENSURE_REGISTERED(NrMacSchedulerOfdma);
29 TypeId(
"ns3::NrMacSchedulerOfdma")
31 .AddAttribute(
"SymPerBeamType",
32 "Type of symbol allocation per beam",
34 MakeEnumAccessor<SymPerBeamType>(&NrMacSchedulerOfdma::SetSymPerBeamType),
43 "Number of assigned symbol per beam. Gets called every time an assignment is made",
44 MakeTraceSourceAccessor(&NrMacSchedulerOfdma::m_tracedValueSymPerBeam),
45 "ns3::TracedValueCallback::Uint32");
55NrMacSchedulerOfdma::SetSymPerBeamType(SymPerBeamType type)
57 m_symPerBeamType = type;
58 switch (m_symPerBeamType)
61 m_symPerBeam = CreateObject<NrMacSchedulerOfdmaSymbolPerBeamPF>(
66 m_symPerBeam = CreateObject<NrMacSchedulerOfdmaSymbolPerBeamRR>();
69 m_symPerBeam = CreateObject<NrMacSchedulerOfdmaSymbolPerBeamLB>();
72 NS_ABORT_MSG(
"Invalid NrMacSchedulerOfdma::m_symPerBeamType");
80 BeamSymbolMap ret = m_symPerBeam->GetSymPerBeam(symAvail, activeDl);
83 for (
const auto& [beam, ueVector] : activeDl)
85 if (ret.find(beam) == ret.end())
93 for (
const auto& v : ret)
101NrMacSchedulerOfdma::AdvanceToNextUeToSchedule(
102 std::vector<UePtrAndBufferReq>::iterator& schedInfoIt,
103 const std::vector<UePtrAndBufferReq>::iterator end,
104 uint32_t resourcesAssignable)
const
107 while (schedInfoIt != end)
109 const uint32_t bufQueueSize = schedInfoIt->second;
110 if (schedInfoIt->first->m_dlTbSize >= std::max(bufQueueSize, 10U))
112 std::advance(schedInfoIt, 1);
119 !ShouldScheduleUeBasedOnFronthaul(schedInfoIt, resourcesAssignable))
121 std::advance(schedInfoIt, 1);
133NrMacSchedulerOfdma::ShouldScheduleUeBasedOnFronthaul(
134 const std::vector<UePtrAndBufferReq>::iterator& schedInfoIt,
135 uint32_t resourcesAssignable)
const
138 uint32_t quantizationStep = resourcesAssignable;
141 GetUe(*schedInfoIt)->m_dlMcs,
142 GetUe(*schedInfoIt)->m_rnti,
143 GetUe(*schedInfoIt)->m_dlRank);
145 maxAssignable = std::max(maxAssignable, 5 * resourcesAssignable);
149 return GetUe(*schedInfoIt)->m_dlRBG.size() + quantizationStep <= maxAssignable;
153NrMacSchedulerOfdma::AllocateCurrentResourceToUe(std::shared_ptr<NrMacSchedulerUeInfo> currentUe,
154 const uint32_t& currentRbg,
155 const uint32_t beamSym,
156 FTResources& assignedResources,
157 std::vector<bool>& availableRbgs)
161 auto& assignedRbgs = currentUe->m_dlRBG;
162 auto existingRbgs = assignedRbgs.size();
163 assignedRbgs.resize(assignedRbgs.size() + beamSym);
164 std::fill(assignedRbgs.begin() + existingRbgs, assignedRbgs.end(), currentRbg);
165 assignedResources.m_rbg++;
167 auto& assignedSymbols = currentUe->m_dlSym;
168 auto existingSymbols = assignedSymbols.size();
169 assignedSymbols.resize(assignedSymbols.size() + beamSym);
170 std::iota(assignedSymbols.begin() + existingSymbols, assignedSymbols.end(), 0);
171 assignedResources.m_sym = beamSym;
173 availableRbgs.at(currentRbg) =
false;
177NrMacSchedulerOfdma::DeallocateCurrentResourceFromUe(
178 std::shared_ptr<NrMacSchedulerUeInfo> currentUe,
179 const uint32_t& currentRbg,
180 const uint32_t beamSym,
181 FTResources& assignedResources,
182 std::vector<bool>& availableRbgs)
184 auto& assignedRbgs = currentUe->m_dlRBG;
185 auto& assignedSymbols = currentUe->m_dlSym;
187 assignedRbgs.resize(assignedRbgs.size() - beamSym);
188 assignedSymbols.resize(assignedSymbols.size() - beamSym);
190 NS_ASSERT_MSG(assignedResources.m_rbg > 0,
191 "Should have more than 0 resources allocated before deallocating");
192 assignedResources.m_rbg--;
194 assignedResources.m_sym = assignedResources.m_rbg == 0 ? 0 : assignedResources.m_sym;
195 availableRbgs.at(currentRbg) =
true;
199NrMacSchedulerOfdma::AttemptAllocationOfCurrentResourceToUe(
200 std::vector<UePtrAndBufferReq>::iterator schedInfoIt,
201 std::set<uint32_t>& remainingRbgSet,
202 const uint32_t beamSym,
203 FTResources& assignedResources,
204 std::vector<bool>& availableRbgs)
const
206 auto currentUe = schedInfoIt->first;
208 uint32_t currentRbgPos = std::numeric_limits<uint32_t>::max();
211 if (currentUe->m_dlSbMcsInfo.empty() ||
214 currentRbgPos = *remainingRbgSet.begin();
220 for (
auto resourcePos : remainingRbgSet)
222 const auto resourceSb = currentUe->m_rbgToSb.at(resourcePos);
223 if (currentUe->m_dlSbMcsInfo.at(resourceSb).cqi > maxCqi)
225 currentRbgPos = resourcePos;
226 maxCqi = currentUe->m_dlSbMcsInfo.at(resourceSb).cqi;
231 if (!currentUe->m_dlRBG.empty())
234 currentUe->m_dlSbMcsInfo.at(currentUe->m_rbgToSb.at(currentUe->m_dlRBG.at(0))).cqi;
235 if (maxCqi < bestCqi - 4)
242 if (currentRbgPos == std::numeric_limits<uint32_t>::max())
248 AllocateCurrentResourceToUe(currentUe,
255 const auto previousTbSize = currentUe->m_dlTbSize;
260 const auto currentTbSize = currentUe->m_dlTbSize;
261 if (currentTbSize < previousTbSize * 0.99)
264 DeallocateCurrentResourceFromUe(currentUe,
274 remainingRbgSet.erase(currentRbgPos);
279NrMacSchedulerOfdma::DeallocateResourcesDueToFronthaulConstraint(
280 const std::vector<UePtrAndBufferReq>& ueVector,
281 const uint32_t& beamSym,
282 FTResources& assignedResources,
283 std::vector<bool>& availableRbgs)
const
286 std::vector<UePtrAndBufferReq> fhUeVector = ueVector;
287 auto rng = std::default_random_engine{};
288 std::shuffle(std::begin(fhUeVector), std::end(fhUeVector), rng);
289 for (
auto schedInfoIt : fhUeVector)
291 const auto numAssignedResourcesToUe = GetUe(schedInfoIt)->m_dlRBG.size();
292 if (numAssignedResourcesToUe > 0)
295 GetUe(schedInfoIt)->GetDlMcs(),
296 numAssignedResourcesToUe,
297 GetUe(schedInfoIt)->m_dlRank) == 0)
301 while (!schedInfoIt.first->m_dlRBG.empty())
303 uint32_t resourceAssigned = schedInfoIt.first->m_dlRBG.back();
304 DeallocateCurrentResourceFromUe(schedInfoIt.first,
343 NS_LOG_FUNCTION(
this);
345 NS_LOG_DEBUG(
"# beams active flows: " << activeDl.size() <<
", # sym: " << symAvail);
352 for (
const auto& el : activeDl)
355 uint32_t beamSym = symPerBeam.at(GetBeamId(el));
356 std::vector<UePtrAndBufferReq> ueVector;
359 std::vector<bool> availableRbgs = !dlNotchedRBGsMask.empty()
362 std::set<uint32_t> remainingRbgSet;
363 for (
size_t i = 0; i < availableRbgs.size(); i++)
365 if (availableRbgs.at(i))
367 remainingRbgSet.emplace(i);
371 NS_ASSERT(!remainingRbgSet.empty());
373 for (
const auto& ue : GetUeVector(el))
375 ueVector.emplace_back(ue);
380 while (!remainingRbgSet.empty())
383 const auto prevRemaining = remainingRbgSet.size();
393 auto schedInfoIt = ueVector.begin();
396 while (AdvanceToNextUeToSchedule(schedInfoIt, ueVector.end(), beamSym))
400 if (!AttemptAllocationOfCurrentResourceToUe(schedInfoIt,
406 std::advance(schedInfoIt, 1);
411 NS_LOG_DEBUG(
"assignedResources " << GetUe(*schedInfoIt)->m_dlRBG.back()
412 <<
" DL RBG, spanned over " << beamSym
413 <<
" SYM, to UE " << GetUe(*schedInfoIt)->m_rnti);
417 for (
auto& ue : ueVector)
419 if (GetUe(ue)->m_rnti != GetUe(*schedInfoIt)->m_rnti)
429 if (prevRemaining == remainingRbgSet.size())
441 for (
auto& schedInfoIt : GetUeVector(el))
443 if (!GetUe(schedInfoIt)->m_dlRBG.empty())
447 GetUe(schedInfoIt)->m_dlRBG.size(),
448 GetUe(schedInfoIt)->m_rnti,
449 GetUe(schedInfoIt)->m_dlRank);
451 NS_LOG_DEBUG(
"UE " << GetUe(schedInfoIt)->m_rnti
452 <<
" MCS from sched: " << GetUe(schedInfoIt)->GetDlMcs()
453 <<
" FH max MCS: " << maxMcsAssignable);
455 GetUe(schedInfoIt)->m_fhMaxMcsAssignable =
456 std::min(GetUe(schedInfoIt)->GetDlMcs(), maxMcsAssignable);
465 DeallocateResourcesDueToFronthaulConstraint(ueVector,
479 NS_LOG_FUNCTION(
this);
481 NS_LOG_DEBUG(
"# beams active flows: " << activeUl.size() <<
", # sym: " << symAvail);
488 for (
const auto& el : activeUl)
491 uint32_t beamSym = symPerBeam.at(GetBeamId(el));
492 std::vector<UePtrAndBufferReq> ueVector;
495 uint32_t resources = !ulNotchedRBGsMask.empty()
496 ? std::count(ulNotchedRBGsMask.begin(), ulNotchedRBGsMask.end(), 1)
498 NS_ASSERT(resources > 0);
500 for (
const auto& ue : GetUeVector(el))
502 ueVector.emplace_back(ue);
505 for (
auto& ue : ueVector)
510 while (resources > 0)
518 auto schedInfoIt = ueVector.begin();
521 while (schedInfoIt != ueVector.end())
523 uint32_t bufQueueSize = schedInfoIt->second;
524 if (GetUe(*schedInfoIt)->m_ulTbSize >= std::max(bufQueueSize, 12U))
526 std::advance(schedInfoIt, 1);
536 if (schedInfoIt == ueVector.end())
543 auto& assignedRbgs = GetUe(*schedInfoIt)->m_ulRBG;
544 auto existingRbgs = assignedRbgs.size();
545 assignedRbgs.resize(assignedRbgs.size() + beamSym);
546 std::fill(assignedRbgs.begin() + existingRbgs, assignedRbgs.end(), resources - 1);
549 auto& assignedSymbols = GetUe(*schedInfoIt)->m_ulSym;
550 auto existingSymbols = assignedSymbols.size();
551 assignedSymbols.resize(assignedSymbols.size() + beamSym);
552 std::iota(assignedSymbols.begin() + existingSymbols, assignedSymbols.end(), 0);
553 assigned.
m_sym = beamSym;
558 NS_LOG_DEBUG(
"Assigned " << assigned.
m_rbg <<
" UL RBG, spanned over " << beamSym
559 <<
" SYM, to UE " << GetUe(*schedInfoIt)->m_rnti);
564 for (
auto& ue : ueVector)
566 if (GetUe(ue)->m_rnti != GetUe(*schedInfoIt)->m_rnti)
586std::shared_ptr<DciInfoElementTdma>
588 const std::shared_ptr<NrMacSchedulerUeInfo>& ueInfo,
589 uint32_t maxSym)
const
591 NS_LOG_FUNCTION(
this);
593 auto dlMcs = ueInfo->GetDlMcs();
594 ueInfo->m_fhMaxMcsAssignable.reset();
595 uint32_t tbs =
m_dlAmc->CalculateTbSize(dlMcs,
602 NS_ASSERT(maxSym <= UINT8_MAX);
607 NS_LOG_DEBUG(
"While creating DCI for UE "
608 << ueInfo->m_rnti <<
" assigned "
609 << std::set<uint32_t>(ueInfo->m_dlRBG.begin(), ueInfo->m_dlRBG.end()).size()
610 <<
" DL RBG, but TBS < 10");
611 ueInfo->m_dlTbSize = 0;
615 const auto rbgBitmask = CreateRbgBitmaskFromAllocatedRbgs(ueInfo->m_dlRBG);
616 std::ostringstream oss;
617 for (
const auto& x : rbgBitmask)
619 oss << std::to_string(x) <<
" ";
622 NS_LOG_INFO(
"UE " << ueInfo->m_rnti <<
" assigned RBG from " << spoint->
m_rbg <<
" with mask "
623 << oss.str() <<
" for " <<
static_cast<uint32_t
>(maxSym) <<
" SYM.");
625 std::shared_ptr<DciInfoElementTdma> dci =
626 std::make_shared<DciInfoElementTdma>(ueInfo->m_rnti,
632 ueInfo->m_dlPrecMats,
640 dci->m_rbgBitmask = std::move(rbgBitmask);
642 NS_ASSERT(std::count(dci->m_rbgBitmask.begin(), dci->m_rbgBitmask.end(), 0) !=
648std::shared_ptr<DciInfoElementTdma>
650 const std::shared_ptr<NrMacSchedulerUeInfo>& ueInfo,
651 uint32_t maxSym)
const
653 NS_LOG_FUNCTION(
this);
655 uint32_t tbs =
m_ulAmc->CalculateTbSize(ueInfo->m_ulMcs,
663 NS_LOG_DEBUG(
"While creating UL DCI for UE "
664 << ueInfo->m_rnti <<
" assigned "
665 << std::set<uint32_t>(ueInfo->m_ulRBG.begin(), ueInfo->m_ulRBG.end()).size()
666 <<
" UL RBG, but TBS < 12");
670 uint32_t RBGNum = ueInfo->m_ulRBG.size() / maxSym;
671 const auto rbgBitmask = CreateRbgBitmaskFromAllocatedRbgs(ueInfo->m_ulRBG);
673 NS_LOG_INFO(
"UE " << ueInfo->m_rnti <<
" assigned RBG from " << spoint->
m_rbg <<
" to "
674 << spoint->
m_rbg + RBGNum <<
" for " <<
static_cast<uint32_t
>(maxSym)
677 NS_ASSERT(spoint->
m_sym >= maxSym);
678 std::shared_ptr<DciInfoElementTdma> dci =
679 std::make_shared<DciInfoElementTdma>(ueInfo->m_rnti,
681 spoint->
m_sym - maxSym,
685 ueInfo->m_ulPrecMats,
693 dci->m_rbgBitmask = std::move(rbgBitmask);
695 std::ostringstream oss;
696 for (
auto x : dci->m_rbgBitmask)
698 oss << std::to_string(x) <<
" ";
700 NS_LOG_INFO(
"UE " << ueInfo->m_rnti <<
" DCI RBG mask: " << oss.str());
702 NS_ASSERT(std::count(dci->m_rbgBitmask.begin(), dci->m_rbgBitmask.end(), 0) !=
712 spoint->
m_sym += symOfBeam;
719 spoint->
m_sym -= symOfBeam;
725 NS_LOG_FUNCTION(
this);
731NrMacSchedulerOfdma::CreateRbgBitmaskFromAllocatedRbgs(
732 const std::vector<uint16_t>& allocatedRbgs)
const
735 if (rbgNotchedBitmask.empty())
741 NS_ASSERT(rbgNotchedBitmask.size() == rbgBitmask.size());
745 for (
auto rbg : allocatedRbgs)
747 NS_ASSERT_MSG(rbgNotchedBitmask.at(rbg),
"Scheduled notched resource");
748 rbgBitmask.at(rbg) =
true;
@ Postponing
Postpone sending data (MAC Layer)
@ OptimizeRBs
Optimize RBs allocated.
@ OptimizeMcs
Optimize MCS.
Ptr< NrAmc > m_ulAmc
AMC pointer.
NrMacSchedulerUeInfo::McsCsiSource m_mcsCsiSource
CSI information source for DL MCS estimation.
NrFhSchedSapProvider * m_nrFhSchedSapProvider
FH Control SAP provider.
Ptr< NrAmc > m_dlAmc
AMC pointer.
bool m_activeUlAi
Flag for activating AI for uplink.
std::vector< bool > GetUlNotchedRbgMask() const
Get the notched (blank) RBGs Mask for the UL.
std::unordered_map< BeamId, uint32_t, BeamIdHash > BeamSymbolMap
Map between a BeamId and the symbol assigned to that beam.
uint16_t GetBwpId() const
Get the bwp id of this MAC.
bool DoesFhAllocationFit(uint16_t bwpId, uint32_t mcs, uint32_t nRegs, uint8_t dlRank) const
Returns a boolean indicating whether the current allocation can fit in the available FH bandwidth (wh...
bool m_activeDlAi
Flag for activating AI for downlink.
std::unordered_map< BeamId, std::vector< UePtrAndBufferReq >, BeamIdHash > ActiveUeMap
Map between a BeamId and a vector of UE (the UE are in that beam)
std::vector< bool > GetDlNotchedRbgMask() const
Get the notched (blank) RBGs Mask for the DL.
uint16_t GetBandwidthInRbg() const
uint64_t GetNumRbPerRbg() const
Private function that is used to get the number of resource blocks per resource block group and also ...
uint8_t GetFhControlMethod() const
Get the FH Control Method.
PointInFTPlane FTResources
Represent an amount of RBG/symbols that can be, or is, assigned.
The base for all the OFDMA schedulers.
std::shared_ptr< DciInfoElementTdma > CreateDlDci(PointInFTPlane *spoint, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t maxSym) const override
Create the DL DCI in OFDMA mode.
void ChangeDlBeam(PointInFTPlane *spoint, uint32_t symOfBeam) const override
Advance the starting point by the number of symbols specified, resetting the RB count to 0.
NrMacSchedulerOfdma()
NrMacSchedulerOfdma constructor.
std::shared_ptr< DciInfoElementTdma > CreateUlDci(PointInFTPlane *spoint, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t maxSym) const override
Create a DCI for the specified UE for UL data.
NrMacSchedulerOfdma::BeamSymbolMap GetSymPerBeam(uint32_t symAvail, const ActiveUeMap &activeDl) const
Calculate the number of symbols to assign to each beam by calling using the technique selected in m_s...
BeamSymbolMap AssignULRBG(uint32_t symAvail, const ActiveUeMap &activeUl) const override
Assign the UL RBG to the active UE, and return the distribution of symbols per beam.
BeamSymbolMap AssignDLRBG(uint32_t symAvail, const ActiveUeMap &activeDl) const override
Assign the available DL RBG to the UEs.
@ ROUND_ROBIN
Distributes all symbols to the first active beam in the m_rrBeams queue.
@ PROPORTIONAL_FAIR
Distributes symbols to beams proportionally to mean achievable rate.
@ LOAD_BASED
Distributes symbols to beams proportionally to the buffer size of its users.
uint8_t GetTpc() const override
Returns TPC command.
static TypeId GetTypeId()
GetTypeId.
void ChangeUlBeam(PointInFTPlane *spoint, uint32_t symOfBeam) const override
Perform a custom operation on the starting point each time all the UE of an UL beam have been schedul...
The base for all the TDMA schedulers.
virtual std::function< bool(const NrMacSchedulerNs3::UePtrAndBufferReq &lhs, const NrMacSchedulerNs3::UePtrAndBufferReq &rhs)> GetUeCompareUlFn() const =0
Provide the comparison function to order the UE when scheduling UL.
virtual void AssignedUlResources(const UePtrAndBufferReq &ue, const FTResources &assigned, const FTResources &totalAssigned) const =0
Update the UE representation after a symbol (DL) has been assigned to it.
virtual std::function< bool(const NrMacSchedulerNs3::UePtrAndBufferReq &lhs, const NrMacSchedulerNs3::UePtrAndBufferReq &rhs)> GetUeCompareDlFn() const =0
Provide the comparison function to order the UE when scheduling DL.
virtual void NotAssignedUlResources(const UePtrAndBufferReq &ue, const FTResources ¬Assigned, const FTResources &totalAssigned) const =0
Update the UE representation after a symbol (UL) has been assigned to other UE.
virtual void NotAssignedDlResources(const UePtrAndBufferReq &ue, const FTResources ¬Assigned, const FTResources &totalAssigned) const =0
Update the UE representation after a symbol (DL) has been assigned to other UE.
virtual void AssignedDlResources(const UePtrAndBufferReq &ue, const FTResources &assigned, const FTResources &totalAssigned) const =0
Update the UE representation after a symbol (DL) has been assigned to it.
virtual void BeforeUlSched(const UePtrAndBufferReq &ue, const FTResources &assignableInIteration) const =0
Prepare UE for the UL scheduling.
virtual void CallNotifyDlFn(const std::vector< UePtrAndBufferReq > &ueVector) const
Call the notify callback function in the OpenGymEnv class in the ns3-gym module for downlink.
virtual void CallNotifyUlFn(const std::vector< UePtrAndBufferReq > &ueVector) const
Call the notify callback function in the OpenGymEnv class in the ns3-gym module for uplink.
virtual void BeforeDlSched(const UePtrAndBufferReq &ue, const FTResources &assignableInIteration) const =0
Prepare UE for the DL scheduling.
@ WIDEBAND_MCS
Wideband MCS.
@ DATA
Used for DL/UL DATA.
Point in the Frequency/Time plane.
uint32_t m_rbg
Represent the starting RBG.
uint8_t m_sym
Represent the starting symbol.