From 5cc7863379cfc1b287708deb660244b2cf842508 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 8 Dec 2021 14:55:08 +0000 Subject: [PATCH] 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 --- srsgnb/src/stack/mac/test/sched_nr_sim_ue.cc | 100 ++++++++++++++++- srsgnb/src/stack/mac/test/sched_nr_sim_ue.h | 18 ++++ srsgnb/src/stack/mac/test/sched_nr_test.cc | 108 ++++++++++++++++++- 3 files changed, 218 insertions(+), 8 deletions(-) diff --git a/srsgnb/src/stack/mac/test/sched_nr_sim_ue.cc b/srsgnb/src/stack/mac/test/sched_nr_sim_ue.cc index 5e35130b2..65e159036 100644 --- a/srsgnb/src/stack/mac/test/sched_nr_sim_ue.cc +++ b/srsgnb/src/stack/mac/test/sched_nr_sim_ue.cc @@ -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.first_slot_tx = cc_out.slot; 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 { // it is retx 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_); } +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) { 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) { 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]; if (ack.ack) { - logger.info( - "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); + logger.info("EVENT: DL ACK rnti=0x%x slot_dl_tx=%u cc=%d pid=%d, tbs=%d", + 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 @@ -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) { 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 } } } diff --git a/srsgnb/src/stack/mac/test/sched_nr_sim_ue.h b/srsgnb/src/stack/mac/test/sched_nr_sim_ue.h index 75341d062..5f617d2d7 100644 --- a/srsgnb/src/stack/mac/test/sched_nr_sim_ue.h +++ b/srsgnb/src/stack/mac/test/sched_nr_sim_ue.h @@ -129,6 +129,8 @@ public: 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 get_cell_params() { return cell_params; } // configurable by simulator concrete implementation @@ -141,6 +143,11 @@ protected: void generate_cc_result(uint32_t cc); 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 apply_slot_events(sim_nr_ue_ctxt_t& ue_ctxt, const ue_nr_slot_events& events); @@ -155,8 +162,19 @@ protected: std::vector > cc_workers; + // UE context from the UE's point-of-view std::map 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 logical_channels; + }; + std::map gnb_ue_db; + // slot-specific slot_point current_slot_tx; std::chrono::steady_clock::time_point slot_start_tp; diff --git a/srsgnb/src/stack/mac/test/sched_nr_test.cc b/srsgnb/src/stack/mac/test/sched_nr_test.cc index 808667709..6a41ece98 100644 --- a/srsgnb/src/stack/mac/test/sched_nr_test.cc +++ b/srsgnb/src/stack/mac/test/sched_nr_test.cc @@ -17,6 +17,50 @@ 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_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 ue_metrics; +}; + struct sched_event_t { uint32_t slot_count; std::function 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}; } -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; uint16_t rnti = 0x4601; @@ -45,8 +95,8 @@ void run_sched_nr_test() cfg.auto_refill_buffer = false; std::vector cells_cfg = get_default_cells_cfg(nof_sectors); - std::string test_name = "Serialized Test"; - sched_nr_base_tester tester(cfg, cells_cfg, test_name); + std::string test_name = "Test with no data"; + sched_tester tester(cfg, cells_cfg, test_name); /* Set events */ std::deque events; @@ -67,6 +117,55 @@ void run_sched_nr_test() // call sched 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 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 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 @@ -83,5 +182,6 @@ int main() // Start the log backend. srslog::init(); - srsenb::run_sched_nr_test(); + srsenb::test_sched_nr_no_data(); + srsenb::test_sched_nr_data(); }