5G-LENA nr-v3.3-120-gdac69c56
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-mac-scheduler-tdma.cc
1// Copyright (c) 2019 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
5#define NS_LOG_APPEND_CONTEXT \
6 do \
7 { \
8 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
9 } while (false);
10
11#include "nr-mac-scheduler-tdma.h"
12
13#include "ns3/log.h"
14
15#include <algorithm>
16#include <functional>
17#include <numeric>
18
19namespace ns3
20{
21
22NS_LOG_COMPONENT_DEFINE("NrMacSchedulerTdma");
23NS_OBJECT_ENSURE_REGISTERED(NrMacSchedulerTdma);
24
25TypeId
27{
28 static TypeId tid = TypeId("ns3::NrMacSchedulerTdma").SetParent<NrMacSchedulerNs3>();
29 return tid;
30}
31
35
39
40std::vector<NrMacSchedulerNs3::UePtrAndBufferReq>
41NrMacSchedulerTdma::GetUeVectorFromActiveUeMap(const NrMacSchedulerNs3::ActiveUeMap& activeUes)
42{
43 std::vector<UePtrAndBufferReq> ueVector;
44 for (const auto& el : activeUes)
45 {
46 uint64_t size = ueVector.size();
47 GetSecond GetUeVector;
48 for (const auto& ue : GetUeVector(el))
49 {
50 ueVector.emplace_back(ue);
51 }
52 NS_ASSERT(size + GetUeVector(el).size() == ueVector.size());
53 }
54 return ueVector;
55}
56
104NrMacSchedulerTdma::AssignRBGTDMA(uint32_t symAvail,
105 const ActiveUeMap& activeUe,
106 const std::string& type,
107 const BeforeSchedFn& BeforeSchedFn,
108 const GetCompareUeFn& GetCompareFn,
109 const GetTBSFn& GetTBSFn,
110 const GetRBGFn& GetRBGFn,
111 const GetSymFn& GetSymFn,
112 const AfterSuccessfulAssignmentFn& SuccessfulAssignmentFn,
113 const AfterUnsuccessfulAssignmentFn& UnSuccessfulAssignmentFn,
114 const CallNotifyFn& callNotifyFn) const
115{
116 NS_LOG_FUNCTION(this);
117 NS_LOG_DEBUG("Assigning RBG in " << type << ", # beams active flows: " << activeUe.size()
118 << ", # sym: " << symAvail);
119
120 // Create vector of UE (without considering the beam)
121 std::vector<UePtrAndBufferReq> ueVector = GetUeVectorFromActiveUeMap(activeUe);
122
123 // Distribute the symbols following the selected behaviour among UEs
124 uint32_t resources = symAvail;
125 FTResources assigned(0, 0);
126
127 const std::vector<bool> notchedRBGsMask =
128 type == "DL" ? GetDlNotchedRbgMask() : GetUlNotchedRbgMask();
129 int zeroes = std::count(notchedRBGsMask.begin(), notchedRBGsMask.end(), 0);
130 uint32_t numOfAssignableRbgs = GetBandwidthInRbg() - zeroes;
131 NS_ASSERT(numOfAssignableRbgs > 0);
132
133 for (auto& ue : ueVector)
134 {
135 BeforeSchedFn(ue, FTResources(numOfAssignableRbgs, 1));
136 }
137
138 while (resources > 0)
139 {
141 {
142 callNotifyFn(ueVector);
143 }
144 GetFirst GetUe;
145
146 auto schedInfoIt = ueVector.begin();
147
148 std::stable_sort(ueVector.begin(), ueVector.end(), GetCompareFn());
149
150 // Ensure fairness: pass over UEs which already has enough resources to transmit
151 while (schedInfoIt != ueVector.end())
152 {
153 uint32_t bufQueueSize = schedInfoIt->second;
154
155 if (GetTBSFn(GetUe(*schedInfoIt)) >= std::max(bufQueueSize, 10U))
156 {
157 NS_LOG_INFO("UE " << GetUe(*schedInfoIt)->m_rnti << " TBS "
158 << GetTBSFn(GetUe(*schedInfoIt)) << " queue " << bufQueueSize
159 << ", passing");
160 schedInfoIt++;
161 }
162 else
163 {
164 break;
165 }
166 }
167
168 // In the case that all the UE already have their requirements fulfilled,
169 // then stop the assignment
170 if (schedInfoIt == ueVector.end())
171 {
172 NS_LOG_INFO("All the UE already have their resources allocated. Skipping the beam");
173 break;
174 }
175
176 // Assign 1 entire symbol (full RBG) to the selected UE and to the total
177 // resources assigned count
178 auto& assignedRbgs = GetRBGFn(GetUe(*schedInfoIt));
179 auto existingRbgs = assignedRbgs.size();
180 assignedRbgs.resize(assignedRbgs.size() + numOfAssignableRbgs);
181 std::iota(assignedRbgs.begin() + existingRbgs, assignedRbgs.end(), 0);
182 assigned.m_rbg += numOfAssignableRbgs;
183
184 auto& assignedSymbols = GetSymFn(GetUe(*schedInfoIt));
185 auto existingSymbols = assignedSymbols.size();
186 assignedSymbols.resize(assignedSymbols.size() + numOfAssignableRbgs);
187 std::fill(assignedSymbols.begin() + existingSymbols, assignedSymbols.end(), resources);
188 assigned.m_sym += 1;
189
190 // subtract 1 SYM from the number of sym available for the while loop
191 resources -= 1;
192
193 // Update metrics for the successful UE
194 NS_LOG_DEBUG("Assigned " << numOfAssignableRbgs << " " << type << " RBG (= 1 SYM) to UE "
195 << GetUe(*schedInfoIt)->m_rnti << " total assigned up to now: "
196 << GetRBGFn(GetUe(*schedInfoIt)).size() << " that corresponds to "
197 << assigned.m_rbg);
198 SuccessfulAssignmentFn(*schedInfoIt, FTResources(numOfAssignableRbgs, 1), assigned);
199
200 // Update metrics for the unsuccessful UEs (who did not get any resource in this iteration)
201 for (auto& ue : ueVector)
202 {
203 if (GetUe(ue)->m_rnti != GetUe(*schedInfoIt)->m_rnti)
204 {
205 UnSuccessfulAssignmentFn(ue, FTResources(numOfAssignableRbgs, 1), assigned);
206 }
207 }
208 }
209
210 // Count the number of assigned symbol of each beam.
212 for (const auto& el : activeUe)
213 {
214 uint32_t symOfBeam = 0;
215 for (const auto& ue : el.second)
216 {
217 symOfBeam += GetRBGFn(ue.first).size() / numOfAssignableRbgs;
218 }
219 ret.insert(std::make_pair(el.first, symOfBeam));
220 }
221 return ret;
222}
223
234NrMacSchedulerTdma::AssignDLRBG(uint32_t symAvail, const ActiveUeMap& activeDl) const
235{
236 NS_LOG_FUNCTION(this);
237
238 BeforeSchedFn beforeSched = std::bind(&NrMacSchedulerTdma::BeforeDlSched,
239 this,
240 std::placeholders::_1,
241 std::placeholders::_2);
242 AfterSuccessfulAssignmentFn SuccFn = std::bind(&NrMacSchedulerTdma::AssignedDlResources,
243 this,
244 std::placeholders::_1,
245 std::placeholders::_2,
246 std::placeholders::_3);
247 AfterUnsuccessfulAssignmentFn UnSuccFn = std::bind(&NrMacSchedulerTdma::NotAssignedDlResources,
248 this,
249 std::placeholders::_1,
250 std::placeholders::_2,
251 std::placeholders::_3);
252 GetCompareUeFn compareFn = std::bind(&NrMacSchedulerTdma::GetUeCompareDlFn, this);
253
254 GetTBSFn GetTbs = &NrMacSchedulerUeInfo::GetDlTBS;
255 GetRBGFn GetRBG = &NrMacSchedulerUeInfo::GetDlRBG;
256 GetSymFn GetSym = &NrMacSchedulerUeInfo::GetDlSym;
257
258 CallNotifyFn callNotifyFn =
259 std::bind(&NrMacSchedulerTdma::CallNotifyDlFn, this, std::placeholders::_1);
260
261 return AssignRBGTDMA(symAvail,
262 activeDl,
263 "DL",
264 beforeSched,
265 compareFn,
266 GetTbs,
267 GetRBG,
268 GetSym,
269 SuccFn,
270 UnSuccFn,
271 callNotifyFn);
272}
273
284NrMacSchedulerTdma::AssignULRBG(uint32_t symAvail, const ActiveUeMap& activeUl) const
285{
286 NS_LOG_FUNCTION(this);
287 BeforeSchedFn beforeSched = std::bind(&NrMacSchedulerTdma::BeforeUlSched,
288 this,
289 std::placeholders::_1,
290 std::placeholders::_2);
291 AfterSuccessfulAssignmentFn SuccFn = std::bind(&NrMacSchedulerTdma::AssignedUlResources,
292 this,
293 std::placeholders::_1,
294 std::placeholders::_2,
295 std::placeholders::_3);
296 GetCompareUeFn compareFn = std::bind(&NrMacSchedulerTdma::GetUeCompareUlFn, this);
297 AfterUnsuccessfulAssignmentFn UnSuccFn = std::bind(&NrMacSchedulerTdma::NotAssignedUlResources,
298 this,
299 std::placeholders::_1,
300 std::placeholders::_2,
301 std::placeholders::_3);
302 GetTBSFn GetTbs = &NrMacSchedulerUeInfo::GetUlTBS;
303 GetRBGFn GetRBG = &NrMacSchedulerUeInfo::GetUlRBG;
304 GetSymFn GetSym = &NrMacSchedulerUeInfo::GetUlSym;
305
306 CallNotifyFn callNotifyFn =
307 std::bind(&NrMacSchedulerTdma::CallNotifyUlFn, this, std::placeholders::_1);
308
309 return AssignRBGTDMA(symAvail,
310 activeUl,
311 "UL",
312 beforeSched,
313 compareFn,
314 GetTbs,
315 GetRBG,
316 GetSym,
317 SuccFn,
318 UnSuccFn,
319 callNotifyFn);
320}
321
332std::shared_ptr<DciInfoElementTdma>
334 const std::shared_ptr<NrMacSchedulerUeInfo>& ueInfo,
335 [[maybe_unused]] uint32_t maxSym) const
336{
337 NS_LOG_FUNCTION(this);
338 uint32_t tbs = m_dlAmc->CalculateTbSize(ueInfo->GetDlMcs(),
339 ueInfo->m_dlRank,
340 ueInfo->m_dlRBG.size() * GetNumRbPerRbg());
341 // If is less than 10 (3 mac header, 2 rlc header, 5 data), then we can't
342 // transmit any new data, so don't create dci.
343 if (tbs < 10)
344 {
345 NS_LOG_DEBUG("While creating DL DCI for UE " << ueInfo->m_rnti << " assigned "
346 << ueInfo->m_dlRBG.size()
347 << " DL RBG, but TBS < 10");
348 ueInfo->m_dlTbSize = 0;
349 return nullptr;
350 }
351
352 const std::vector<bool> notchedRBGsMask = GetDlNotchedRbgMask();
353 int zeroes = std::count(notchedRBGsMask.begin(), notchedRBGsMask.end(), 0);
354 uint32_t numOfAssignableRbgs = GetBandwidthInRbg() - zeroes;
355
356 uint8_t numSym = static_cast<uint8_t>(ueInfo->m_dlRBG.size() / numOfAssignableRbgs);
357
358 auto dci = CreateDci(spoint,
359 ueInfo,
360 tbs,
362 ueInfo->GetDlMcs(),
363 ueInfo->m_dlRank,
364 ueInfo->m_dlPrecMats,
365 std::max(numSym, static_cast<uint8_t>(1)));
366
367 // The starting point must advance.
368 spoint->m_rbg = 0;
369 spoint->m_sym += numSym;
370
371 return dci;
372}
373
385std::shared_ptr<DciInfoElementTdma>
387 const std::shared_ptr<NrMacSchedulerUeInfo>& ueInfo,
388 uint32_t maxSym) const
389{
390 NS_LOG_FUNCTION(this);
391 uint32_t tbs = m_ulAmc->CalculateTbSize(ueInfo->m_ulMcs,
392 ueInfo->m_ulRank,
393 ueInfo->m_ulRBG.size() * GetNumRbPerRbg());
394
395 // If is less than 12, 7 (3 mac header, 2 rlc header, 2 data) + SHORT_BSR (5),
396 // then we can't transmit any new data, so don't create dci.
397 if (tbs < 12)
398 {
399 NS_LOG_DEBUG("While creating UL DCI for UE " << ueInfo->m_rnti << " assigned "
400 << ueInfo->m_ulRBG.size()
401 << " UL RBG, but TBS " << tbs << " < 12");
402 return nullptr;
403 }
404
405 const std::vector<bool> notchedRBGsMask = GetUlNotchedRbgMask();
406 int zeroes = std::count(notchedRBGsMask.begin(), notchedRBGsMask.end(), 0);
407 uint32_t numOfAssignableRbgs = GetBandwidthInRbg() - zeroes;
408
409 uint8_t numSym =
410 static_cast<uint8_t>(std::max<size_t>(ueInfo->m_ulRBG.size() / numOfAssignableRbgs, 1));
411 numSym = std::min(numSym, static_cast<uint8_t>(maxSym));
412
413 NS_ASSERT(spoint->m_sym >= numSym);
414
415 // The starting point must go backward to accommodate the needed sym
416 spoint->m_sym -= numSym;
417
418 auto dci = CreateDci(spoint,
419 ueInfo,
420 tbs,
422 ueInfo->m_ulMcs,
423 ueInfo->m_ulRank,
424 ueInfo->m_ulPrecMats,
425 numSym);
426
427 // Reset the RBG (we are TDMA)
428 spoint->m_rbg = 0;
429
430 return dci;
431}
432
433uint8_t
435{
436 NS_LOG_FUNCTION(this);
437 return 1; // 1 is mapped to 0 for Accumulated mode, and to -1 in Absolute mode TS38.213 Table
438 // Table 7.1.1-1
439}
440
454std::shared_ptr<DciInfoElementTdma>
455NrMacSchedulerTdma::CreateDci(NrMacSchedulerNs3::PointInFTPlane* spoint,
456 const std::shared_ptr<NrMacSchedulerUeInfo>& ueInfo,
457 uint32_t tbs,
459 uint32_t mcs,
460 uint8_t rank,
461 Ptr<const ComplexMatrixArray> precMats,
462 uint8_t numSym) const
463{
464 NS_LOG_FUNCTION(this);
465 NS_ASSERT(tbs > 0);
466 NS_ASSERT(numSym > 0);
467
468 std::shared_ptr<DciInfoElementTdma> dci =
469 std::make_shared<DciInfoElementTdma>(ueInfo->m_rnti,
470 fmt,
471 spoint->m_sym,
472 numSym,
473 mcs,
474 rank,
475 precMats,
476 tbs,
477 1,
478 0,
480 GetBwpId(),
481 GetTpc());
482
483 std::vector<bool> rbgAssigned =
485
486 if (rbgAssigned.empty())
487 {
488 rbgAssigned = std::vector<bool>(GetBandwidthInRbg(), true);
489 }
490
491 NS_ASSERT(rbgAssigned.size() == GetBandwidthInRbg());
492
493 dci->m_rbgBitmask = std::move(rbgAssigned);
494
495 std::ostringstream oss;
496 for (auto x : dci->m_rbgBitmask)
497 {
498 oss << std::to_string(x) << " ";
499 }
500
501 NS_LOG_INFO("UE " << ueInfo->m_rnti << " assigned RBG from " << spoint->m_rbg << " with mask "
502 << oss.str() << " for " << static_cast<uint32_t>(numSym) << " SYM ");
503
504 NS_ASSERT(std::count(dci->m_rbgBitmask.begin(), dci->m_rbgBitmask.end(), 0) !=
506
507 return dci;
508}
509
510} // namespace ns3
A general scheduler for nr in NS3.
Ptr< NrAmc > m_ulAmc
AMC pointer.
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 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.
uint64_t GetNumRbPerRbg() const
Private function that is used to get the number of resource blocks per resource block group and also ...
PointInFTPlane FTResources
Represent an amount of RBG/symbols that can be, or is, assigned.
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.
std::shared_ptr< DciInfoElementTdma > CreateDlDci(PointInFTPlane *spoint, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t maxSym) const override
Create a DL DCI starting from spoint and spanning maxSym symbols.
NrMacSchedulerTdma()
NrMacSchedulerTdma constructor.
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.
BeamSymbolMap AssignDLRBG(uint32_t symAvail, const ActiveUeMap &activeDl) const override
Assign the available DL RBG to the UEs.
static TypeId GetTypeId()
GetTypeId.
virtual void NotAssignedUlResources(const UePtrAndBufferReq &ue, const FTResources &notAssigned, 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 &notAssigned, 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.
BeamSymbolMap AssignULRBG(uint32_t symAvail, const ActiveUeMap &activeUl) const override
Assign the available UL RBG to the UEs.
virtual void BeforeUlSched(const UePtrAndBufferReq &ue, const FTResources &assignableInIteration) const =0
Prepare UE for the UL scheduling.
~NrMacSchedulerTdma() override
NrMacSchedulerTdma deconstructor.
uint8_t GetTpc() const override
Returns TPC command.
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.
std::shared_ptr< DciInfoElementTdma > CreateUlDci(PointInFTPlane *spoint, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t maxSym) const override
Create a UL DCI starting from spoint and spanning maxSym symbols.
static uint32_t & GetUlTBS(const UePtr &ue)
GetUlTBS.
static std::vector< uint8_t > & GetUlSym(const UePtr &ue)
GetUlSym.
static std::vector< uint16_t > & GetUlRBG(const UePtr &ue)
GetUlRBG.
static std::vector< uint16_t > & GetDlRBG(const UePtr &ue)
GetDlRBG.
static std::vector< uint8_t > & GetDlSym(const UePtr &ue)
GetDlSym.
static uint32_t & GetDlTBS(const UePtr &ue)
GetDlTBS.
@ DATA
Used for DL/UL DATA.
DciFormat
Format of the DCI.
Point in the Frequency/Time plane.
uint32_t m_rbg
Represent the starting RBG.
uint8_t m_sym
Represent the starting symbol.