5G-LENA nr-v3.3-81-g75c7590d
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-mac-scheduler-harq-rr.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#include "nr-mac-scheduler-harq-rr.h"
11
12#include "nr-fh-control.h"
13
14#include <ns3/log.h>
15
16#include <algorithm>
17
18namespace ns3
19{
20
21NS_LOG_COMPONENT_DEFINE("NrMacSchedulerHarqRr");
22
26
27void
28NrMacSchedulerHarqRr::InstallGetBwpIdFn(const std::function<uint16_t()>& fn)
29{
30 m_getBwpId = fn;
31}
32
33void
34NrMacSchedulerHarqRr::InstallGetCellIdFn(const std::function<uint16_t()>& fn)
35{
36 m_getCellId = fn;
37}
38
39void
40NrMacSchedulerHarqRr::InstallGetBwInRBG(const std::function<uint16_t()>& fn)
41{
42 m_getBwInRbg = fn;
43}
44
45void
46NrMacSchedulerHarqRr::InstallGetFhControlMethodFn(const std::function<uint8_t()>& fn)
47{
48 m_getFhControlMethod = fn;
49}
50
51void
53 const std::function<bool(uint16_t bwpId, uint32_t mcs, uint32_t nRegs, uint8_t dlRank)>& fn)
54{
55 m_getDoesAllocationFit = fn;
56}
57
72uint8_t
75 uint8_t symAvail,
76 const Ns3Sched::ActiveHarqMap& activeDlHarq,
77 const std::unordered_map<uint16_t, std::shared_ptr<NrMacSchedulerUeInfo>>& ueMap,
78 std::vector<DlHarqInfo>* dlHarqToRetransmit,
79 const std::vector<DlHarqInfo>& dlHarqFeedback,
80 SlotAllocInfo* slotAlloc) const
81{
82 NS_LOG_FUNCTION(this);
83 NS_ASSERT(startingPoint->m_rbg == 0);
84 uint8_t usedSym = 0;
85 uint8_t symPerBeam = symAvail / activeDlHarq.size();
86
87 NS_LOG_INFO("We have " << activeDlHarq.size() << " beams with data to RETX, each beam has "
88 << static_cast<uint32_t>(symPerBeam) << " symb");
89
90 for (const auto& beam : activeDlHarq)
91 {
92 std::vector<uint16_t> allocatedUe;
93 NS_LOG_INFO(" Try to assign HARQ resource for Beam sector: "
94 << static_cast<uint32_t>(beam.first.GetSector())
95 << " Beam theta: " << static_cast<uint32_t>(beam.first.GetElevation())
96 << " # HARQ to Retx=" << beam.second.size());
97
98 for (auto it : beam.second)
99 {
100 HarqProcess& harqProcess = it->second;
101 NS_ASSERT_MSG(harqProcess.m_status == HarqProcess::RECEIVED_FEEDBACK,
102 "Process " << static_cast<uint32_t>(it->first)
103 << " is not in RECEIVED_FEEDBACK status");
104
106 harqProcess.m_timer = 0;
107
108 auto& dciInfoReTx = harqProcess.m_dciElement;
109
110 uint32_t rbgAssigned =
111 std::count(dciInfoReTx->m_rbgBitmask.begin(), dciInfoReTx->m_rbgBitmask.end(), 1) *
112 dciInfoReTx->m_numSym;
113 uint32_t rbgAvail = (GetBandwidthInRbg() - startingPoint->m_rbg) * symPerBeam;
114
115 NS_LOG_INFO("Evaluating space to retransmit HARQ PID="
116 << static_cast<uint32_t>(dciInfoReTx->m_harqProcess) << " for UE="
117 << static_cast<uint32_t>(dciInfoReTx->m_rnti) << " SYM assigned previously="
118 << static_cast<uint32_t>(dciInfoReTx->m_numSym)
119 << " RBG assigned previously=" << static_cast<uint32_t>(rbgAssigned)
120 << " SYM avail for this beam=" << static_cast<uint32_t>(symPerBeam)
121 << " RBG avail for this beam=" << rbgAvail);
122
123 if (std::find(allocatedUe.begin(), allocatedUe.end(), dciInfoReTx->m_rnti) !=
124 allocatedUe.end())
125 {
126 NS_LOG_INFO("UE " << dciInfoReTx->m_rnti
127 << " already has an HARQ allocated, buffer this HARQ process"
128 << static_cast<uint32_t>(dciInfoReTx->m_harqProcess));
129 BufferHARQFeedback(dlHarqFeedback,
130 dlHarqToRetransmit,
131 dciInfoReTx->m_rnti,
132 dciInfoReTx->m_harqProcess);
133 continue;
134 }
135 else if (rbgAvail < rbgAssigned)
136 {
137 NS_LOG_INFO("No resource for this retx, we have to buffer it");
138 BufferHARQFeedback(dlHarqFeedback,
139 dlHarqToRetransmit,
140 dciInfoReTx->m_rnti,
141 dciInfoReTx->m_harqProcess);
142 continue;
143 }
147 {
149 dciInfoReTx->m_mcs,
150 rbgAssigned,
151 dciInfoReTx->m_rank) == 0)
152 {
153 NS_LOG_INFO("No FH resources for this retx, we have to buffer it");
154 BufferHARQFeedback(dlHarqFeedback,
155 dlHarqToRetransmit,
156 dciInfoReTx->m_rnti,
157 dciInfoReTx->m_harqProcess);
158 continue;
159 }
160 }
161
162 allocatedUe.push_back(dciInfoReTx->m_rnti);
163
164 NS_ASSERT(dciInfoReTx->m_format == DciInfoElementTdma::DL);
165 auto dci = std::make_shared<DciInfoElementTdma>(dciInfoReTx->m_rnti,
166 dciInfoReTx->m_format,
167 startingPoint->m_sym,
168 symPerBeam,
169 dciInfoReTx->m_mcs,
170 dciInfoReTx->m_rank,
171 dciInfoReTx->m_precMats,
172 dciInfoReTx->m_tbSize,
173 0,
174 dciInfoReTx->m_rv + 1,
176 dciInfoReTx->m_bwpIndex,
177 dciInfoReTx->m_tpc);
178
179 dci->m_rbgBitmask = harqProcess.m_dciElement->m_rbgBitmask;
180 dci->m_harqProcess = dciInfoReTx->m_harqProcess;
181
182 harqProcess.m_dciElement = dci;
183 dciInfoReTx = harqProcess.m_dciElement;
184
185 if (rbgAssigned % dciInfoReTx->m_numSym == 0)
186 {
187 rbgAssigned = rbgAssigned / dciInfoReTx->m_numSym;
188 }
189 else
190 {
191 rbgAssigned = rbgAssigned / dciInfoReTx->m_numSym;
192 ++rbgAssigned;
193 }
194
195 NS_ABORT_IF(static_cast<unsigned long>(rbgAssigned) > dciInfoReTx->m_rbgBitmask.size());
196
197 for (unsigned int i = 0; i < dciInfoReTx->m_rbgBitmask.size(); ++i)
198 {
199 if (startingPoint->m_rbg <= i && i < startingPoint->m_rbg + rbgAssigned)
200 {
201 dciInfoReTx->m_rbgBitmask.at(i) = true;
202 }
203 else
204 {
205 dciInfoReTx->m_rbgBitmask.at(i) = false;
206 }
207 }
208
209 startingPoint->m_rbg += rbgAssigned;
210
211 VarTtiAllocInfo slotInfo(dciInfoReTx);
212 NS_LOG_DEBUG(
213 "UE" << dciInfoReTx->m_rnti << " gets DL symbols "
214 << static_cast<uint32_t>(dciInfoReTx->m_symStart) << "-"
215 << static_cast<uint32_t>(dciInfoReTx->m_symStart + dciInfoReTx->m_numSym - 1)
216 << " tbs " << dciInfoReTx->m_tbSize << " harqId "
217 << static_cast<uint32_t>(dciInfoReTx->m_harqProcess) << " rv "
218 << static_cast<uint32_t>(dciInfoReTx->m_rv)
219 << " RBG start: " << static_cast<uint32_t>(startingPoint->m_rbg - rbgAssigned)
220 << " RBG end: " << static_cast<uint32_t>(startingPoint->m_rbg) << " RETX");
221 for (const auto& rlcPdu : harqProcess.m_rlcPduInfo)
222 {
223 slotInfo.m_rlcPduInfo.push_back(rlcPdu);
224 }
225 slotAlloc->m_varTtiAllocInfo.push_back(slotInfo);
226
227 ueMap.find(dciInfoReTx->m_rnti)->second->m_dlMRBRetx =
228 dciInfoReTx->m_numSym * rbgAssigned;
229 }
230
231 if (!allocatedUe.empty())
232 {
233 startingPoint->m_sym += symPerBeam;
234 startingPoint->m_rbg = 0;
235 usedSym += symPerBeam;
236 slotAlloc->m_numSymAlloc += symPerBeam;
237 symAvail -= symPerBeam;
238 }
239 }
240 NS_ASSERT(startingPoint->m_rbg == 0);
241 return usedSym;
242}
243
261uint8_t
264 uint8_t symAvail,
265 const std::unordered_map<uint16_t, std::shared_ptr<NrMacSchedulerUeInfo>>& ueMap,
266 std::vector<UlHarqInfo>* ulHarqToRetransmit,
267 const std::vector<UlHarqInfo>& ulHarqFeedback,
268 SlotAllocInfo* slotAlloc) const
269{
270 NS_LOG_FUNCTION(this);
271 uint8_t symUsed = 0;
272 NS_ASSERT(startingPoint->m_rbg == 0);
273
274 NS_LOG_INFO("Scheduling UL HARQ starting from sym "
275 << +startingPoint->m_sym << " and RBG " << startingPoint->m_rbg
276 << ". Available symbols: " << symAvail
277 << " number of feedback: " << ulHarqFeedback.size());
278
279 for (uint16_t i = 0; i < ulHarqFeedback.size() && symAvail > 0; i++)
280 {
281 UlHarqInfo harqInfo = ulHarqFeedback.at(i);
282 uint8_t harqId = harqInfo.m_harqProcessId;
283 uint16_t rnti = harqInfo.m_rnti;
284
285 NS_ABORT_IF(harqInfo.IsReceivedOk());
286
287 // retx correspondent block: retrieve the UL-DCI
288 HarqProcess& harqProcess = ueMap.find(rnti)->second->m_ulHarq.Find(harqId)->second;
289 NS_ASSERT(harqProcess.m_status == HarqProcess::RECEIVED_FEEDBACK);
290
292 harqProcess.m_timer = 0;
293 auto& dciInfoReTx = harqProcess.m_dciElement;
294
295 NS_LOG_INFO("Feedback is for UE " << rnti << " process " << +harqId
296 << " sym: " << +dciInfoReTx->m_numSym);
297
298 if (symAvail >= dciInfoReTx->m_numSym)
299 {
300 symAvail -= dciInfoReTx->m_numSym;
301 symUsed += dciInfoReTx->m_numSym;
302
303 NS_ASSERT(dciInfoReTx->m_format == DciInfoElementTdma::UL);
304
305 auto dci =
306 std::make_shared<DciInfoElementTdma>(dciInfoReTx->m_rnti,
307 dciInfoReTx->m_format,
308 startingPoint->m_sym - dciInfoReTx->m_numSym,
309 dciInfoReTx->m_numSym,
310 dciInfoReTx->m_mcs,
311 dciInfoReTx->m_rank,
312 dciInfoReTx->m_precMats,
313 dciInfoReTx->m_tbSize,
314 0,
315 dciInfoReTx->m_rv + 1,
317 dciInfoReTx->m_bwpIndex,
318 dciInfoReTx->m_tpc);
319 dci->m_rbgBitmask = harqProcess.m_dciElement->m_rbgBitmask;
320 dci->m_harqProcess = harqId;
321 harqProcess.m_dciElement = dci;
322 dciInfoReTx = harqProcess.m_dciElement;
323
324 startingPoint->m_sym -= dciInfoReTx->m_numSym;
325
326 VarTtiAllocInfo slotInfo(dciInfoReTx);
327 NS_LOG_DEBUG(
328 "UE" << dciInfoReTx->m_rnti << " gets UL symbols "
329 << static_cast<uint32_t>(dciInfoReTx->m_symStart) << "-"
330 << static_cast<uint32_t>(dciInfoReTx->m_symStart + dciInfoReTx->m_numSym - 1)
331 << " tbs " << dciInfoReTx->m_tbSize << " harqId "
332 << static_cast<uint32_t>(dciInfoReTx->m_harqProcess) << " rv "
333 << static_cast<uint32_t>(dciInfoReTx->m_rv) << " RETX");
334 slotAlloc->m_varTtiAllocInfo.push_front(slotInfo);
335 slotAlloc->m_numSymAlloc += dciInfoReTx->m_numSym;
336
337 ueMap.find(rnti)->second->m_ulMRBRetx = dciInfoReTx->m_numSym * GetBandwidthInRbg();
338 }
339 else
340 {
341 ulHarqToRetransmit->push_back(ulHarqFeedback.at(i));
342 }
343 }
344
345 NS_ASSERT(startingPoint->m_rbg == 0);
346
347 return symUsed;
348}
349
354void
356{
357 NS_LOG_FUNCTION(this);
358
359 // Order based on required sym
360 static struct
361 {
362 bool operator()(const NrMacSchedulerNs3::HarqVectorIterator& a,
363 const NrMacSchedulerNs3::HarqVectorIterator& b) const
364 {
365 return a->second.m_dciElement->m_numSym > b->second.m_dciElement->m_numSym;
366 }
367 } CompareNumSym;
368
369 for (auto& it : *activeDlHarq)
370 {
371 std::stable_sort(it.second.begin(), it.second.end(), CompareNumSym);
372 }
373}
374
384void
386 [[maybe_unused]] NrMacSchedulerNs3::ActiveHarqMap* activeUlHarq) const
387{
388 NS_LOG_FUNCTION(this);
389}
390
398void
399NrMacSchedulerHarqRr::BufferHARQFeedback(const std::vector<DlHarqInfo>& dlHarqFeedback,
400 std::vector<DlHarqInfo>* dlHarqToRetransmit,
401 uint16_t rnti,
402 uint8_t harqProcess) const
403{
404 NS_LOG_FUNCTION(this);
405
406 bool found = false;
407 for (const auto& feedback : dlHarqFeedback)
408 {
409 if (feedback.m_rnti == rnti && feedback.m_harqProcessId == harqProcess)
410 {
411 dlHarqToRetransmit->push_back(feedback);
412 found = true;
413 break;
414 }
415 }
416 NS_ASSERT(found);
417}
418
419uint16_t
421{
422 return m_getBwpId();
423}
424
425uint16_t
427{
428 return m_getCellId();
429}
430
431uint16_t
433{
434 return m_getBwInRbg();
435}
436
437uint8_t
439{
440 return m_getFhControlMethod();
441}
442
443bool
445 uint32_t mcs,
446 uint32_t nRegs,
447 uint8_t dlRank) const
448{
449 return m_getDoesAllocationFit(bwpId, mcs, nRegs, dlRank);
450}
451
452} // namespace ns3
@ Postponing
Postpone sending data (MAC Layer)
@ OptimizeRBs
Optimize RBs allocated.
@ OptimizeMcs
Optimize MCS.
virtual uint8_t ScheduleUlHarq(NrMacSchedulerNs3::PointInFTPlane *startingPoint, uint8_t symAvail, const std::unordered_map< uint16_t, std::shared_ptr< NrMacSchedulerUeInfo > > &ueMap, std::vector< UlHarqInfo > *ulHarqToRetransmit, const std::vector< UlHarqInfo > &ulHarqFeedback, SlotAllocInfo *slotAlloc) const
Schedule the UL HARQ.
uint16_t GetBwpId() const
Get the bwp id of this MAC.
uint16_t GetCellId() const
Get the cell id of this MAC.
void InstallGetBwpIdFn(const std::function< uint16_t()> &fn)
Install a function to retrieve the bwp id.
void InstallDoesFhAllocationFitFn(const std::function< bool(uint16_t bwpId, uint32_t mcs, uint32_t nRegs, uint8_t dlRank)> &fn)
Install a function to retrieve whether the allocation fits when FH Control is enabled.
virtual void SortDlHarq(NrMacSchedulerNs3::ActiveHarqMap *activeDlHarq) const
Sort Dl Harq retx based on their symbol requirement.
uint16_t GetBandwidthInRbg() const
Get the bandwidth in RBG.
NrMacSchedulerHarqRr()
NrMacSchedulerHarqRr constructor.
void BufferHARQFeedback(const std::vector< DlHarqInfo > &dlHarqFeedback, std::vector< DlHarqInfo > *dlHarqToRetransmit, uint16_t rnti, uint8_t harqProcess) const
Find the specified HARQ process and buffer it into a vector.
void InstallGetCellIdFn(const std::function< uint16_t()> &fn)
Install a function to retrieve the cell id.
bool GetDoesFhAllocationFit(uint16_t bwpId, uint32_t mcs, uint32_t nRegs, uint8_t dlRank) const
Get from sched if the allocation fits when FH Control is enabled.
void InstallGetFhControlMethodFn(const std::function< uint8_t()> &fn)
Install a function to retrieve the FH Control Method (when enabled)
uint8_t GetFromSchedFhControlMethod() const
Get the FH Control method.
virtual void SortUlHarq(NrMacSchedulerNs3::ActiveHarqMap *activeUlHarq) const
(In theory) sort UL HARQ retx
void InstallGetBwInRBG(const std::function< uint16_t()> &fn)
Install a function to retrieve the bandwidth in RBG.
virtual uint8_t ScheduleDlHarq(NrMacSchedulerNs3::PointInFTPlane *startingPoint, uint8_t symAvail, const NrMacSchedulerNs3::ActiveHarqMap &activeDlHarq, const std::unordered_map< uint16_t, std::shared_ptr< NrMacSchedulerUeInfo > > &ueMap, std::vector< DlHarqInfo > *dlHarqToRetransmit, const std::vector< DlHarqInfo > &dlHarqFeedback, SlotAllocInfo *slotAlloc) const
Schedule DL HARQ in RR fashion.
std::unordered_map< BeamId, HarqVectorIteratorList, BeamIdHash > ActiveHarqMap
Map between a beamID and the HARQ of that beam.
@ DATA
Used for DL/UL DATA.
uint8_t m_harqProcessId
ProcessId.
uint16_t m_rnti
RNTI.
The HarqProcess struct.
Status m_status
Status of the process.
std::vector< RlcPduInfo > m_rlcPduInfo
vector of RLC PDU
uint8_t m_timer
Timer of the process (in slot)
@ RECEIVED_FEEDBACK
Received feedback (NACK)
@ WAITING_FEEDBACK
Data transmitted, waiting the feedback.
std::shared_ptr< DciInfoElementTdma > m_dciElement
DCI element.
Point in the Frequency/Time plane.
uint32_t m_rbg
Represent the starting RBG.
uint8_t m_sym
Represent the starting symbol.
The SlotAllocInfo struct.
uint32_t m_numSymAlloc
Number of allocated symbols.
std::deque< VarTtiAllocInfo > m_varTtiAllocInfo
queue of allocations
A struct that contains info for the UL HARQ.
bool IsReceivedOk() const override