@@ -34,6 +34,9 @@ ue_srb0_scheduler::ue_srb0_scheduler(const scheduler_ue_expert_config& expert_cf
3434 cs_cfg(cell_cfg.get_common_coreset(ss_cfg.get_coreset_id())),
3535 logger(srslog::fetch_basic_logger(" SCHED" ))
3636{
37+ // NOTE: We use a std::vector instead of a std::array because we can later on initialize the vector with the minimum
38+ // value of k1, passed through the expert config.
39+ dci_1_0_k1_values = {4 , 5 , 6 , 7 , 8 };
3740}
3841
3942void ue_srb0_scheduler::run_slot (cell_resource_allocator& res_alloc)
@@ -58,12 +61,12 @@ void ue_srb0_scheduler::run_slot(cell_resource_allocator& res_alloc)
5861 auto * h_dl = next_ue_harq_retx->get_harq_process ();
5962
6063 if (h_dl->has_pending_retx ()) {
61- optional<slot_point> most_recent_tx = get_most_recent_slot_tx (u.ue_index );
64+ optional<std::pair< slot_point, slot_point>> most_recent_tx_ack = get_most_recent_slot_tx (u.ue_index );
6265 if (next_ue_harq_retx->is_srb0 ) {
63- schedule_srb (res_alloc, u, true , h_dl, most_recent_tx );
66+ schedule_srb (res_alloc, u, next_ue_harq_retx-> is_srb0 , h_dl, most_recent_tx_ack );
6467 } else {
6568 // TODO: Change this into SRB1_retx.
66- schedule_srb (res_alloc, u, true , h_dl, most_recent_tx );
69+ schedule_srb (res_alloc, u, next_ue_harq_retx-> is_srb0 , h_dl, most_recent_tx_ack );
6770 }
6871 }
6972 ++next_ue_harq_retx;
@@ -83,9 +86,9 @@ void ue_srb0_scheduler::run_slot(cell_resource_allocator& res_alloc)
8386 continue ;
8487 }
8588
86- auto & u = ues[next_ue->ue_index ];
87- optional<slot_point> most_recent_tx = get_most_recent_slot_tx (u.ue_index );
88- if (u.has_pending_dl_newtx_bytes (LCID_SRB0) and schedule_srb (res_alloc, u, true , nullptr , most_recent_tx )) {
89+ auto & u = ues[next_ue->ue_index ];
90+ optional<std::pair< slot_point, slot_point>> most_recent_tx_ack = get_most_recent_slot_tx (u.ue_index );
91+ if (u.has_pending_dl_newtx_bytes (LCID_SRB0) and schedule_srb (res_alloc, u, true , nullptr , most_recent_tx_ack )) {
8992 next_ue = pending_ues.erase (next_ue);
9093 } else {
9194 ++next_ue;
@@ -106,10 +109,18 @@ void ue_srb0_scheduler::run_slot(cell_resource_allocator& res_alloc)
106109 continue ;
107110 }
108111
109- auto & u = ues[next_ue->ue_index ];
110- optional<slot_point> most_recent_tx = get_most_recent_slot_tx (u.ue_index );
111- if (u.has_pending_dl_newtx_bytes (LCID_SRB1) and schedule_srb (res_alloc, u, false , nullptr , most_recent_tx)) {
112- next_ue = pending_ues.erase (next_ue);
112+ auto & u = ues[next_ue->ue_index ];
113+ optional<std::pair<slot_point, slot_point>> most_recent_tx_ack = get_most_recent_slot_tx (u.ue_index );
114+ if (u.has_pending_dl_newtx_bytes (LCID_SRB1) and schedule_srb (res_alloc, u, false , nullptr , most_recent_tx_ack)) {
115+ if (not u.has_pending_dl_newtx_bytes (LCID_SRB1)) {
116+ logger.debug (" rnti={}: Removing UE from list, as SRB1 buffer is empty." , u.crnti );
117+ next_ue = pending_ues.erase (next_ue);
118+ }
119+ // Don't increase the iterator here, as we give priority to the same UE if there left are bytes in the SRB1
120+ // buffer.
121+ // NOTE: The policy we adopt in this scheduler is to schedule first the all possible grants to a given UE,
122+ // to speed up the re-establishment and re-configuration for that UE. Only after the SRB1 buffer of the UE is
123+ // emptied, we move on to the next UE.
113124 } else {
114125 ++next_ue;
115126 }
@@ -137,11 +148,11 @@ static slot_point get_next_srb_slot(const cell_configuration& cell_cfg, slot_poi
137148 return next_candidate_slot;
138149}
139150
140- bool ue_srb0_scheduler::schedule_srb (cell_resource_allocator& res_alloc,
141- ue& u,
142- bool is_srb0,
143- dl_harq_process* h_dl_retx,
144- optional<slot_point> starting_sl )
151+ bool ue_srb0_scheduler::schedule_srb (cell_resource_allocator& res_alloc,
152+ ue& u,
153+ bool is_srb0,
154+ dl_harq_process* h_dl_retx,
155+ optional<std::pair< slot_point, slot_point>> most_recent_tx_ack_slots )
145156{
146157 const auto & bwp_cfg_common = cell_cfg.dl_cfg_common .init_dl_bwp ;
147158 // Search valid PDSCH time domain resource.
@@ -160,14 +171,17 @@ bool ue_srb0_scheduler::schedule_srb(cell_resource_allocator& res_alloc,
160171 return false ;
161172 }
162173
163- if (starting_sl.has_value () and sched_ref_slot + max_dl_slots_ahead_sched < starting_sl.value ()) {
174+ if (most_recent_tx_ack_slots.has_value () and
175+ sched_ref_slot + max_dl_slots_ahead_sched < most_recent_tx_ack_slots.value ().first ) {
164176 return false ;
165177 }
166- starting_sl = sched_ref_slot;
167178
168179 // We keep track of the number of scheduling attempts for the given UE.
169180 unsigned sched_attempts_cnt = 0 ;
170- slot_point next_slot = starting_sl.value ();
181+ slot_point next_slot =
182+ most_recent_tx_ack_slots.has_value () and most_recent_tx_ack_slots.value ().first > sched_ref_slot
183+ ? most_recent_tx_ack_slots.value ().first
184+ : sched_ref_slot;
171185
172186 while (next_slot <= sched_ref_slot + max_dl_slots_ahead_sched) {
173187 unsigned offset_to_sched_ref_slot = static_cast <unsigned >(next_slot - sched_ref_slot);
@@ -215,15 +229,26 @@ bool ue_srb0_scheduler::schedule_srb(cell_resource_allocator& res_alloc,
215229 return false ;
216230 }
217231
232+ slot_point most_recent_ack_slot = pdsch_alloc.slot ;
233+ if (most_recent_tx_ack_slots.has_value ()) {
234+ if (pdsch_alloc.slot + dci_1_0_k1_values.back () <= most_recent_tx_ack_slots.value ().second ) {
235+ continue ;
236+ }
237+ most_recent_ack_slot = most_recent_tx_ack_slots.value ().second ;
238+ }
239+
218240 dl_harq_process* candidate_h_dl =
219- is_srb0 ? schedule_srb0 (u, res_alloc, time_res_idx, offset_to_sched_ref_slot, h_dl_retx)
220- : schedule_srb1 (u, res_alloc, time_res_idx, offset_to_sched_ref_slot, h_dl_retx);
241+ is_srb0
242+ ? schedule_srb0 (u, res_alloc, time_res_idx, offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx)
243+ : schedule_srb1 (u, res_alloc, time_res_idx, offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx);
221244
222245 const bool alloc_successful = candidate_h_dl != nullptr ;
223246 if (alloc_successful) {
224247 if (not is_retx) {
225248 store_harq_tx (u.ue_index , candidate_h_dl, is_srb0);
226249 }
250+ logger.debug (
251+ " rnti={}: PDSCH space for SRB{} scheduled for slot:{}" , u.crnti , is_srb0 ? " 0" : " 1" , pdsch_alloc.slot );
227252 return true ;
228253 }
229254
@@ -235,7 +260,7 @@ bool ue_srb0_scheduler::schedule_srb(cell_resource_allocator& res_alloc,
235260
236261 // No resource found in UE's carriers and Search spaces.
237262 slot_point pdcch_slot = res_alloc[0 ].slot ;
238- logger.debug (" rnti={}: Not enough PDSCH space for {} message found in any of the slots:[{},{}). " ,
263+ logger.debug (" rnti={}: Not enough PDSCH space for {} message found in any of the slots:[{},{})" ,
239264 u.crnti ,
240265 is_srb0 ? " SRB0" : " SRB1" ,
241266 pdcch_slot,
@@ -247,6 +272,7 @@ dl_harq_process* ue_srb0_scheduler::schedule_srb0(ue& u,
247272 cell_resource_allocator& res_alloc,
248273 unsigned pdsch_time_res,
249274 unsigned slot_offset,
275+ slot_point most_recent_ack_slot,
250276 dl_harq_process* h_dl_retx)
251277{
252278 ue_cell& ue_pcell = u.get_pcell ();
@@ -306,7 +332,7 @@ dl_harq_process* ue_srb0_scheduler::schedule_srb0(ue& u,
306332
307333 if (prbs_tbs.tbs_bytes < pending_bytes) {
308334 logger.debug (
309- " rnti={}: SRB0 PDU size ({}) exceeds TBS calculated ({}). " , pending_bytes, prbs_tbs.tbs_bytes , u.crnti );
335+ " rnti={}: SRB0 PDU size ({}) exceeds TBS calculated ({})" , pending_bytes, prbs_tbs.tbs_bytes , u.crnti );
310336 return nullptr ;
311337 }
312338
@@ -334,16 +360,20 @@ dl_harq_process* ue_srb0_scheduler::schedule_srb0(ue& u,
334360 pdcch_dl_information* pdcch =
335361 pdcch_sch.alloc_dl_pdcch_common (pdcch_alloc, u.crnti , ss_cfg.get_id (), aggregation_level::n4);
336362 if (pdcch == nullptr ) {
337- logger.debug (" rnti={}: Postponed SRB0 PDU scheduling. Cause: No space in PDCCH." , u.crnti );
363+ logger.debug (
364+ " rnti={}: Postponed SRB0 PDU scheduling for slot. Cause: No space in PDCCH." , u.crnti , pdsch_alloc.slot );
338365 return nullptr ;
339366 }
340367
341368 // Allocate PUCCH resources.
342- unsigned k1 = 4 ;
369+ unsigned k1 = dci_1_0_k1_values. front () ;
343370 // Minimum k1 value supported is 4.
344- static const std::array<uint8_t , 5 > dci_1_0_k1_values = {4 , 5 , 6 , 7 , 8 };
345- optional<unsigned > pucch_res_indicator;
371+ optional<unsigned > pucch_res_indicator;
346372 for (const auto k1_candidate : dci_1_0_k1_values) {
373+ // Skip k1 values that would result in a PUCCH transmission in a slot that is older than the most recent ACK slot.
374+ if (pdsch_alloc.slot + k1_candidate <= most_recent_ack_slot) {
375+ continue ;
376+ }
347377 pucch_res_indicator = pucch_alloc.alloc_common_pucch_harq_ack_ue (
348378 res_alloc, u.crnti , slot_offset + pdsch_td_cfg.k0 , k1_candidate, *pdcch);
349379 if (pucch_res_indicator.has_value ()) {
@@ -352,7 +382,8 @@ dl_harq_process* ue_srb0_scheduler::schedule_srb0(ue& u,
352382 }
353383 }
354384 if (not pucch_res_indicator.has_value ()) {
355- logger.debug (" Failed to allocate PDSCH for SRB0. Cause: No space in PUCCH." );
385+ logger.debug (
386+ " rnti={}: Failed to allocate PDSCH for SRB0 for slot={}. Cause: No space in PUCCH" , u.crnti , pdsch_alloc.slot );
356387 pdcch_sch.cancel_last_pdcch (pdcch_alloc);
357388 return nullptr ;
358389 }
@@ -381,6 +412,7 @@ dl_harq_process* ue_srb0_scheduler::schedule_srb1(ue& u,
381412 cell_resource_allocator& res_alloc,
382413 unsigned pdsch_time_res,
383414 unsigned slot_offset,
415+ slot_point most_recent_ack_slot,
384416 dl_harq_process* h_dl_retx)
385417{
386418 ue_cell& ue_pcell = u.get_pcell ();
@@ -490,11 +522,14 @@ dl_harq_process* ue_srb0_scheduler::schedule_srb1(ue& u,
490522 }
491523
492524 // Allocate PUCCH resources.
493- unsigned k1 = 4 ;
525+ unsigned k1 = dci_1_0_k1_values. front () ;
494526 // Minimum k1 value supported is 4.
495- static const std::array<uint8_t , 5 > dci_1_0_k1_values = {4 , 5 , 6 , 7 , 8 };
496- optional<unsigned > pucch_res_indicator;
527+ optional<unsigned > pucch_res_indicator;
497528 for (const auto k1_candidate : dci_1_0_k1_values) {
529+ // Skip the k1 values that would result in a PUCCH allocation that would overlap with the most recent ACK slot.
530+ if (pdsch_alloc.slot + k1_candidate <= most_recent_ack_slot) {
531+ continue ;
532+ }
498533 pucch_res_indicator = pucch_alloc.alloc_common_pucch_harq_ack_ue (
499534 res_alloc, u.crnti , slot_offset + pdsch_td_cfg.k0 , k1_candidate, *pdcch);
500535 if (pucch_res_indicator.has_value ()) {
@@ -503,7 +538,8 @@ dl_harq_process* ue_srb0_scheduler::schedule_srb1(ue& u,
503538 }
504539 }
505540 if (not pucch_res_indicator.has_value ()) {
506- logger.debug (" Failed to allocate PDSCH for SRB0. Cause: No space in PUCCH." );
541+ logger.debug (
542+ " rnti={}: Failed to allocate PDSCH for SRB0 for slot={}. Cause: No space in PUCCH" , u.crnti , pdsch_alloc.slot );
507543 pdcch_sch.cancel_last_pdcch (pdcch_alloc);
508544 return nullptr ;
509545 }
@@ -713,20 +749,26 @@ const pdsch_time_domain_resource_allocation& ue_srb0_scheduler::get_pdsch_td_cfg
713749 return cell_cfg.dl_cfg_common .init_dl_bwp .pdsch_common .pdsch_td_alloc_list [pdsch_time_res_idx];
714750}
715751
716- optional<slot_point> ue_srb0_scheduler::get_most_recent_slot_tx (du_ue_index_t ue_idx) const
752+ optional<std::pair< slot_point, slot_point> > ue_srb0_scheduler::get_most_recent_slot_tx (du_ue_index_t ue_idx) const
717753{
718- optional<slot_point> most_recent_tx ;
754+ optional<std::pair< slot_point, slot_point>> most_recent_tx_ack_slot ;
719755 for (const auto & ue_proc : ongoing_ues_ack_retxs) {
720756 if (ue_proc.ue_index == ue_idx) {
721- slot_point h_dl_slot_tx = ue_proc.get_harq_process ()->slot_tx ();
722- if (most_recent_tx.has_value () and h_dl_slot_tx > most_recent_tx.value ()) {
723- most_recent_tx = ue_proc.get_harq_process ()->slot_tx ();
724- } else {
725- most_recent_tx.emplace (ue_proc.get_harq_process ()->slot_tx ());
757+ slot_point h_dl_slot_tx = ue_proc.get_harq_process ()->slot_tx ();
758+ slot_point h_dl_slot_ack = ue_proc.get_harq_process ()->slot_ack ();
759+ if (not most_recent_tx_ack_slot.has_value ()) {
760+ most_recent_tx_ack_slot.emplace (h_dl_slot_tx, h_dl_slot_ack);
761+ continue ;
762+ }
763+ if (h_dl_slot_tx > most_recent_tx_ack_slot.value ().first ) {
764+ most_recent_tx_ack_slot.value ().first = h_dl_slot_tx;
765+ }
766+ if (h_dl_slot_ack > most_recent_tx_ack_slot.value ().second ) {
767+ most_recent_tx_ack_slot.value ().second = h_dl_slot_ack;
726768 }
727769 }
728770 }
729- return most_recent_tx ;
771+ return most_recent_tx_ack_slot ;
730772}
731773
732774void ue_srb0_scheduler::store_harq_tx (du_ue_index_t ue_index, dl_harq_process* h_dl, bool is_srb0)
0 commit comments