5G-LENA nr-v3.0-32-g83aee33
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-mac-scheduler-harq-rr.cc
1/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2
3// Copyright (c) 2019 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4//
5// SPDX-License-Identifier: GPL-2.0-only
6
7#define NS_LOG_APPEND_CONTEXT \
8 do \
9 { \
10 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
11 } while (false);
12#include "nr-mac-scheduler-harq-rr.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
59uint8_t
62 uint8_t symAvail,
63 const Ns3Sched::ActiveHarqMap& activeDlHarq,
64 const std::unordered_map<uint16_t, std::shared_ptr<NrMacSchedulerUeInfo>>& ueMap,
65 std::vector<DlHarqInfo>* dlHarqToRetransmit,
66 const std::vector<DlHarqInfo>& dlHarqFeedback,
67 SlotAllocInfo* slotAlloc) const
68{
69 NS_LOG_FUNCTION(this);
70 NS_ASSERT(startingPoint->m_rbg == 0);
71 uint8_t usedSym = 0;
72 uint8_t symPerBeam = symAvail / activeDlHarq.size();
73
74 NS_LOG_INFO("We have " << activeDlHarq.size() << " beams with data to RETX, each beam has "
75 << static_cast<uint32_t>(symPerBeam) << " symb");
76
77 for (const auto& beam : activeDlHarq)
78 {
79 std::vector<uint16_t> allocatedUe;
80 NS_LOG_INFO(" Try to assign HARQ resource for Beam sector: "
81 << static_cast<uint32_t>(beam.first.GetSector())
82 << " Beam theta: " << static_cast<uint32_t>(beam.first.GetElevation())
83 << " # HARQ to Retx=" << beam.second.size());
84
85 for (auto it : beam.second)
86 {
87 HarqProcess& harqProcess = it->second;
88 NS_ASSERT_MSG(harqProcess.m_status == HarqProcess::RECEIVED_FEEDBACK,
89 "Process " << static_cast<uint32_t>(it->first)
90 << " is not in RECEIVED_FEEDBACK status");
91
93 harqProcess.m_timer = 0;
94
95 auto& dciInfoReTx = harqProcess.m_dciElement;
96
97 uint32_t rbgAssigned =
98 std::count(dciInfoReTx->m_rbgBitmask.begin(), dciInfoReTx->m_rbgBitmask.end(), 1) *
99 dciInfoReTx->m_numSym;
100 uint32_t rbgAvail = (GetBandwidthInRbg() - startingPoint->m_rbg) * symPerBeam;
101
102 NS_LOG_INFO("Evaluating space to retransmit HARQ PID="
103 << static_cast<uint32_t>(dciInfoReTx->m_harqProcess) << " for UE="
104 << static_cast<uint32_t>(dciInfoReTx->m_rnti) << " SYM assigned previously="
105 << static_cast<uint32_t>(dciInfoReTx->m_numSym)
106 << " RBG assigned previously=" << static_cast<uint32_t>(rbgAssigned)
107 << " SYM avail for this beam=" << static_cast<uint32_t>(symPerBeam)
108 << " RBG avail for this beam=" << rbgAvail);
109
110 if (std::find(allocatedUe.begin(), allocatedUe.end(), dciInfoReTx->m_rnti) !=
111 allocatedUe.end())
112 {
113 NS_LOG_INFO("UE " << dciInfoReTx->m_rnti
114 << " already has an HARQ allocated, buffer this HARQ process"
115 << static_cast<uint32_t>(dciInfoReTx->m_harqProcess));
116 BufferHARQFeedback(dlHarqFeedback,
117 dlHarqToRetransmit,
118 dciInfoReTx->m_rnti,
119 dciInfoReTx->m_harqProcess);
120 continue;
121 }
122 else if (rbgAvail < rbgAssigned)
123 {
124 NS_LOG_INFO("No resource for this retx, we have to buffer it");
125 BufferHARQFeedback(dlHarqFeedback,
126 dlHarqToRetransmit,
127 dciInfoReTx->m_rnti,
128 dciInfoReTx->m_harqProcess);
129 continue;
130 }
131
132 allocatedUe.push_back(dciInfoReTx->m_rnti);
133
134 NS_ASSERT(dciInfoReTx->m_format == DciInfoElementTdma::DL);
135 auto dci = std::make_shared<DciInfoElementTdma>(dciInfoReTx->m_rnti,
136 dciInfoReTx->m_format,
137 startingPoint->m_sym,
138 symPerBeam,
139 dciInfoReTx->m_mcs,
140 dciInfoReTx->m_rank,
141 dciInfoReTx->m_precMats,
142 dciInfoReTx->m_tbSize,
143 0,
144 dciInfoReTx->m_rv + 1,
146 dciInfoReTx->m_bwpIndex,
147 dciInfoReTx->m_tpc);
148
149 dci->m_rbgBitmask = harqProcess.m_dciElement->m_rbgBitmask;
150 dci->m_harqProcess = dciInfoReTx->m_harqProcess;
151
152 harqProcess.m_dciElement = dci;
153 dciInfoReTx = harqProcess.m_dciElement;
154
155 if (rbgAssigned % dciInfoReTx->m_numSym == 0)
156 {
157 rbgAssigned = rbgAssigned / dciInfoReTx->m_numSym;
158 }
159 else
160 {
161 rbgAssigned = rbgAssigned / dciInfoReTx->m_numSym;
162 ++rbgAssigned;
163 }
164
165 NS_ABORT_IF(static_cast<unsigned long>(rbgAssigned) > dciInfoReTx->m_rbgBitmask.size());
166
167 for (unsigned int i = 0; i < dciInfoReTx->m_rbgBitmask.size(); ++i)
168 {
169 if (startingPoint->m_rbg <= i && i < startingPoint->m_rbg + rbgAssigned)
170 {
171 dciInfoReTx->m_rbgBitmask.at(i) = 1;
172 }
173 else
174 {
175 dciInfoReTx->m_rbgBitmask.at(i) = 0;
176 }
177 }
178
179 startingPoint->m_rbg += rbgAssigned;
180
181 VarTtiAllocInfo slotInfo(dciInfoReTx);
182 NS_LOG_DEBUG(
183 "UE" << dciInfoReTx->m_rnti << " gets DL symbols "
184 << static_cast<uint32_t>(dciInfoReTx->m_symStart) << "-"
185 << static_cast<uint32_t>(dciInfoReTx->m_symStart + dciInfoReTx->m_numSym - 1)
186 << " tbs " << dciInfoReTx->m_tbSize << " harqId "
187 << static_cast<uint32_t>(dciInfoReTx->m_harqProcess) << " rv "
188 << static_cast<uint32_t>(dciInfoReTx->m_rv)
189 << " RBG start: " << static_cast<uint32_t>(startingPoint->m_rbg - rbgAssigned)
190 << " RBG end: " << static_cast<uint32_t>(startingPoint->m_rbg) << " RETX");
191 for (const auto& rlcPdu : harqProcess.m_rlcPduInfo)
192 {
193 slotInfo.m_rlcPduInfo.push_back(rlcPdu);
194 }
195 slotAlloc->m_varTtiAllocInfo.push_back(slotInfo);
196
197 ueMap.find(dciInfoReTx->m_rnti)->second->m_dlMRBRetx =
198 dciInfoReTx->m_numSym * rbgAssigned;
199 }
200
201 if (!allocatedUe.empty())
202 {
203 startingPoint->m_sym += symPerBeam;
204 startingPoint->m_rbg = 0;
205 usedSym += symPerBeam;
206 slotAlloc->m_numSymAlloc += symPerBeam;
207 symAvail -= symPerBeam;
208 }
209 }
210 NS_ASSERT(startingPoint->m_rbg == 0);
211 return usedSym;
212}
213
231uint8_t
234 uint8_t symAvail,
235 const std::unordered_map<uint16_t, std::shared_ptr<NrMacSchedulerUeInfo>>& ueMap,
236 std::vector<UlHarqInfo>* ulHarqToRetransmit,
237 const std::vector<UlHarqInfo>& ulHarqFeedback,
238 SlotAllocInfo* slotAlloc) const
239{
240 NS_LOG_FUNCTION(this);
241 uint8_t symUsed = 0;
242 NS_ASSERT(startingPoint->m_rbg == 0);
243
244 NS_LOG_INFO("Scheduling UL HARQ starting from sym "
245 << +startingPoint->m_sym << " and RBG " << startingPoint->m_rbg
246 << ". Available symbols: " << symAvail
247 << " number of feedback: " << ulHarqFeedback.size());
248
249 for (uint16_t i = 0; i < ulHarqFeedback.size() && symAvail > 0; i++)
250 {
251 UlHarqInfo harqInfo = ulHarqFeedback.at(i);
252 uint8_t harqId = harqInfo.m_harqProcessId;
253 uint16_t rnti = harqInfo.m_rnti;
254
255 NS_ABORT_IF(harqInfo.IsReceivedOk());
256
257 // retx correspondent block: retrieve the UL-DCI
258 HarqProcess& harqProcess = ueMap.find(rnti)->second->m_ulHarq.Find(harqId)->second;
259 NS_ASSERT(harqProcess.m_status == HarqProcess::RECEIVED_FEEDBACK);
260
262 harqProcess.m_timer = 0;
263 auto& dciInfoReTx = harqProcess.m_dciElement;
264
265 NS_LOG_INFO("Feedback is for UE " << rnti << " process " << +harqId
266 << " sym: " << +dciInfoReTx->m_numSym);
267
268 if (symAvail >= dciInfoReTx->m_numSym)
269 {
270 symAvail -= dciInfoReTx->m_numSym;
271 symUsed += dciInfoReTx->m_numSym;
272
273 NS_ASSERT(dciInfoReTx->m_format == DciInfoElementTdma::UL);
274
275 auto dci =
276 std::make_shared<DciInfoElementTdma>(dciInfoReTx->m_rnti,
277 dciInfoReTx->m_format,
278 startingPoint->m_sym - dciInfoReTx->m_numSym,
279 dciInfoReTx->m_numSym,
280 dciInfoReTx->m_mcs,
281 dciInfoReTx->m_rank,
282 dciInfoReTx->m_precMats,
283 dciInfoReTx->m_tbSize,
284 0,
285 dciInfoReTx->m_rv + 1,
287 dciInfoReTx->m_bwpIndex,
288 dciInfoReTx->m_tpc);
289 dci->m_rbgBitmask = harqProcess.m_dciElement->m_rbgBitmask;
290 dci->m_harqProcess = harqId;
291 harqProcess.m_dciElement = dci;
292 dciInfoReTx = harqProcess.m_dciElement;
293
294 startingPoint->m_sym -= dciInfoReTx->m_numSym;
295
296 VarTtiAllocInfo slotInfo(dciInfoReTx);
297 NS_LOG_DEBUG(
298 "UE" << dciInfoReTx->m_rnti << " gets UL symbols "
299 << static_cast<uint32_t>(dciInfoReTx->m_symStart) << "-"
300 << static_cast<uint32_t>(dciInfoReTx->m_symStart + dciInfoReTx->m_numSym - 1)
301 << " tbs " << dciInfoReTx->m_tbSize << " harqId "
302 << static_cast<uint32_t>(dciInfoReTx->m_harqProcess) << " rv "
303 << static_cast<uint32_t>(dciInfoReTx->m_rv) << " RETX");
304 slotAlloc->m_varTtiAllocInfo.push_front(slotInfo);
305 slotAlloc->m_numSymAlloc += dciInfoReTx->m_numSym;
306
307 ueMap.find(rnti)->second->m_ulMRBRetx = dciInfoReTx->m_numSym * GetBandwidthInRbg();
308 }
309 else
310 {
311 ulHarqToRetransmit->push_back(ulHarqFeedback.at(i));
312 }
313 }
314
315 NS_ASSERT(startingPoint->m_rbg == 0);
316
317 return symUsed;
318}
319
324void
326{
327 NS_LOG_FUNCTION(this);
328
329 // Order based on required sym
330 static struct
331 {
332 bool operator()(const NrMacSchedulerNs3::HarqVectorIterator& a,
333 const NrMacSchedulerNs3::HarqVectorIterator& b) const
334 {
335 return a->second.m_dciElement->m_numSym > b->second.m_dciElement->m_numSym;
336 }
337 } CompareNumSym;
338
339 for (auto& it : *activeDlHarq)
340 {
341 std::sort(it.second.begin(), it.second.end(), CompareNumSym);
342 }
343}
344
354void
356 [[maybe_unused]] NrMacSchedulerNs3::ActiveHarqMap* activeUlHarq) const
357{
358 NS_LOG_FUNCTION(this);
359}
360
368void
369NrMacSchedulerHarqRr::BufferHARQFeedback(const std::vector<DlHarqInfo>& dlHarqFeedback,
370 std::vector<DlHarqInfo>* dlHarqToRetransmit,
371 uint16_t rnti,
372 uint8_t harqProcess) const
373{
374 NS_LOG_FUNCTION(this);
375
376 bool found = false;
377 for (const auto& feedback : dlHarqFeedback)
378 {
379 if (feedback.m_rnti == rnti && feedback.m_harqProcessId == harqProcess)
380 {
381 dlHarqToRetransmit->push_back(feedback);
382 found = true;
383 break;
384 }
385 }
386 NS_ASSERT(found);
387}
388
389uint16_t
391{
392 return m_getBwpId();
393}
394
395uint16_t
397{
398 return m_getCellId();
399}
400
401uint16_t
403{
404 return m_getBwInRbg();
405}
406
407} // namespace ns3
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.
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.
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