Skip to content

Commit bc29dc9

Browse files
herlesupreethcodebot
authored andcommitted
sched: refactor to use common functionality for DL and UL
1 parent 5c66acb commit bc29dc9

File tree

3 files changed

+114
-101
lines changed

3 files changed

+114
-101
lines changed

lib/scheduler/config/serving_cell_config_factory.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -286,36 +286,43 @@ std::vector<pusch_time_domain_resource_allocation>
286286
srsran::config_helpers::generate_k2_candidates(cyclic_prefix cp, const tdd_ul_dl_config_common& tdd_cfg, uint8_t min_k2)
287287
{
288288
static const unsigned SYMBOLS_PER_SLOT = get_nsymb_per_slot(cp);
289-
// Maximum number of candidates as per TS 38.331, "maxNrofUL-Allocations".
290-
static constexpr unsigned MAX_SIZE = 16;
291289

292290
const unsigned tdd_period_slots = nof_slots_per_tdd_period(tdd_cfg);
291+
const unsigned nof_dl_slots = nof_full_dl_slots_per_tdd_period(tdd_cfg);
292+
const unsigned nof_ul_slots = nof_full_ul_slots_per_tdd_period(tdd_cfg);
293293

294294
// TODO: This algorithm may need to be revisited for partial UL slots to avoid that the partial slot is always picked.
295295
std::vector<pusch_time_domain_resource_allocation> result;
296-
for (unsigned idx = 0; idx < nof_slots_per_tdd_period(tdd_cfg) and result.size() < MAX_SIZE; ++idx) {
296+
for (unsigned idx = 0; idx < tdd_period_slots and result.size() < pusch_constants::MAX_NOF_PUSCH_TD_RES_ALLOCS;
297+
++idx) {
297298
// For every slot containing DL symbols check for corresponding k2 value.
298299
if (get_active_tdd_dl_symbols(tdd_cfg, idx, cp).length() > 0) {
299-
for (unsigned k2 = min_k2; k2 <= SCHEDULER_MAX_K2 and result.size() < MAX_SIZE and k2 < tdd_period_slots; ++k2) {
300+
for (unsigned k2 = min_k2;
301+
k2 <= SCHEDULER_MAX_K2 and result.size() < pusch_constants::MAX_NOF_PUSCH_TD_RES_ALLOCS;
302+
++k2) {
300303
// TODO: Consider partial UL slots when scheduler supports it.
301304
if (get_active_tdd_ul_symbols(tdd_cfg, idx + k2, cp).length() == SYMBOLS_PER_SLOT) {
302305
if (std::none_of(result.begin(), result.end(), [k2](const auto& res) { return res.k2 == k2; })) {
303306
result.emplace_back(pusch_time_domain_resource_allocation{
304307
k2, sch_mapping_type::typeA, ofdm_symbol_range{0, SYMBOLS_PER_SLOT}});
305308
}
306309
// [Implementation-defined] For DL heavy (nof. of DL slots greater than nof. UL slots) TDD configuration nof.
307-
// k2 values are generated based on nof. DL slots i.e. one k2 value per DL slot. But whereas in the case of UL
308-
// heavy TDD configuration, where we allow multiple UL PDCCH allocations in the same slot for same UE multiple
309-
// k2 values per DL slot are generated.
310-
if (nof_full_dl_slots_per_tdd_period(tdd_cfg) > nof_full_ul_slots_per_tdd_period(tdd_cfg)) {
310+
// k2 values are generated based on nof. DL slots i.e. one k2 value per DL slot. But in the case of UL
311+
// heavy TDD configuration we generate all applicable k2 value(s) for each DL slot to allow multiple UL PDCCH
312+
// allocations in the same slot for same UE.
313+
if (nof_dl_slots > nof_ul_slots) {
314+
break;
315+
} else if (k2 > tdd_period_slots) {
311316
break;
312317
}
313318
}
314319
}
315320
}
316321
}
317322
// Sorting in ascending order is performed to reduce the latency with which PUSCH is scheduled.
318-
std::sort(result.begin(), result.end(), [](const auto& lhs, const auto& rhs) { return lhs.k2 < rhs.k2; });
323+
std::sort(result.begin(), result.end(), [](const auto& lhs, const auto& rhs) {
324+
return lhs.k2 < rhs.k2 or (lhs.k2 == rhs.k2 and lhs.symbols.length() > rhs.symbols.length());
325+
});
319326
return result;
320327
}
321328

lib/scheduler/policy/scheduler_policy.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ class ue_resource_grid_view
2525

2626
slot_point get_pdcch_slot(du_cell_index_t cell_index) const { return cell_res_grids[cell_index]->slot_tx(); }
2727

28+
slot_point get_pusch_slot(du_cell_index_t cell_index, unsigned k2) const
29+
{
30+
return (*cell_res_grids[cell_index])[k2].slot;
31+
}
32+
2833
const cell_configuration& get_cell_cfg_common(du_cell_index_t cell_index) const
2934
{
3035
return cell_res_grids[cell_index]->cfg;

lib/scheduler/policy/scheduler_time_rr.cpp

Lines changed: 93 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -112,71 +112,59 @@ static unsigned compute_max_nof_rbs_per_ue_per_slot(const ue_repository&
112112
return (bwp_crb_limits.length() / nof_ues_to_be_scheduled_per_slot);
113113
}
114114

115-
/// \brief Algorithm to select next UE to allocate in a time-domain RR fashion
116-
/// \param[in] ue_db map of "slot_ue"
117-
/// \param[in] next_ue_index UE index with the highest priority to be allocated.
118-
/// \param[in] alloc_ue callable with signature "alloc_outcome(ue&, pusch_time_domain_resource_index)" that returns the
119-
/// UE allocation outcome.
120-
/// \return Index of next UE to allocate.
121-
template <typename AllocUEFunc>
122-
du_ue_index_t round_robin_ul_apply(const ue_repository& ue_db, du_ue_index_t next_ue_index, const AllocUEFunc& alloc_ue)
115+
/// \brief Fetches a list of PUSCH Time Domain resource indexes based on cell, UE configuration and nof. symbols in
116+
/// PUSCH slot.
117+
/// \param[in] res_grid View of the current resource grid state to the PDSCH and PUSCH allocators.
118+
/// \param[in] ues map of ues.
119+
/// \return List of PUSCH Time Domain resource indexes.
120+
static static_vector<unsigned, pusch_constants::MAX_NOF_PUSCH_TD_RES_ALLOCS>
121+
get_pusch_td_resource_indexes(const ue_resource_grid_view& res_grid, const ue_repository& ues)
123122
{
124-
if (ue_db.empty()) {
125-
return next_ue_index;
126-
}
127-
auto it = ue_db.lower_bound(next_ue_index);
128-
bool first_alloc = true;
123+
// Compute list of PUSCH time domain resource index list relevant for the PUSCH slot.
124+
static_vector<unsigned, pusch_constants::MAX_NOF_PUSCH_TD_RES_ALLOCS> pusch_td_res_index_list;
129125

130126
// NOTE: All UEs use the same PUSCH Time Domain Resource configuration.
131-
const ue& ref_u = **ue_db.begin();
132-
133-
unsigned max_pusch_time_domain_resource_index = 1;
134-
if (ref_u.nof_cells() > 0) {
135-
const ue_cell_configuration& ue_cfg = ref_u.get_pcell().cfg();
136-
const auto* ss_info =
137-
ue_cfg.find_search_space(ue_cfg.cfg_dedicated().init_dl_bwp.pdcch_cfg->search_spaces.back().get_id());
138-
if (ss_info == nullptr) {
139-
return next_ue_index;
140-
}
141-
142-
// [Implementation-defined] For UL heavy TDD configuration we allow multiple UL PDCCH allocations in the same slot
143-
// for same UE but with different k2 values. In other cases (DL heavy) k2 value which is less than or equal to
144-
// minimum value of k1(s) is used. Assumes that first entry in the PUSCH Time Domain resource list contains the k2
145-
// value which is less than or equal to minimum value of k1(s).
146-
if (ue_cfg.cell_cfg_common.is_tdd() and
147-
(nof_full_ul_slots_per_tdd_period(ue_cfg.cell_cfg_common.tdd_cfg_common.value()) >
148-
nof_full_dl_slots_per_tdd_period(ue_cfg.cell_cfg_common.tdd_cfg_common.value()))) {
149-
max_pusch_time_domain_resource_index = ss_info->pusch_time_domain_list.size();
127+
const ue& ref_u = **ues.begin();
128+
const ue_cell_configuration& ue_cfg = ref_u.get_pcell().cfg();
129+
const search_space_info* ss_info =
130+
ue_cfg.find_search_space(ue_cfg.cfg_dedicated().init_dl_bwp.pdcch_cfg->search_spaces.back().get_id());
131+
if (ss_info != nullptr) {
132+
optional<unsigned> nof_full_ul_slots = nullopt;
133+
optional<unsigned> nof_full_dl_slots = nullopt;
134+
if (ue_cfg.cell_cfg_common.is_tdd()) {
135+
nof_full_ul_slots = nof_full_ul_slots_per_tdd_period(ue_cfg.cell_cfg_common.tdd_cfg_common.value());
136+
nof_full_dl_slots = nof_full_dl_slots_per_tdd_period(ue_cfg.cell_cfg_common.tdd_cfg_common.value());
150137
}
151-
}
152-
153-
for (unsigned pusch_td_res_idx = 0; pusch_td_res_idx < max_pusch_time_domain_resource_index; ++pusch_td_res_idx) {
154-
for (unsigned count = 0; count < ue_db.size(); ++count, ++it) {
155-
if (it == ue_db.end()) {
156-
// wrap-around
157-
it = ue_db.begin();
158-
}
159-
const ue& u = **it;
160-
const alloc_outcome alloc_result = alloc_ue(u, pusch_td_res_idx);
161-
if (alloc_result == alloc_outcome::skip_slot) {
162-
// Grid allocator directed policy to stop allocations for this slot.
163-
return next_ue_index;
164-
}
165-
166-
if (alloc_result == alloc_outcome::success) {
167-
if (first_alloc) {
168-
// Mark the next UE to be the first UE to get allocated in the following slot.
169-
// It is important that we equally distribute the opportunity to be the first UE being allocated in a slot for
170-
// all UEs. Otherwise, we could end up in a situation, where a UE is always the last one to be allocated and
171-
// can only use the RBs that were left from the previous UE allocations.
172-
next_ue_index = to_du_ue_index((unsigned)u.ue_index + 1U);
173-
first_alloc = false;
138+
const unsigned min_k1 = *std::min(ss_info->get_k1_candidates().begin(), ss_info->get_k1_candidates().end());
139+
// [Implementation-defined] It is assumed that UE is not configured pusch-TimeDomainAllocationList in
140+
// pusch-Config and configured only in pusch-ConfigCommon (SIB1).
141+
for (const pusch_time_domain_resource_allocation& pusch_td_res : ss_info->pusch_time_domain_list) {
142+
if (not ue_cfg.cell_cfg_common.is_tdd() or
143+
pusch_td_res.symbols.length() ==
144+
get_active_tdd_ul_symbols(
145+
ue_cfg.cell_cfg_common.tdd_cfg_common.value(),
146+
res_grid.get_pusch_slot(ref_u.get_pcell().cell_index, pusch_td_res.k2).slot_index(),
147+
cyclic_prefix::NORMAL)
148+
.length()) {
149+
if ((not ue_cfg.cell_cfg_common.is_tdd() or (*nof_full_dl_slots >= *nof_full_ul_slots)) and
150+
pusch_td_res.k2 <= min_k1) {
151+
// NOTE: Generated PUSCH time domain resources are sorted based on ascending order of k2 values and
152+
// descending order of nof. UL symbols for PUSCH.
153+
// [Implementation-defined] For DL heavy TDD configuration, only one entry in the PUSCH time domain
154+
// resources list with k2 value less than or equal to minimum value of k1(s) and, which matches nof. active
155+
// UL symbols in a slot is used.
156+
pusch_td_res_index_list.push_back(std::distance(ss_info->pusch_time_domain_list.begin(), &pusch_td_res));
157+
break;
158+
}
159+
if (ue_cfg.cell_cfg_common.is_tdd() and (*nof_full_ul_slots > *nof_full_dl_slots)) {
160+
// [Implementation-defined] For UL heavy TDD configuration multiple k2 values are considered for scheduling
161+
// since it allows multiple UL PDCCH allocations in the same slot for same UE but with different k2 values.
162+
pusch_td_res_index_list.push_back(std::distance(ss_info->pusch_time_domain_list.begin(), &pusch_td_res));
174163
}
175164
}
176165
}
177166
}
178-
179-
return next_ue_index;
167+
return pusch_td_res_index_list;
180168
}
181169

182170
/// \brief Algorithm to select next UE to allocate in a time-domain RR fashion
@@ -185,7 +173,7 @@ du_ue_index_t round_robin_ul_apply(const ue_repository& ue_db, du_ue_index_t nex
185173
/// \param[in] alloc_ue callable with signature "bool(ue&)" that returns true if UE allocation was successful.
186174
/// \return Index of next UE to allocate.
187175
template <typename AllocUEFunc>
188-
du_ue_index_t round_robin_dl_apply(const ue_repository& ue_db, du_ue_index_t next_ue_index, const AllocUEFunc& alloc_ue)
176+
du_ue_index_t round_robin_apply(const ue_repository& ue_db, du_ue_index_t next_ue_index, const AllocUEFunc& alloc_ue)
189177
{
190178
if (ue_db.empty()) {
191179
return next_ue_index;
@@ -321,13 +309,6 @@ static alloc_outcome alloc_ul_ue(const ue& u,
321309
srslog::basic_logger& logger,
322310
unsigned pusch_td_res_idx,
323311
optional<unsigned> ul_new_tx_max_nof_rbs_per_ue_per_slot = {})
324-
// static alloc_outcome alloc_ul_ue(const ue& u,
325-
// const ue_resource_grid_view& res_grid,
326-
// ue_pusch_allocator& pusch_alloc,
327-
// bool is_retx,
328-
// bool schedule_sr_only,
329-
// srslog::basic_logger& logger,
330-
// optional<unsigned> ul_new_tx_max_nof_rbs_per_ue_per_slot = {})
331312
{
332313
unsigned pending_newtx_bytes = 0;
333314
if (not is_retx) {
@@ -374,36 +355,38 @@ static alloc_outcome alloc_ul_ue(const ue& u,
374355
static_vector<const search_space_info*, MAX_NOF_SEARCH_SPACE_PER_BWP> search_spaces =
375356
ue_cc.get_active_ul_search_spaces(pdcch_slot, preferred_dci_rnti_type);
376357
for (const search_space_info* ss : search_spaces) {
377-
if (ss->cfg->is_search_space0()) {
358+
if (ss->cfg->is_search_space0() or
359+
ss->cfg->get_id() != ue_cc.cfg().cfg_dedicated().init_dl_bwp.pdcch_cfg->search_spaces.back().get_id()) {
378360
continue;
379361
}
380362

381363
const pusch_time_domain_resource_allocation& pusch_td = ss->pusch_time_domain_list[pusch_td_res_idx];
382364

383-
// UE is already allocated PUSCH.
384-
if (res_grid.has_ue_ul_grant(ue_cc.cell_index, u.crnti, pusch_td.k2)) {
365+
if (res_grid.has_ue_ul_grant(ue_cc.cell_index, ue_cc.rnti(), pusch_td.k2 + cell_cfg_common.ntn_cs_koffset)) {
366+
// Only one PUSCH per UE per slot.
385367
return alloc_outcome::skip_ue;
386368
}
387369

388370
const slot_point pusch_slot = pdcch_slot + pusch_td.k2 + cell_cfg_common.ntn_cs_koffset;
389-
const unsigned start_ul_symbols =
371+
if (not cell_cfg_common.is_ul_enabled(pusch_slot)) {
372+
// Try next PUSCH time domain resource value.
373+
return alloc_outcome::invalid_params;
374+
}
375+
const unsigned start_ul_symbols =
390376
NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - cell_cfg_common.get_nof_ul_symbol_per_slot(pusch_slot);
391377
// If it is a retx, we need to ensure we use a time_domain_resource with the same number of symbols as used for
392378
// the first transmission.
393379
const bool sym_length_match_prev_grant_for_retx =
394380
is_retx ? pusch_td.symbols.length() != h->last_tx_params().nof_symbols : true;
395-
if (not cell_cfg_common.is_ul_enabled(pusch_slot) or pusch_td.symbols.start() < start_ul_symbols or
381+
if (pusch_td.symbols.start() < start_ul_symbols or
382+
pusch_td.symbols.stop() > (start_ul_symbols + cell_cfg_common.get_nof_ul_symbol_per_slot(pusch_slot)) or
396383
!sym_length_match_prev_grant_for_retx) {
397-
// UL needs to be active for PUSCH in this slot.
398-
continue;
384+
// Try next PUSCH time domain resource value.
385+
return alloc_outcome::invalid_params;
399386
}
400387

401388
const cell_slot_resource_grid& grid =
402389
res_grid.get_pusch_grid(ue_cc.cell_index, pusch_td.k2 + cell_cfg_common.ntn_cs_koffset);
403-
if (res_grid.has_ue_ul_grant(ue_cc.cell_index, ue_cc.rnti(), pusch_td.k2 + cell_cfg_common.ntn_cs_koffset)) {
404-
// only one PUSCH per UE per slot.
405-
continue;
406-
}
407390
const prb_bitmap used_crbs =
408391
grid.used_crbs(ss->bwp->ul_common->generic_params.scs, ss->ul_crb_lims, pusch_td.symbols);
409392
if (used_crbs.all()) {
@@ -505,7 +488,7 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc,
505488
auto retx_ue_function = [this, &res_grid, &pdsch_alloc](const ue& u) {
506489
return alloc_dl_ue(u, res_grid, pdsch_alloc, true, logger);
507490
};
508-
next_dl_ue_index = round_robin_dl_apply(ues, next_dl_ue_index, retx_ue_function);
491+
next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, retx_ue_function);
509492

510493
// Then, schedule new transmissions.
511494
const unsigned dl_new_tx_max_nof_rbs_per_ue_per_slot =
@@ -514,35 +497,53 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc,
514497
auto tx_ue_function = [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) {
515498
return alloc_dl_ue(u, res_grid, pdsch_alloc, false, logger, dl_new_tx_max_nof_rbs_per_ue_per_slot);
516499
};
517-
next_dl_ue_index = round_robin_dl_apply(ues, next_dl_ue_index, tx_ue_function);
500+
next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, tx_ue_function);
518501
}
519502
}
520503

521504
void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc,
522505
const ue_resource_grid_view& res_grid,
523506
const ue_repository& ues)
524507
{
508+
if (ues.empty()) {
509+
// No UEs to be scheduled.
510+
return;
511+
}
512+
513+
// Fetch applicable PUSCH Time Domain resource index list.
514+
static_vector<unsigned, pusch_constants::MAX_NOF_PUSCH_TD_RES_ALLOCS> pusch_td_res_index_list =
515+
get_pusch_td_resource_indexes(res_grid, ues);
516+
525517
// First schedule UL data re-transmissions.
526-
auto data_retx_ue_function = [this, &res_grid, &pusch_alloc](const ue& u, unsigned pusch_td_res_idx) {
527-
return alloc_ul_ue(u, res_grid, pusch_alloc, true, false, logger, pusch_td_res_idx);
528-
};
529-
next_ul_ue_index = round_robin_ul_apply(ues, next_ul_ue_index, data_retx_ue_function);
518+
for (unsigned pusch_td_res_idx : pusch_td_res_index_list) {
519+
auto data_retx_ue_function = [this, &res_grid, &pusch_alloc, pusch_td_res_idx](const ue& u) {
520+
return alloc_ul_ue(u, res_grid, pusch_alloc, true, false, logger, pusch_td_res_idx);
521+
};
522+
next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, data_retx_ue_function);
523+
}
530524

531525
// Then, schedule all pending SR.
532-
auto sr_ue_function = [this, &res_grid, &pusch_alloc](const ue& u, unsigned pusch_td_res_idx) {
533-
return alloc_ul_ue(u, res_grid, pusch_alloc, false, true, logger, pusch_td_res_idx);
534-
};
535-
next_ul_ue_index = round_robin_ul_apply(ues, next_ul_ue_index, sr_ue_function);
526+
for (unsigned pusch_td_res_idx : pusch_td_res_index_list) {
527+
auto sr_ue_function = [this, &res_grid, &pusch_alloc, pusch_td_res_idx](const ue& u) {
528+
return alloc_ul_ue(u, res_grid, pusch_alloc, false, true, logger, pusch_td_res_idx);
529+
};
530+
next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, sr_ue_function);
531+
}
536532

537533
// Finally, schedule UL data new transmissions.
538534
const unsigned ul_new_tx_max_nof_rbs_per_ue_per_slot =
539535
compute_max_nof_rbs_per_ue_per_slot(ues, false, res_grid, expert_cfg);
540536
if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) {
541-
auto data_tx_ue_function =
542-
[this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u, unsigned pusch_td_res_idx) {
543-
return alloc_ul_ue(
544-
u, res_grid, pusch_alloc, false, false, logger, pusch_td_res_idx, ul_new_tx_max_nof_rbs_per_ue_per_slot);
545-
};
546-
next_ul_ue_index = round_robin_ul_apply(ues, next_ul_ue_index, data_tx_ue_function);
537+
for (unsigned pusch_td_res_idx : pusch_td_res_index_list) {
538+
auto data_tx_ue_function = [this,
539+
&res_grid,
540+
&pusch_alloc,
541+
ul_new_tx_max_nof_rbs_per_ue_per_slot,
542+
pusch_td_res_idx](const ue& u) {
543+
return alloc_ul_ue(
544+
u, res_grid, pusch_alloc, false, false, logger, pusch_td_res_idx, ul_new_tx_max_nof_rbs_per_ue_per_slot);
545+
};
546+
next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, data_tx_ue_function);
547+
}
547548
}
548549
}

0 commit comments

Comments
 (0)