Skip to content

Commit 9c104d5

Browse files
committed
sched: unit test for default slice scheduler
1 parent 9bc62a3 commit 9c104d5

File tree

12 files changed

+300
-51
lines changed

12 files changed

+300
-51
lines changed

lib/scheduler/slicing/ran_slice_candidate.h

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,8 @@ namespace detail {
1919
template <bool IsDl>
2020
class common_ran_slice_candidate
2121
{
22-
struct candidate_deleter {
23-
void operator()(ran_slice_instance* p)
24-
{
25-
if (p != nullptr) {
26-
if constexpr (IsDl) {
27-
p->pdsch_completed();
28-
} else {
29-
p->pusch_completed();
30-
}
31-
}
32-
}
33-
};
34-
3522
public:
36-
common_ran_slice_candidate(ran_slice_instance* instance_) : inst(instance_, candidate_deleter{}) {}
23+
common_ran_slice_candidate(ran_slice_instance& instance_) : inst(&instance_) {}
3724

3825
ran_slice_id_t id() const { return inst->id; }
3926
[[nodiscard]] const slice_rrm_policy_config& cfg() const { return inst->cfg; }
@@ -42,9 +29,6 @@ class common_ran_slice_candidate
4229
bool is_candidate(du_ue_index_t ue_idx) const { return inst->contains(ue_idx); }
4330
bool is_candidate(du_ue_index_t ue_idx, lcid_t lcid) const { return inst->contains(ue_idx, lcid); }
4431

45-
/// Signal that the allocations for this slice are complete.
46-
void clear() { inst.reset(); }
47-
4832
/// Register that a new grant was allocated for a given UE.
4933
void store_grant(unsigned nof_rbs)
5034
{
@@ -65,7 +49,7 @@ class common_ran_slice_candidate
6549
}
6650

6751
protected:
68-
std::unique_ptr<ran_slice_instance, candidate_deleter> inst;
52+
ran_slice_instance* inst = nullptr;
6953
};
7054

7155
} // namespace detail

lib/scheduler/slicing/ran_slice_id.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ namespace srsran {
1717

1818
/// RAN slice identifier that should be unique for a given cell,PLMN,S-NSSAI.
1919
struct ran_slice_id_tag {};
20-
using ran_slice_id_t = strong_type<uint8_t, struct ran_slice_id_tag, strong_increment_decrement>;
20+
using ran_slice_id_t = strong_type<uint8_t, struct ran_slice_id_tag, strong_increment_decrement, strong_equality>;
2121

2222
} // namespace srsran

lib/scheduler/slicing/ran_slice_instance.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ void ran_slice_instance::slot_indication()
2323
{
2424
pdsch_rb_count = 0;
2525
pusch_rb_count = 0;
26-
pdsch_stopped = false;
27-
pusch_stopped = false;
26+
pdsch_complete = false;
27+
pusch_complete = false;
2828
}
2929

3030
void ran_slice_instance::add_logical_channel(du_ue_index_t ue_idx, lcid_t lcid)

lib/scheduler/slicing/ran_slice_instance.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ class ran_slice_instance
3232

3333
int get_dl_prio()
3434
{
35-
if (not active() or pdsch_stopped or cfg.max_prb <= pdsch_rb_count) {
35+
if (not active() or pdsch_complete or cfg.max_prb <= pdsch_rb_count) {
3636
return skip_slice_prio;
3737
}
3838
return cfg.min_prb > pdsch_rb_count ? cfg.min_prb - pdsch_rb_count : default_slice_prio;
3939
}
4040

4141
int get_ul_prio()
4242
{
43-
if (not active() or pusch_stopped or cfg.max_prb <= pusch_rb_count) {
43+
if (not active() or pusch_complete or cfg.max_prb <= pusch_rb_count) {
4444
return skip_slice_prio;
4545
}
4646
return cfg.min_prb > pusch_rb_count ? cfg.min_prb - pusch_rb_count : default_slice_prio;
@@ -53,10 +53,10 @@ class ran_slice_instance
5353
void store_pusch_grant(unsigned crbs) { pusch_rb_count += crbs; }
5454

5555
/// Mark the allocation of PDSCH for this slice and the current slot as complete.
56-
void pdsch_completed() { pdsch_stopped = true; }
56+
void set_pdsch_scheduled() { pdsch_complete = true; }
5757

5858
/// Mark the allocation of PUSCH for this slice and the current slot as complete.
59-
void pusch_completed() { pusch_stopped = true; }
59+
void set_pusch_scheduled() { pusch_complete = true; }
6060

6161
/// Determine if at least one bearer of the given UE is currently managed by this slice.
6262
bool contains(du_ue_index_t ue_idx) const { return bearers.contains(ue_idx); }
@@ -87,8 +87,8 @@ class ran_slice_instance
8787
unsigned pusch_rb_count = 0;
8888

8989
private:
90-
bool pdsch_stopped = false;
91-
bool pusch_stopped = false;
90+
bool pdsch_complete = false;
91+
bool pusch_complete = false;
9292
};
9393

9494
} // namespace srsran

lib/scheduler/slicing/slice_scheduler.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
using namespace srsran;
1616

17-
slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_, const slice_rrm_policy_config& cfg_) :
17+
slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_) :
1818
cell_cfg(cell_cfg_), logger(srslog::fetch_basic_logger("SCHED"))
1919
{
2020
// Create a number of slices equal to the number of configured RRM Policy members + 1 (default slice).
@@ -61,28 +61,26 @@ void slice_scheduler::slot_indication()
6161
std::sort(sorted_ul_prios.begin(), sorted_ul_prios.end(), std::greater<>{});
6262
}
6363

64-
void slice_scheduler::add_ue(du_ue_index_t ue_idx, const ue_configuration& ue_cfg)
64+
void slice_scheduler::add_ue(const ue_configuration& ue_cfg)
6565
{
6666
for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) {
6767
ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy);
68-
sl_inst.add_logical_channel(ue_idx, lc_cfg.lcid);
68+
sl_inst.add_logical_channel(ue_cfg.ue_index, lc_cfg.lcid);
6969
}
7070
}
7171

72-
void slice_scheduler::reconf_ue(du_ue_index_t ue_idx,
73-
const ue_configuration& next_ue_cfg,
74-
const ue_configuration& prev_ue_cfg)
72+
void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_configuration& prev_ue_cfg)
7573
{
7674
// Remove old bearers.
7775
for (const logical_channel_config& lc_cfg : prev_ue_cfg.logical_channels()) {
7876
ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy);
79-
sl_inst.rem_logical_channel(ue_idx, lc_cfg.lcid);
77+
sl_inst.rem_logical_channel(prev_ue_cfg.ue_index, lc_cfg.lcid);
8078
}
8179

8280
// Add new bearers.
8381
for (const logical_channel_config& lc_cfg : next_ue_cfg.logical_channels()) {
8482
ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy);
85-
sl_inst.add_logical_channel(ue_idx, lc_cfg.lcid);
83+
sl_inst.add_logical_channel(prev_ue_cfg.ue_index, lc_cfg.lcid);
8684
}
8785
}
8886

@@ -104,7 +102,7 @@ ran_slice_instance& slice_scheduler::get_slice(const rrm_policy_member& rrm)
104102
return *it;
105103
}
106104

107-
dl_ran_slice_candidate slice_scheduler::get_next_dl_candidate()
105+
std::optional<dl_ran_slice_candidate> slice_scheduler::get_next_dl_candidate()
108106
{
109107
if (slices.size() == 1) {
110108
return create_dl_candidate();
@@ -128,7 +126,7 @@ dl_ran_slice_candidate slice_scheduler::get_next_dl_candidate()
128126
return create_dl_candidate();
129127
}
130128

131-
ul_ran_slice_candidate slice_scheduler::get_next_ul_candidate()
129+
std::optional<ul_ran_slice_candidate> slice_scheduler::get_next_ul_candidate()
132130
{
133131
if (slices.size() == 1) {
134132
return create_ul_candidate();
@@ -152,14 +150,22 @@ ul_ran_slice_candidate slice_scheduler::get_next_ul_candidate()
152150
return create_ul_candidate();
153151
}
154152

155-
dl_ran_slice_candidate slice_scheduler::create_dl_candidate()
153+
std::optional<dl_ran_slice_candidate> slice_scheduler::create_dl_candidate()
156154
{
157-
bool has_candidates = sorted_dl_prios[0].prio != ran_slice_instance::skip_slice_prio;
158-
return dl_ran_slice_candidate{has_candidates ? &slices[sorted_dl_prios[0].id.value()] : nullptr};
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+
sorted_dl_prios[0].prio = ran_slice_instance::skip_slice_prio;
158+
return dl_ran_slice_candidate{slices[sorted_dl_prios[0].id.value()]};
159+
}
160+
return std::nullopt;
159161
}
160162

161-
ul_ran_slice_candidate slice_scheduler::create_ul_candidate()
163+
std::optional<ul_ran_slice_candidate> slice_scheduler::create_ul_candidate()
162164
{
163-
bool has_candidates = sorted_ul_prios[0].prio != ran_slice_instance::skip_slice_prio;
164-
return ul_ran_slice_candidate{has_candidates ? &slices[sorted_ul_prios[0].id.value()] : nullptr};
165+
if (sorted_ul_prios[0].prio != ran_slice_instance::skip_slice_prio) {
166+
slices[sorted_ul_prios[0].id.value()].set_pusch_scheduled();
167+
sorted_ul_prios[0].prio = ran_slice_instance::skip_slice_prio;
168+
return ul_ran_slice_candidate{slices[sorted_ul_prios[0].id.value()]};
169+
}
170+
return std::nullopt;
165171
}

lib/scheduler/slicing/slice_scheduler.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,24 @@ namespace srsran {
2020
class slice_scheduler
2121
{
2222
public:
23-
slice_scheduler(const cell_configuration& cell_cfg_, const slice_rrm_policy_config& cfg_);
23+
slice_scheduler(const cell_configuration& cell_cfg_);
2424

2525
/// Reset the state of the slices.
2626
void slot_indication();
2727

2828
/// Update the state of the slice with the provided UE configs.
29-
void add_ue(du_ue_index_t ue_idx, const ue_configuration& ue_cfg);
30-
void reconf_ue(du_ue_index_t ue_idx, const ue_configuration& next_ue_cfg, const ue_configuration& prev_ue_cfg);
29+
void add_ue(const ue_configuration& ue_cfg);
30+
void reconf_ue(const ue_configuration& next_ue_cfg, const ue_configuration& prev_ue_cfg);
3131
void rem_ue(du_ue_index_t ue_idx);
3232

3333
/// Get next RAN slice for PDSCH scheduling.
34-
dl_ran_slice_candidate get_next_dl_candidate();
34+
std::optional<dl_ran_slice_candidate> get_next_dl_candidate();
3535

3636
/// Get next RAN slice for PUSCH scheduling.
37-
ul_ran_slice_candidate get_next_ul_candidate();
37+
std::optional<ul_ran_slice_candidate> get_next_ul_candidate();
38+
39+
size_t nof_slices() const { return slices.size(); }
40+
const slice_rrm_policy_config& slice_config(ran_slice_id_t id) const { return slices[id.value()].cfg; }
3841

3942
private:
4043
struct slice_prio_context {
@@ -51,8 +54,8 @@ class slice_scheduler
5154

5255
ran_slice_instance& get_slice(const rrm_policy_member& rrm);
5356

54-
dl_ran_slice_candidate create_dl_candidate();
55-
ul_ran_slice_candidate create_ul_candidate();
57+
std::optional<dl_ran_slice_candidate> create_dl_candidate();
58+
std::optional<ul_ran_slice_candidate> create_ul_candidate();
5659

5760
const cell_configuration& cell_cfg;
5861
srslog::basic_logger& logger;

tests/unittests/scheduler/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ add_subdirectory(ue_scheduling)
1818
add_subdirectory(uci_and_pucch)
1919
add_subdirectory(policy)
2020
add_subdirectory(config)
21+
add_subdirectory(slicing)
2122

2223
add_executable(sched_no_ue_test scheduler_no_ue_test.cpp)
2324
target_link_libraries(sched_no_ue_test srsran_sched
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#
2+
# Copyright 2021-2024 Software Radio Systems Limited
3+
#
4+
# By using this file, you agree to the terms and conditions set
5+
# forth in the LICENSE file which can be found at the top level of
6+
# the distribution.
7+
#
8+
9+
add_executable(slice_scheduler_test slice_scheduler_test.cpp)
10+
target_link_libraries(slice_scheduler_test
11+
srsran_sched
12+
scheduler_test_utils
13+
scheduler_test_suite
14+
mac_configuration_helpers
15+
gtest
16+
gtest_main
17+
)
18+
add_test(slice_scheduler_test slice_scheduler_test)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
*
3+
* Copyright 2021-2024 Software Radio Systems Limited
4+
*
5+
* By using this file, you agree to the terms and conditions set
6+
* forth in the LICENSE file which can be found at the top level of
7+
* the distribution.
8+
*
9+
*/
10+
11+
#include "lib/scheduler/slicing/slice_scheduler.h"
12+
#include "tests/unittests/scheduler/test_utils/config_generators.h"
13+
#include "srsran/srslog/srslog.h"
14+
#include <gtest/gtest.h>
15+
16+
using namespace srsran;
17+
18+
class slice_scheduler_test : public ::testing::Test
19+
{
20+
protected:
21+
slice_scheduler_test(const std::vector<slice_rrm_policy_config>& rrm_policy_members = {}) :
22+
test_cfg(
23+
[]() {
24+
cell_config_builder_params params{};
25+
params.scs_common = subcarrier_spacing::kHz30;
26+
params.channel_bw_mhz = bs_channel_bandwidth_fr1::MHz100;
27+
params.dl_arfcn = 520000;
28+
params.band = nr_band::n41;
29+
return params;
30+
}(),
31+
scheduler_expert_config{}),
32+
cell_cfg([this, rrm_policy_members]() -> const cell_configuration& {
33+
auto req = test_cfg.get_default_cell_config_request();
34+
req.rrm_policy_members = rrm_policy_members;
35+
return *test_cfg.add_cell(req);
36+
}())
37+
{
38+
logger.set_level(srslog::basic_levels::debug);
39+
srslog::init();
40+
}
41+
42+
~slice_scheduler_test() { srslog::flush(); }
43+
44+
const ue_configuration* add_ue(du_ue_index_t ue_idx)
45+
{
46+
auto req = test_cfg.get_default_ue_config_request();
47+
req.ue_index = ue_idx;
48+
req.crnti = to_rnti(0x4601 + ue_idx);
49+
req.starts_in_fallback = false;
50+
const ue_configuration* ue_cfg = test_cfg.add_ue(req);
51+
52+
slice_sched.add_ue(*ue_cfg);
53+
54+
return ue_cfg;
55+
}
56+
57+
srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST");
58+
test_helpers::test_sched_config_manager test_cfg;
59+
const cell_configuration& cell_cfg;
60+
61+
slice_scheduler slice_sched{cell_cfg};
62+
};
63+
64+
class default_slice_scheduler_test : public slice_scheduler_test
65+
{};
66+
67+
TEST_F(default_slice_scheduler_test, if_no_rrm_policy_cfg_exists_then_only_default_slice_is_created)
68+
{
69+
ASSERT_EQ(slice_sched.nof_slices(), 1);
70+
ASSERT_EQ(slice_sched.slice_config(ran_slice_id_t{0}).min_prb, 0);
71+
ASSERT_EQ(slice_sched.slice_config(ran_slice_id_t{0}).max_prb, MAX_NOF_PRBS);
72+
}
73+
74+
TEST_F(default_slice_scheduler_test, when_no_lcid_exists_then_default_slice_is_not_a_candidate)
75+
{
76+
slice_sched.slot_indication();
77+
78+
auto next_dl_slice = slice_sched.get_next_dl_candidate();
79+
ASSERT_FALSE(next_dl_slice.has_value());
80+
81+
auto next_ul_slice = slice_sched.get_next_ul_candidate();
82+
ASSERT_FALSE(next_ul_slice.has_value());
83+
}
84+
85+
TEST_F(default_slice_scheduler_test, when_lcid_is_part_of_default_slice_then_default_slice_is_valid_candidate)
86+
{
87+
this->add_ue(to_du_ue_index(0));
88+
slice_sched.slot_indication();
89+
90+
auto next_dl_slice = slice_sched.get_next_dl_candidate();
91+
ASSERT_TRUE(next_dl_slice.has_value());
92+
ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0});
93+
ASSERT_TRUE(next_dl_slice->is_candidate(to_du_ue_index(0)));
94+
ASSERT_TRUE(next_dl_slice->is_candidate(to_du_ue_index(0), lcid_t::LCID_SRB1));
95+
96+
auto next_ul_slice = slice_sched.get_next_ul_candidate();
97+
ASSERT_TRUE(next_ul_slice.has_value());
98+
ASSERT_EQ(next_ul_slice->id(), ran_slice_id_t{0});
99+
ASSERT_TRUE(next_ul_slice->is_candidate(to_du_ue_index(0)));
100+
ASSERT_TRUE(next_ul_slice->is_candidate(to_du_ue_index(0), lcid_t::LCID_SRB1));
101+
}
102+
103+
TEST_F(default_slice_scheduler_test,
104+
when_candidate_instance_goes_out_of_scope_then_it_stops_being_a_candidate_for_the_same_slot)
105+
{
106+
this->add_ue(to_du_ue_index(0));
107+
slice_sched.slot_indication();
108+
109+
auto next_dl_slice = slice_sched.get_next_dl_candidate();
110+
ASSERT_TRUE(next_dl_slice.has_value());
111+
ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0});
112+
113+
next_dl_slice = slice_sched.get_next_dl_candidate();
114+
ASSERT_FALSE(next_dl_slice.has_value());
115+
}
116+
117+
TEST_F(default_slice_scheduler_test, when_candidate_instance_goes_out_of_scope_then_it_can_be_a_candidate_for_next_slot)
118+
{
119+
this->add_ue(to_du_ue_index(0));
120+
121+
slice_sched.slot_indication();
122+
auto next_dl_slice = slice_sched.get_next_dl_candidate();
123+
ASSERT_TRUE(next_dl_slice.has_value());
124+
125+
slice_sched.slot_indication();
126+
next_dl_slice = slice_sched.get_next_dl_candidate();
127+
ASSERT_TRUE(next_dl_slice.has_value());
128+
ASSERT_EQ(next_dl_slice->id(), ran_slice_id_t{0});
129+
}

0 commit comments

Comments
 (0)