@@ -19,46 +19,40 @@ slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_) :
1919{
2020 // Create a number of slices equal to the number of configured RRM Policy members + 1 (default slice).
2121 slices.reserve (cell_cfg.rrm_policy_members .size () + 1 );
22- sorted_dl_prios.reserve (cell_cfg.rrm_policy_members .size () + 1 );
23- sorted_ul_prios.reserve (cell_cfg.rrm_policy_members .size () + 1 );
2422
2523 // Create RAN slice instances.
2624 ran_slice_id_t id_count{0 };
2725 // Default slice.
2826 slices.emplace_back (id_count, cell_cfg, slice_rrm_policy_config{});
29- slices.back ().policy =
27+ slices.back ().inst . policy =
3028 create_scheduler_strategy (scheduler_strategy_params{" time_rr" , &logger}, cell_cfg.expert_cfg .ue );
31- sorted_dl_prios.emplace_back (id_count);
32- sorted_ul_prios.emplace_back (id_count);
3329 ++id_count;
3430 // Configured RRM policy members
3531 for (const slice_rrm_policy_config& rrm : cell_cfg.rrm_policy_members ) {
3632 slices.emplace_back (id_count, cell_cfg, rrm);
37- slices.back ().policy =
33+ slices.back ().inst . policy =
3834 create_scheduler_strategy (scheduler_strategy_params{" time_rr" , &logger}, cell_cfg.expert_cfg .ue );
39- sorted_dl_prios.emplace_back (id_count);
40- sorted_ul_prios.emplace_back (id_count);
4135 ++id_count;
4236 }
4337}
4438
4539void slice_scheduler::slot_indication ()
4640{
41+ slot_count++;
42+
43+ // Update the context of each slice.
4744 for (auto & slice : slices) {
48- slice.slot_indication ();
45+ slice.inst . slot_indication ();
4946 }
5047
51- // Compute slice priorities.
52- for (slice_prio_context& ctx : sorted_dl_prios) {
53- ctx.prio = slices[ctx.id .value ()].get_dl_prio ();
54- }
55- for (slice_prio_context& ctx : sorted_ul_prios) {
56- ctx.prio = slices[ctx.id .value ()].get_ul_prio ();
48+ // Recompute the priority queues.
49+ dl_prio_queue.clear ();
50+ ul_prio_queue.clear ();
51+ for (const auto & slice : slices) {
52+ unsigned max_rbs = slice.inst .cfg .min_prb > 0 ? slice.inst .cfg .min_prb : slice.inst .cfg .max_prb ;
53+ dl_prio_queue.push (slice_candidate_context{slice.inst .id , slice.get_prio (true , slot_count, false ), {0 , max_rbs}});
54+ ul_prio_queue.push (slice_candidate_context{slice.inst .id , slice.get_prio (false , slot_count, false ), {0 , max_rbs}});
5755 }
58-
59- // Sort slices by descending priority.
60- std::sort (sorted_dl_prios.begin (), sorted_dl_prios.end (), std::greater<>{});
61- std::sort (sorted_ul_prios.begin (), sorted_ul_prios.end (), std::greater<>{});
6256}
6357
6458void slice_scheduler::add_ue (const ue_configuration& ue_cfg)
@@ -87,83 +81,104 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co
8781void slice_scheduler::rem_ue (du_ue_index_t ue_idx)
8882{
8983 for (auto & slice : slices) {
90- slice.rem_ue (ue_idx);
84+ slice.inst . rem_ue (ue_idx);
9185 }
9286}
9387
9488ran_slice_instance& slice_scheduler::get_slice (const rrm_policy_member& rrm)
9589{
96- auto it = std::find_if (
97- slices.begin (), slices.end (), [&rrm](const ran_slice_instance& slice) { return slice.cfg .rrc_member == rrm; });
90+ auto it = std::find_if (slices.begin () + 1 , slices.end (), [&rrm](const ran_slice_sched_context& slice) {
91+ return slice.inst .cfg .rrc_member == rrm;
92+ });
9893 if (it == slices.end ()) {
9994 // Slice with the provided RRM policy member was not found. Return default slice.
100- return slices.front ();
95+ return slices.front (). inst ;
10196 }
102- return *it ;
97+ return it-> inst ;
10398}
10499
105- std::optional<dl_ran_slice_candidate> slice_scheduler::get_next_dl_candidate ()
100+ template <bool IsDownlink>
101+ std::optional<std::conditional_t <IsDownlink, dl_ran_slice_candidate, ul_ran_slice_candidate>>
102+ slice_scheduler::get_next_candidate ()
106103{
107- if (slices.size () == 1 ) {
108- return create_dl_candidate ();
109- }
110-
111- // Check if the slice priority hasn't changed. If it did, recompute priorities.
112- slice_prio_context* slice_prio_ctxt = &sorted_dl_prios.front ();
113- // Recompute priority
114- int prio = slices[slice_prio_ctxt->id .value ()].get_dl_prio ();
115- if (prio != slice_prio_ctxt->prio ) {
116- // Priority changed
117- slice_prio_ctxt->prio = prio;
118- // Check if sort needs to be called again
119- // Note: This assumes that only the previous front slice was used in scheduling.
120- if (prio < sorted_dl_prios[1 ].prio ) {
121- // Slices need to be reordered.
122- std::sort (sorted_dl_prios.begin (), sorted_dl_prios.end (), std::greater<>{});
104+ slice_prio_queue& prio_queue = IsDownlink ? dl_prio_queue : ul_prio_queue;
105+ while (not prio_queue.empty ()) {
106+ ran_slice_sched_context& chosen_slice = slices[prio_queue.top ().id .value ()];
107+ interval<unsigned > rb_lims = prio_queue.top ().rb_lims ;
108+ prio_queue.pop ();
109+
110+ unsigned rb_count = IsDownlink ? chosen_slice.inst .pdsch_rb_count : chosen_slice.inst .pusch_rb_count ;
111+ if (not rb_lims.contains (rb_count)) {
112+ // The slice has been scheduled in this slot with a number of RBs that is not within the limits for this
113+ // candidate. This could happen, for instance, if the scheduler could not schedule all RBs of a candidate
114+ // bounded between {0, minRB}. In this case, the second candidate for the same slice with bounds {minRB, maxRB}
115+ // is skipped.
116+ continue ;
123117 }
124- }
125118
126- return create_dl_candidate ();
127- }
119+ const slice_rrm_policy_config& cfg = chosen_slice.inst .cfg ;
120+ if (cfg.min_prb != cfg.max_prb and rb_lims.stop () == cfg.min_prb ) {
121+ // For the special case when minRB ratio>0, the first candidate for this slice was bounded between {0, minRB}.
122+ // We re-add the slice as a candidate, this time, with RB bounds {minRB, maxRB}.
123+ priority_type prio = chosen_slice.get_prio (true , slot_count, true );
124+ prio_queue.push (slice_candidate_context{chosen_slice.inst .id , prio, {cfg.min_prb , cfg.max_prb }});
125+ }
128126
129- std::optional<ul_ran_slice_candidate> slice_scheduler::get_next_ul_candidate ()
130- {
131- if (slices.size () == 1 ) {
132- return create_ul_candidate ();
133- }
127+ // Save current slot count.
128+ unsigned & count_to_set = IsDownlink ? chosen_slice.last_dl_slot : chosen_slice.last_ul_slot ;
129+ count_to_set = slot_count;
134130
135- // Check if the slice priority hasn't changed. If it did, recompute priorities.
136- slice_prio_context* slice_prio_ctxt = &sorted_ul_prios.front ();
137- // Recompute priority
138- int prio = slices[slice_prio_ctxt->id .value ()].get_ul_prio ();
139- if (prio != slice_prio_ctxt->prio ) {
140- // Priority changed
141- slice_prio_ctxt->prio = prio;
142- // Check if sort needs to be called again
143- // Note: This assumes that only the previous front slice was used in scheduling.
144- if (prio < sorted_ul_prios[1 ].prio ) {
145- // Slices need to be reordered.
146- std::sort (sorted_ul_prios.begin (), sorted_ul_prios.end (), std::greater<>{});
147- }
131+ // Return the candidate.
132+ return std::conditional_t <IsDownlink, dl_ran_slice_candidate, ul_ran_slice_candidate>{chosen_slice.inst ,
133+ rb_lims.stop ()};
148134 }
135+ return std::nullopt ;
136+ }
149137
150- return create_ul_candidate ();
138+ std::optional<dl_ran_slice_candidate> slice_scheduler::get_next_dl_candidate ()
139+ {
140+ return get_next_candidate<true >();
151141}
152142
153- std::optional<dl_ran_slice_candidate > slice_scheduler::create_dl_candidate ()
143+ std::optional<ul_ran_slice_candidate > slice_scheduler::get_next_ul_candidate ()
154144{
155- if (sorted_dl_prios[0 ].prio != ran_slice_instance::skip_slice_prio) {
156- slices[sorted_dl_prios[0 ].id .value ()].set_pdsch_scheduled ();
157- return dl_ran_slice_candidate{slices[sorted_dl_prios[0 ].id .value ()]};
158- }
159- return std::nullopt ;
145+ return get_next_candidate<false >();
160146}
161147
162- std::optional<ul_ran_slice_candidate> slice_scheduler::create_ul_candidate ()
148+ slice_scheduler::priority_type slice_scheduler::ran_slice_sched_context::get_prio (bool is_dl,
149+ slot_count_type current_slot_count,
150+ bool slice_resched) const
163151{
164- if (sorted_ul_prios[0 ].prio != ran_slice_instance::skip_slice_prio) {
165- slices[sorted_ul_prios[0 ].id .value ()].set_pusch_scheduled ();
166- return ul_ran_slice_candidate{slices[sorted_ul_prios[0 ].id .value ()]};
152+ // Note: The positive integer representing the priority of a slice consists of a concatenation of three priority
153+ // values:
154+ // 1. slice traffic priority (16 bits). Differentiation of slices based on whether they have minimum required
155+ // traffic agreements (e.g. minRB ratio).
156+ // 2. delay priority (8 bits), which attributes the highest priority to slices that have not been scheduled for a
157+ // long time
158+ // 3. round-robin based on slot indication count (8 bits).
159+
160+ // Priority when slice has already reached its minimum RB ratio agreement.
161+ constexpr static priority_type default_prio = 0x1U ;
162+ // Priority when slice still needs to reach its minimum RB ratio agreement.
163+ constexpr static priority_type high_prio = 0x2U ;
164+ constexpr static priority_type delay_bitsize = 8U ;
165+ constexpr static priority_type rr_bitsize = 8U ;
166+
167+ unsigned rb_count = is_dl ? inst.pdsch_rb_count : inst.pusch_rb_count ;
168+ if (not inst.active () or rb_count >= inst.cfg .max_prb ) {
169+ // If the slice is not in a state to be scheduled in this slot, return skip priority level.
170+ return skip_prio;
167171 }
168- return std::nullopt ;
172+
173+ // In case minRB > 0 and this is the first time the slice is proposed as a candidate, we give it a higher priority.
174+ priority_type slice_prio = inst.cfg .min_prb > 0 and not slice_resched ? high_prio : default_prio;
175+
176+ // Increase priorities of slices that have not been scheduled for a long time.
177+ unsigned last_count = is_dl ? last_dl_slot : last_ul_slot;
178+ priority_type delay_prio = (current_slot_count - last_count) & ((1U << delay_bitsize) - 1U );
179+
180+ // Round-robin across slices with the same slice and delay priorities.
181+ priority_type rr_prio = (inst.id .value () % current_slot_count) & ((1U << rr_bitsize) - 1U );
182+
183+ return (slice_prio << (delay_bitsize + rr_bitsize)) + (delay_prio << rr_bitsize) + rr_prio;
169184}
0 commit comments