mirror of https://github.com/PentHertz/srsLTE.git
nr,gnb,sched: fix and extend sched_nr_test to verify that the DL allocated bytes match the bytes passed as DL buffer state to the scheduler
This commit is contained in:
parent
107e2aa938
commit
5cc7863379
|
@ -78,7 +78,11 @@ void sched_nr_ue_sim::update_dl_harqs(const sched_nr_cc_result_view& cc_out)
|
||||||
h.ndi = data.dci.ndi;
|
h.ndi = data.dci.ndi;
|
||||||
h.first_slot_tx = cc_out.slot;
|
h.first_slot_tx = cc_out.slot;
|
||||||
h.dci_loc = data.dci.ctx.location;
|
h.dci_loc = data.dci.ctx.location;
|
||||||
h.tbs = 100; // TODO
|
for (const sched_nr_impl::pdsch_t& pdsch : cc_out.dl->phy.pdsch) {
|
||||||
|
if (pdsch.sch.grant.rnti == data.dci.ctx.rnti) {
|
||||||
|
h.tbs = pdsch.sch.grant.tb[0].tbs / 8u;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// it is retx
|
// it is retx
|
||||||
h.nof_retxs++;
|
h.nof_retxs++;
|
||||||
|
@ -229,6 +233,12 @@ void sched_nr_base_tester::user_cfg(uint16_t rnti, const sched_nr_interface::ue_
|
||||||
sched_ptr->ue_cfg(rnti, ue_cfg_);
|
sched_ptr->ue_cfg(rnti, ue_cfg_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sched_nr_base_tester::add_rlc_dl_bytes(uint16_t rnti, uint32_t lcid, uint32_t pdu_size_bytes)
|
||||||
|
{
|
||||||
|
TESTASSERT(ue_db.count(rnti) > 0);
|
||||||
|
dl_buffer_state_diff(rnti, lcid, pdu_size_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
void sched_nr_base_tester::run_slot(slot_point slot_tx)
|
void sched_nr_base_tester::run_slot(slot_point slot_tx)
|
||||||
{
|
{
|
||||||
srsran_assert(not stopped.load(std::memory_order_relaxed), "Running scheduler when it has already been stopped");
|
srsran_assert(not stopped.load(std::memory_order_relaxed), "Running scheduler when it has already been stopped");
|
||||||
|
@ -313,6 +323,83 @@ void sched_nr_base_tester::process_results()
|
||||||
for (auto& u : ue_db) {
|
for (auto& u : ue_db) {
|
||||||
u.second.update(cc_out);
|
u.second.update(cc_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update scheduler buffers
|
||||||
|
update_sched_buffer_state(cc_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sched_nr_base_tester::dl_buffer_state_diff(uint16_t rnti, uint32_t lcid, int newtx)
|
||||||
|
{
|
||||||
|
auto& lch = gnb_ue_db[rnti].logical_channels[lcid];
|
||||||
|
lch.rlc_unacked = std::max(0, (int)lch.rlc_unacked + newtx);
|
||||||
|
update_sched_buffer_state(rnti);
|
||||||
|
logger.debug("STATUS: rnti=0x%x, lcid=%d DL buffer state is (unacked=%d, newtx=%d)",
|
||||||
|
rnti,
|
||||||
|
lcid,
|
||||||
|
lch.rlc_unacked,
|
||||||
|
lch.rlc_newtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sched_nr_base_tester::dl_buffer_state_diff(uint16_t rnti, int diff_bs)
|
||||||
|
{
|
||||||
|
if (diff_bs == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (diff_bs > 0) {
|
||||||
|
const auto& ue_bearers = ue_db.at(rnti).get_ctxt().ue_cfg.ue_bearers;
|
||||||
|
for (int i = ue_bearers.size() - 1; i >= 0; --i) {
|
||||||
|
if (ue_bearers[i].is_dl()) {
|
||||||
|
dl_buffer_state_diff(rnti, i, diff_bs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
srsran_terminate("Updating UE RLC buffer state but no bearers are active");
|
||||||
|
}
|
||||||
|
for (auto& lch : gnb_ue_db[rnti].logical_channels) {
|
||||||
|
if (not ue_db.at(rnti).get_ctxt().ue_cfg.ue_bearers[lch.first].is_dl()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int max_diff = -std::min((int)lch.second.rlc_unacked, -diff_bs);
|
||||||
|
if (max_diff != 0) {
|
||||||
|
dl_buffer_state_diff(rnti, lch.first, max_diff);
|
||||||
|
diff_bs -= max_diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sched_nr_base_tester::update_sched_buffer_state(uint16_t rnti)
|
||||||
|
{
|
||||||
|
auto& u = ue_db.at(rnti);
|
||||||
|
for (auto& lch : gnb_ue_db[rnti].logical_channels) {
|
||||||
|
int newtx = lch.second.rlc_unacked;
|
||||||
|
for (auto& cc : u.get_ctxt().cc_list) {
|
||||||
|
if (newtx <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (auto& dl_h : cc.dl_harqs) {
|
||||||
|
int tbs = dl_h.active ? dl_h.tbs : 0;
|
||||||
|
newtx = std::max(0, newtx - tbs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newtx != (int)lch.second.rlc_newtx) {
|
||||||
|
sched_ptr->dl_buffer_state(rnti, lch.first, newtx, 0);
|
||||||
|
lch.second.rlc_newtx = newtx;
|
||||||
|
logger.debug("STATUS: rnti=0x%x, lcid=%d DL buffer state is (unacked=%d, newtx=%d)",
|
||||||
|
rnti,
|
||||||
|
lch.first,
|
||||||
|
lch.second.rlc_unacked,
|
||||||
|
lch.second.rlc_newtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sched_nr_base_tester::update_sched_buffer_state(const sched_nr_cc_result_view& cc_out)
|
||||||
|
{
|
||||||
|
for (auto& dl : cc_out.dl->phy.pdcch_dl) {
|
||||||
|
if (dl.dci.ctx.rnti_type == srsran_rnti_type_c or dl.dci.ctx.rnti_type == srsran_rnti_type_tc) {
|
||||||
|
update_sched_buffer_state(dl.dci.ctx.rnti);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,8 +446,13 @@ int sched_nr_base_tester::apply_slot_events(sim_nr_ue_ctxt_t& ue_ctxt, const ue_
|
||||||
auto& h = ue_ctxt.cc_list[enb_cc_idx].dl_harqs[ack.pid];
|
auto& h = ue_ctxt.cc_list[enb_cc_idx].dl_harqs[ack.pid];
|
||||||
|
|
||||||
if (ack.ack) {
|
if (ack.ack) {
|
||||||
logger.info(
|
logger.info("EVENT: DL ACK rnti=0x%x slot_dl_tx=%u cc=%d pid=%d, tbs=%d",
|
||||||
"DL ACK rnti=0x%x slot_dl_tx=%u cc=%d pid=%d", ue_ctxt.rnti, h.last_slot_tx.to_uint(), enb_cc_idx, ack.pid);
|
ue_ctxt.rnti,
|
||||||
|
h.last_slot_tx.to_uint(),
|
||||||
|
enb_cc_idx,
|
||||||
|
ack.pid,
|
||||||
|
h.tbs);
|
||||||
|
dl_buffer_state_diff(ue_ctxt.rnti, -(int)h.tbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update scheduler
|
// update scheduler
|
||||||
|
@ -385,7 +477,7 @@ int sched_nr_base_tester::apply_slot_events(sim_nr_ue_ctxt_t& ue_ctxt, const ue_
|
||||||
|
|
||||||
if (h.is_msg3) {
|
if (h.is_msg3) {
|
||||||
logger.info("STATUS: rnti=0x%x received Msg3", ue_ctxt.rnti);
|
logger.info("STATUS: rnti=0x%x received Msg3", ue_ctxt.rnti);
|
||||||
sched_ptr->dl_buffer_state(ue_ctxt.rnti, 0, 150, 0); // Schedule RRC setup
|
dl_buffer_state_diff(ue_ctxt.rnti, 0, 150); // Schedule RRC setup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,8 @@ public:
|
||||||
|
|
||||||
void user_cfg(uint16_t rnti, const sched_nr_interface::ue_cfg_t& ue_cfg_);
|
void user_cfg(uint16_t rnti, const sched_nr_interface::ue_cfg_t& ue_cfg_);
|
||||||
|
|
||||||
|
void add_rlc_dl_bytes(uint16_t rnti, uint32_t lcid, uint32_t pdu_size_bytes);
|
||||||
|
|
||||||
srsran::const_span<sched_nr_impl::cell_params_t> get_cell_params() { return cell_params; }
|
srsran::const_span<sched_nr_impl::cell_params_t> get_cell_params() { return cell_params; }
|
||||||
|
|
||||||
// configurable by simulator concrete implementation
|
// configurable by simulator concrete implementation
|
||||||
|
@ -141,6 +143,11 @@ protected:
|
||||||
void generate_cc_result(uint32_t cc);
|
void generate_cc_result(uint32_t cc);
|
||||||
sim_nr_enb_ctxt_t get_enb_ctxt() const;
|
sim_nr_enb_ctxt_t get_enb_ctxt() const;
|
||||||
|
|
||||||
|
void dl_buffer_state_diff(uint16_t rnti, uint32_t lcid, int newtx);
|
||||||
|
void dl_buffer_state_diff(uint16_t rnti, int newtx);
|
||||||
|
void update_sched_buffer_state(uint16_t rnti);
|
||||||
|
void update_sched_buffer_state(const sched_nr_cc_result_view& cc_out);
|
||||||
|
|
||||||
int set_default_slot_events(const sim_nr_ue_ctxt_t& ue_ctxt, ue_nr_slot_events& pending_events);
|
int set_default_slot_events(const sim_nr_ue_ctxt_t& ue_ctxt, ue_nr_slot_events& pending_events);
|
||||||
int apply_slot_events(sim_nr_ue_ctxt_t& ue_ctxt, const ue_nr_slot_events& events);
|
int apply_slot_events(sim_nr_ue_ctxt_t& ue_ctxt, const ue_nr_slot_events& events);
|
||||||
|
|
||||||
|
@ -155,8 +162,19 @@ protected:
|
||||||
|
|
||||||
std::vector<std::unique_ptr<srsran::task_worker> > cc_workers;
|
std::vector<std::unique_ptr<srsran::task_worker> > cc_workers;
|
||||||
|
|
||||||
|
// UE context from the UE's point-of-view
|
||||||
std::map<uint16_t, sched_nr_ue_sim> ue_db;
|
std::map<uint16_t, sched_nr_ue_sim> ue_db;
|
||||||
|
|
||||||
|
// gNB point-of-view of UE state
|
||||||
|
struct gnb_ue_ctxt {
|
||||||
|
struct channel_ctxt {
|
||||||
|
uint32_t rlc_unacked = 0;
|
||||||
|
uint32_t rlc_newtx = 0;
|
||||||
|
};
|
||||||
|
std::map<uint32_t, channel_ctxt> logical_channels;
|
||||||
|
};
|
||||||
|
std::map<uint16_t, gnb_ue_ctxt> gnb_ue_db;
|
||||||
|
|
||||||
// slot-specific
|
// slot-specific
|
||||||
slot_point current_slot_tx;
|
slot_point current_slot_tx;
|
||||||
std::chrono::steady_clock::time_point slot_start_tp;
|
std::chrono::steady_clock::time_point slot_start_tp;
|
||||||
|
|
|
@ -17,6 +17,50 @@
|
||||||
|
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
|
|
||||||
|
class sched_tester : public sched_nr_base_tester
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using sched_nr_base_tester::sched_nr_base_tester;
|
||||||
|
|
||||||
|
void process_slot_result(const sim_nr_enb_ctxt_t& enb_ctxt, srsran::const_span<cc_result_t> cc_out) override
|
||||||
|
{
|
||||||
|
for (auto& cc : cc_out) {
|
||||||
|
for (auto& pdsch : cc.res.dl->phy.pdsch) {
|
||||||
|
if (pdsch.sch.grant.rnti_type == srsran_rnti_type_c or pdsch.sch.grant.rnti_type == srsran_rnti_type_tc) {
|
||||||
|
ue_metrics[pdsch.sch.grant.rnti].nof_dl_txs++;
|
||||||
|
ue_metrics[pdsch.sch.grant.rnti].nof_dl_bytes += pdsch.sch.grant.tb[0].tbs / 8u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& pusch : cc.res.ul->pusch) {
|
||||||
|
if (pusch.sch.grant.rnti_type == srsran_rnti_type_c or pusch.sch.grant.rnti_type == srsran_rnti_type_tc) {
|
||||||
|
ue_metrics[pusch.sch.grant.rnti].nof_ul_txs++;
|
||||||
|
ue_metrics[pusch.sch.grant.rnti].nof_ul_bytes += pusch.sch.grant.tb[0].tbs / 8u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_results()
|
||||||
|
{
|
||||||
|
srslog::flush();
|
||||||
|
fmt::print("SCHED UE metrics:\n");
|
||||||
|
for (auto& u : ue_metrics) {
|
||||||
|
fmt::print(" 0x{:x}: nof_txs=({}, {}), nof_bytes=({}, {})\n",
|
||||||
|
u.first,
|
||||||
|
u.second.nof_dl_txs,
|
||||||
|
u.second.nof_ul_txs,
|
||||||
|
u.second.nof_dl_bytes,
|
||||||
|
u.second.nof_ul_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sched_ue_metrics {
|
||||||
|
uint32_t nof_dl_txs = 0, nof_ul_txs = 0;
|
||||||
|
uint64_t nof_dl_bytes = 0, nof_ul_bytes = 0;
|
||||||
|
};
|
||||||
|
std::map<uint16_t, sched_ue_metrics> ue_metrics;
|
||||||
|
};
|
||||||
|
|
||||||
struct sched_event_t {
|
struct sched_event_t {
|
||||||
uint32_t slot_count;
|
uint32_t slot_count;
|
||||||
std::function<void(sched_nr_base_tester&)> run;
|
std::function<void(sched_nr_base_tester&)> run;
|
||||||
|
@ -36,7 +80,13 @@ sched_event_t ue_cfg(uint32_t slot_count, uint16_t rnti, const sched_nr_ue_cfg_t
|
||||||
return sched_event_t{slot_count, task};
|
return sched_event_t{slot_count, task};
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_sched_nr_test()
|
sched_event_t add_rlc_dl_bytes(uint32_t slot_count, uint16_t rnti, uint32_t lcid, uint32_t pdu_size)
|
||||||
|
{
|
||||||
|
auto task = [rnti, pdu_size, lcid](sched_nr_base_tester& tester) { tester.add_rlc_dl_bytes(rnti, lcid, pdu_size); };
|
||||||
|
return sched_event_t{slot_count, task};
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_sched_nr_no_data()
|
||||||
{
|
{
|
||||||
uint32_t max_nof_ttis = 1000, nof_sectors = 1;
|
uint32_t max_nof_ttis = 1000, nof_sectors = 1;
|
||||||
uint16_t rnti = 0x4601;
|
uint16_t rnti = 0x4601;
|
||||||
|
@ -45,8 +95,8 @@ void run_sched_nr_test()
|
||||||
cfg.auto_refill_buffer = false;
|
cfg.auto_refill_buffer = false;
|
||||||
std::vector<sched_nr_interface::cell_cfg_t> cells_cfg = get_default_cells_cfg(nof_sectors);
|
std::vector<sched_nr_interface::cell_cfg_t> cells_cfg = get_default_cells_cfg(nof_sectors);
|
||||||
|
|
||||||
std::string test_name = "Serialized Test";
|
std::string test_name = "Test with no data";
|
||||||
sched_nr_base_tester tester(cfg, cells_cfg, test_name);
|
sched_tester tester(cfg, cells_cfg, test_name);
|
||||||
|
|
||||||
/* Set events */
|
/* Set events */
|
||||||
std::deque<sched_event_t> events;
|
std::deque<sched_event_t> events;
|
||||||
|
@ -67,6 +117,55 @@ void run_sched_nr_test()
|
||||||
// call sched
|
// call sched
|
||||||
tester.run_slot(slot_tx);
|
tester.run_slot(slot_tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tester.print_results();
|
||||||
|
|
||||||
|
// Since DL buffers were not externally updated, we should only see Msg4 as DL tx
|
||||||
|
TESTASSERT_EQ(1, tester.ue_metrics[rnti].nof_dl_txs);
|
||||||
|
// Since UL buffers were not externally updated, we should only see Msg3 as UL tx
|
||||||
|
TESTASSERT_EQ(1, tester.ue_metrics[rnti].nof_ul_txs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_sched_nr_data()
|
||||||
|
{
|
||||||
|
uint32_t max_nof_ttis = 1000, nof_sectors = 1;
|
||||||
|
uint16_t rnti = 0x4601;
|
||||||
|
uint32_t nof_dl_bytes_to_tx = 1e6;
|
||||||
|
|
||||||
|
sched_nr_interface::sched_args_t cfg;
|
||||||
|
cfg.auto_refill_buffer = false;
|
||||||
|
std::vector<sched_nr_interface::cell_cfg_t> cells_cfg = get_default_cells_cfg(nof_sectors);
|
||||||
|
|
||||||
|
std::string test_name = "Test with data";
|
||||||
|
sched_tester tester(cfg, cells_cfg, test_name);
|
||||||
|
|
||||||
|
/* Set events */
|
||||||
|
std::deque<sched_event_t> events;
|
||||||
|
events.push_back(add_user(9, rnti, 0));
|
||||||
|
events.push_back(ue_cfg(20, rnti, get_default_ue_cfg(1)));
|
||||||
|
events.push_back(add_rlc_dl_bytes(50, rnti, 0, nof_dl_bytes_to_tx));
|
||||||
|
|
||||||
|
/* Run Test */
|
||||||
|
for (uint32_t nof_slots = 0; nof_slots < max_nof_ttis; ++nof_slots) {
|
||||||
|
slot_point slot_rx(0, nof_slots % 10240);
|
||||||
|
slot_point slot_tx = slot_rx + TX_ENB_DELAY;
|
||||||
|
|
||||||
|
// run events
|
||||||
|
while (not events.empty() and events.front().slot_count <= nof_slots) {
|
||||||
|
events.front().run(tester);
|
||||||
|
events.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call sched
|
||||||
|
tester.run_slot(slot_tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
tester.print_results();
|
||||||
|
|
||||||
|
TESTASSERT(tester.ue_metrics[rnti].nof_dl_txs > 1);
|
||||||
|
TESTASSERT(tester.ue_metrics[rnti].nof_dl_bytes >= nof_dl_bytes_to_tx);
|
||||||
|
// Since UL buffers were not externally updated, we should only see Msg3 as UL tx
|
||||||
|
TESTASSERT_EQ(1, tester.ue_metrics[rnti].nof_ul_txs);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace srsenb
|
} // namespace srsenb
|
||||||
|
@ -83,5 +182,6 @@ int main()
|
||||||
// Start the log backend.
|
// Start the log backend.
|
||||||
srslog::init();
|
srslog::init();
|
||||||
|
|
||||||
srsenb::run_sched_nr_test();
|
srsenb::test_sched_nr_no_data();
|
||||||
|
srsenb::test_sched_nr_data();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue