From 992ea7fd29eb488f47536bbcaca52781449997dc Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 13 Nov 2020 00:37:45 +0000 Subject: [PATCH] moved UE-dedicated RA sched test to separate test suite file. --- srsenb/test/mac/sched_sim_ue.cc | 106 +++++++-- srsenb/test/mac/sched_sim_ue.h | 18 +- srsenb/test/mac/sched_ue_ded_test_suite.cc | 149 ++++++++++-- srsenb/test/mac/sched_ue_ded_test_suite.h | 10 + srsenb/test/mac/scheduler_test_common.cc | 249 ++------------------- srsenb/test/mac/scheduler_test_common.h | 19 +- srsenb/test/mac/scheduler_test_rand.cc | 2 +- 7 files changed, 272 insertions(+), 281 deletions(-) diff --git a/srsenb/test/mac/sched_sim_ue.cc b/srsenb/test/mac/sched_sim_ue.cc index 934f13ea0..e60a14e11 100644 --- a/srsenb/test/mac/sched_sim_ue.cc +++ b/srsenb/test/mac/sched_sim_ue.cc @@ -20,23 +20,52 @@ */ #include "sched_sim_ue.h" +#include "lib/include/srslte/mac/pdu.h" namespace srsenb { using phich_t = sched_interface::ul_sched_phich_t; -ue_sim::ue_sim(uint16_t rnti_, const sched_interface::ue_cfg_t& ue_cfg_, srslte::tti_point prach_tti_rx_) +bool sim_ue_ctxt_t::is_msg3_harq(uint32_t ue_cc_idx, uint32_t pid) const +{ + auto& h = cc_list.at(ue_cc_idx).ul_harqs[pid]; + return h.first_tti_rx == msg3_tti_rx and h.nof_txs == h.nof_retxs + 1; +} + +bool sim_ue_ctxt_t::is_last_ul_retx(uint32_t ue_cc_idx, uint32_t pid, uint32_t maxharq_msg3tx) const +{ + bool is_msg3 = is_msg3_harq(ue_cc_idx, pid); + auto& h = cc_list.at(ue_cc_idx).ul_harqs[pid]; + return h.nof_retxs + 1 >= (is_msg3 ? maxharq_msg3tx : ue_cfg.maxharq_tx); +} + +bool sim_ue_ctxt_t::is_last_dl_retx(uint32_t ue_cc_idx, uint32_t pid) const +{ + auto& h = cc_list.at(ue_cc_idx).dl_harqs[pid]; + return h.nof_retxs + 1 >= ue_cfg.maxharq_tx; +} + +ue_sim::ue_sim(uint16_t rnti_, + const sched_interface::ue_cfg_t& ue_cfg_, + srslte::tti_point prach_tti_rx_, + uint32_t preamble_idx) { ctxt.rnti = rnti_; - ctxt.ue_cfg = ue_cfg_; ctxt.prach_tti_rx = prach_tti_rx_; - ctxt.cc_list.resize(ue_cfg_.supported_cc_list.size()); + ctxt.preamble_idx = preamble_idx; + set_cfg(ue_cfg_); } void ue_sim::set_cfg(const sched_interface::ue_cfg_t& ue_cfg_) { ctxt.ue_cfg = ue_cfg_; ctxt.cc_list.resize(ue_cfg_.supported_cc_list.size()); + for (auto& cc : ctxt.cc_list) { + for (size_t pid = 0; pid < (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS); ++pid) { + cc.ul_harqs[pid].pid = pid; + cc.dl_harqs[pid].pid = pid; + } + } } bool ue_sim::enqueue_pending_acks(srslte::tti_point tti_rx, @@ -92,14 +121,16 @@ void ue_sim::update_dl_harqs(const sf_output_res_t& sf_out) auto& h = ctxt.cc_list[data.dci.ue_cc_idx].dl_harqs[data.dci.pid]; if (h.nof_txs == 0 or h.ndi != data.dci.tb[0].ndi) { // It is newtx - h.active = true; - h.nof_retxs = 0; - h.ndi = data.dci.tb[0].ndi; + h.nof_retxs = 0; + h.ndi = data.dci.tb[0].ndi; + h.first_tti_rx = sf_out.tti_rx; } else { // it is retx h.nof_retxs++; } + h.active = true; h.last_tti_rx = sf_out.tti_rx; + h.nof_txs++; } } } @@ -156,19 +187,68 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) void ue_sim::update_conn_state(const sf_output_res_t& sf_out) { - if (not ctxt.msg3_tti_rx.is_valid()) { - auto& cc_result = sf_out.ul_cc_result[ctxt.ue_cfg.supported_cc_list[0].enb_cc_idx]; - for (uint32_t i = 0; i < cc_result.nof_dci_elems; ++i) { - if (cc_result.pusch[i].dci.rnti == ctxt.rnti) { - ctxt.msg3_tti_rx = sf_out.tti_rx; + if (ctxt.msg4_tti_rx.is_valid()) { + return; + } + + // only check for RAR/Msg3 presence for a UE's PCell + uint32_t cc = ctxt.ue_cfg.supported_cc_list[0].enb_cc_idx; + const auto& dl_cc_result = sf_out.dl_cc_result[cc]; + const auto& ul_cc_result = sf_out.ul_cc_result[cc]; + srslte::tti_point tti_tx_dl = to_tx_dl(sf_out.tti_rx); + + if (not ctxt.rar_tti_rx.is_valid()) { + // RAR not yet found + uint32_t rar_win_size = sf_out.cc_params[cc].cfg.prach_rar_window; + srslte::tti_interval rar_window{ctxt.prach_tti_rx + 3, ctxt.prach_tti_rx + 3 + rar_win_size}; + + if (rar_window.contains(tti_tx_dl)) { + for (uint32_t i = 0; i < dl_cc_result.nof_rar_elems; ++i) { + for (uint32_t j = 0; j < dl_cc_result.rar[i].nof_grants; ++j) { + const auto& data = dl_cc_result.rar[i].msg3_grant[j].data; + if (data.prach_tti == (uint32_t)ctxt.prach_tti_rx.to_uint() and data.preamble_idx == ctxt.preamble_idx) { + ctxt.rar_tti_rx = sf_out.tti_rx; + ctxt.msg3_riv = dl_cc_result.rar[i].msg3_grant[j].grant.rba; + } + } + } + } + } + + if (ctxt.rar_tti_rx.is_valid() and not ctxt.msg3_tti_rx.is_valid()) { + // RAR scheduled, Msg3 not yet scheduled + srslte::tti_point expected_msg3_tti_rx = ctxt.rar_tti_rx + MSG3_DELAY_MS; + if (expected_msg3_tti_rx == sf_out.tti_rx) { + // Msg3 should exist + for (uint32_t i = 0; i < ul_cc_result.nof_dci_elems; ++i) { + if (ul_cc_result.pusch[i].dci.rnti == ctxt.rnti) { + ctxt.msg3_tti_rx = sf_out.tti_rx; + } + } + } + } + + if (ctxt.msg3_tti_rx.is_valid() and not ctxt.msg4_tti_rx.is_valid()) { + // Msg3 scheduled, but Msg4 not yet scheduled + for (uint32_t i = 0; i < dl_cc_result.nof_data_elems; ++i) { + if (dl_cc_result.data[i].dci.rnti == ctxt.rnti) { + for (uint32_t j = 0; j < dl_cc_result.data[i].nof_pdu_elems[0]; ++j) { + if (dl_cc_result.data[i].pdu[0][j].lcid == (uint32_t)srslte::dl_sch_lcid::CON_RES_ID) { + // ConRes found + ctxt.msg4_tti_rx = sf_out.tti_rx; + } + } } } } } -void ue_db_sim::add_user(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_, srslte::tti_point prach_tti_rx_) +void ue_db_sim::add_user(uint16_t rnti, + const sched_interface::ue_cfg_t& ue_cfg_, + srslte::tti_point prach_tti_rx_, + uint32_t preamble_idx) { - ue_db.insert(std::make_pair(rnti, ue_sim(rnti, ue_cfg_, prach_tti_rx_))); + ue_db.insert(std::make_pair(rnti, ue_sim(rnti, ue_cfg_, prach_tti_rx_, preamble_idx))); } void ue_db_sim::ue_recfg(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_) diff --git a/srsenb/test/mac/sched_sim_ue.h b/srsenb/test/mac/sched_sim_ue.h index 3ca44d161..c3b3d6b53 100644 --- a/srsenb/test/mac/sched_sim_ue.h +++ b/srsenb/test/mac/sched_sim_ue.h @@ -43,12 +43,16 @@ struct ue_cc_ctxt_t { }; struct sim_ue_ctxt_t { uint16_t rnti; - srslte::tti_point prach_tti_rx, msg3_tti_rx; + uint32_t preamble_idx, msg3_riv; + srslte::tti_point prach_tti_rx, rar_tti_rx, msg3_tti_rx, msg4_tti_rx; sched_interface::ue_cfg_t ue_cfg; std::vector cc_list; const sched_interface::ue_cfg_t::cc_cfg_t* get_cc_cfg(uint32_t enb_cc_idx) const; int enb_to_ue_cc_idx(uint32_t enb_cc_idx) const; + bool is_msg3_harq(uint32_t ue_cc_idx, uint32_t pid) const; + bool is_last_ul_retx(uint32_t ue_cc_idx, uint32_t pid, uint32_t maxharq_msg3tx) const; + bool is_last_dl_retx(uint32_t ue_cc_idx, uint32_t pid) const; }; struct sim_enb_ctxt_t { @@ -68,7 +72,10 @@ struct pucch_feedback { class ue_sim { public: - ue_sim(uint16_t rnti_, const sched_interface::ue_cfg_t& ue_cfg_, srslte::tti_point prach_tti_rx); + ue_sim(uint16_t rnti_, + const sched_interface::ue_cfg_t& ue_cfg_, + srslte::tti_point prach_tti_rx, + uint32_t preamble_idx); void set_cfg(const sched_interface::ue_cfg_t& ue_cfg_); @@ -92,12 +99,17 @@ private: class ue_db_sim { public: - void add_user(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_, srslte::tti_point prach_tti_rx_); + void add_user(uint16_t rnti, + const sched_interface::ue_cfg_t& ue_cfg_, + srslte::tti_point prach_tti_rx_, + uint32_t preamble_idx); void ue_recfg(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_); void rem_user(uint16_t rnti); void update(const sf_output_res_t& sf_out); std::map get_ues_ctxt() const; + ue_sim& at(uint16_t rnti) { return ue_db.at(rnti); } + const ue_sim& at(uint16_t rnti) const { return ue_db.at(rnti); } private: std::map ue_db; diff --git a/srsenb/test/mac/sched_ue_ded_test_suite.cc b/srsenb/test/mac/sched_ue_ded_test_suite.cc index 3014b81d0..7fede9686 100644 --- a/srsenb/test/mac/sched_ue_ded_test_suite.cc +++ b/srsenb/test/mac/sched_ue_ded_test_suite.cc @@ -20,6 +20,7 @@ */ #include "sched_ue_ded_test_suite.h" +#include "lib/include/srslte/mac/pdu.h" #include "srslte/common/test_common.h" namespace srsenb { @@ -64,6 +65,7 @@ int test_pdsch_grant(const sim_ue_ctxt_t& ue_ctxt, if (h.nof_txs == 0 or h.ndi != pdsch.dci.tb[0].ndi) { // It is newtx CONDERROR(nof_retx != 0, "Invalid rv index for new tx\n"); + CONDERROR(h.active, "DL newtx for already active DL harq pid=%d\n", h.pid); } else { // it is retx CONDERROR(sched_utils::get_rvidx(h.nof_retxs + 1) != (uint32_t)pdsch.dci.tb[0].rv, "Invalid rv index for retx\n"); @@ -104,6 +106,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& const auto& ue = *ue_pair.second; uint16_t rnti = ue.rnti; int ue_cc_idx = ue.enb_to_ue_cc_idx(cc); + const auto& h = ue.cc_list[ue_cc_idx].ul_harqs[pid]; // TEST: Check if CC is configured and active CONDERROR(ue_cc_idx < 0 or not ue.ue_cfg.supported_cc_list[ue_cc_idx].active, @@ -116,8 +119,12 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& std::find_if(pusch_begin, pusch_end, [rnti](const pusch_t& pusch) { return pusch.dci.rnti == rnti; }); pusch_ptr = pusch_ptr == pusch_end ? nullptr : pusch_ptr; + bool phich_ack = phich_ptr != nullptr and phich_ptr->phich == phich_t::ACK; + bool is_msg3 = h.first_tti_rx == ue.msg3_tti_rx and h.nof_txs == h.nof_retxs + 1; + bool last_retx = h.nof_retxs + 1 >= (is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ue.ue_cfg.maxharq_tx); + bool h_inactive = (not h.active) or (phich_ack or last_retx); + // TEST: Already active UL HARQs have to receive PHICH - const auto& h = ue.cc_list[ue_cc_idx].ul_harqs[pid]; CONDERROR( h.active and phich_ptr == nullptr, "PHICH not received for rnti=0x%x active UL HARQ pid=%d\n", rnti, pid); CONDERROR(not h.active and phich_ptr != nullptr, @@ -127,11 +134,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& // TEST: absent PUSCH grants for active DL HARQs must be either ACKs, last retx, or interrupted HARQs if (phich_ptr != nullptr and pusch_ptr == nullptr) { - bool is_ack = phich_ptr->phich == phich_t::ACK; - bool is_msg3 = h.first_tti_rx == ue.msg3_tti_rx and h.nof_txs == h.nof_retxs + 1; - bool last_retx = h.nof_retxs + 1 >= (is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ue.ue_cfg.maxharq_tx); - CONDERROR( - not is_ack and not last_retx, "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated\n", rnti); + CONDERROR(not h_inactive, "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated\n", rnti); } if (pusch_ptr != nullptr) { @@ -144,6 +147,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& // newtx CONDERROR(nof_retx != 0, "Invalid rv index for new tx\n"); CONDERROR(pusch_ptr->current_tx_nb != 0, "UL HARQ retxs need to have been previously transmitted\n"); + CONDERROR(not h_inactive, "New tx for already active UL HARQ\n"); } else { CONDERROR(pusch_ptr->current_tx_nb == 0, "UL retx has to have nof tx > 0\n"); if (not h.active) { @@ -169,20 +173,135 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& return SRSLTE_SUCCESS; } +int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) +{ + for (uint32_t cc = 0; cc < enb_ctxt.cell_params->size(); ++cc) { + for (const auto& ue_pair : enb_ctxt.ue_db) { + const auto& ue = *ue_pair.second; + const auto& dl_cc_res = sf_out.dl_cc_result[cc]; + const auto& ul_cc_res = sf_out.ul_cc_result[cc]; + uint16_t rnti = ue.rnti; + uint32_t ue_cc_idx = ue.enb_to_ue_cc_idx(cc); + + if (ue_cc_idx != 0) { + // only check for RAR/Msg3/Msg4 presence for a UE's PCell + continue; + } + + // TEST: RAR allocation + uint32_t rar_win_size = (*enb_ctxt.cell_params)[cc].prach_rar_window; + srslte::tti_interval rar_window{ue.prach_tti_rx + 3, ue.prach_tti_rx + 3 + rar_win_size}; + srslte::tti_point tti_tx_dl = to_tx_dl(sf_out.tti_rx); + + if (not rar_window.contains(tti_tx_dl)) { + CONDERROR(not ue.rar_tti_rx.is_valid() and tti_tx_dl > rar_window.stop(), + "rnti=0x%x RAR not scheduled within the RAR Window\n", + rnti); + for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].nof_rar_elems; ++i) { + CONDERROR(sf_out.dl_cc_result[cc].rar[i].dci.rnti == rnti, + "No RAR allocations allowed outside of user RAR window\n"); + } + } else { + // Inside RAR window + uint32_t nof_rars = ue.rar_tti_rx.is_valid() ? 1 : 0; + for (uint32_t i = 0; i < dl_cc_res.nof_rar_elems; ++i) { + for (uint32_t j = 0; j < dl_cc_res.rar[i].nof_grants; ++j) { + const auto& data = dl_cc_res.rar[i].msg3_grant[j].data; + if (data.prach_tti == (uint32_t)ue.prach_tti_rx.to_uint() and data.preamble_idx == ue.preamble_idx) { + CONDERROR(rnti != data.temp_crnti, "RAR grant C-RNTI does not match the expected.\n"); + nof_rars++; + } + } + } + CONDERROR(nof_rars > 1, "There was more than one RAR for the same user\n"); + } + + // TEST: Msg3 was allocated + if (ue.rar_tti_rx.is_valid() and not ue.msg3_tti_rx.is_valid()) { + // RAR scheduled, Msg3 not yet scheduled + srslte::tti_point expected_msg3_tti_rx = ue.rar_tti_rx + MSG3_DELAY_MS; + CONDERROR(expected_msg3_tti_rx < sf_out.tti_rx, "No UL msg3 alloc was made\n"); + + if (expected_msg3_tti_rx == sf_out.tti_rx) { + // Msg3 should exist + uint32_t msg3_count = 0; + for (uint32_t i = 0; i < ul_cc_res.nof_dci_elems; ++i) { + if (ul_cc_res.pusch[i].dci.rnti == rnti) { + msg3_count++; + CONDERROR(ul_cc_res.pusch[i].needs_pdcch, "Msg3 allocations do not require PDCCH\n"); + CONDERROR(ue.msg3_riv != ul_cc_res.pusch[i].dci.type2_alloc.riv, + "The Msg3 was not allocated in the expected PRBs.\n"); + } + } + CONDERROR(msg3_count == 0, "Msg3 was not transmitted.\n"); + CONDERROR(msg3_count > 1, "Only one Msg3 allower per user.\n"); + } + } + + // TEST: Check Msg4 + if (ue.msg3_tti_rx.is_valid() and not ue.msg4_tti_rx.is_valid()) { + // Msg3 scheduled, but Msg4 not yet scheduled + uint32_t msg4_count = 0; + for (uint32_t i = 0; i < dl_cc_res.nof_data_elems; ++i) { + if (dl_cc_res.data[i].dci.rnti == rnti) { + CONDERROR(to_tx_dl(sf_out.tti_rx) < to_tx_ul(ue.msg3_tti_rx), + "Msg4 cannot be scheduled without Msg3 being tx\n"); + for (uint32_t j = 0; j < dl_cc_res.data[i].nof_pdu_elems[0]; ++j) { + if (dl_cc_res.data[i].pdu[0][j].lcid == (uint32_t)srslte::dl_sch_lcid::CON_RES_ID) { + // ConRes found + CONDERROR(dl_cc_res.data[i].dci.format != SRSLTE_DCI_FORMAT1, "ConRes must be format1\n"); + msg4_count++; + } + } + CONDERROR(msg4_count == 0, "No ConRes CE was scheduled in Msg4\n"); + } + } + CONDERROR(msg4_count > 1, "Duplicate ConRes CE for the same rnti\n"); + } + + if (not ue.msg4_tti_rx.is_valid()) { + // TEST: No UL allocs except for Msg3 before Msg4 + for (uint32_t i = 0; i < ul_cc_res.nof_dci_elems; ++i) { + if (ul_cc_res.pusch[i].dci.rnti == rnti) { + CONDERROR(not ue.rar_tti_rx.is_valid(), "No UL allocs before RAR allowed\n"); + srslte::tti_point expected_msg3_tti = ue.rar_tti_rx + MSG3_DELAY_MS; + CONDERROR(expected_msg3_tti > sf_out.tti_rx, "No UL allocs before Msg3 is scheduled\n"); + if (expected_msg3_tti < sf_out.tti_rx) { + bool msg3_retx = + ((ue.msg3_tti_rx - expected_msg3_tti) % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS)) == 0; + CONDERROR(not msg3_retx, "No UL txs allowed except for Msg3 before user received Msg4\n"); + } + } + } + + // TEST: No DL allocs before Msg3 + if (not ue.msg3_tti_rx.is_valid()) { + for (uint32_t i = 0; i < dl_cc_res.nof_data_elems; ++i) { + CONDERROR(dl_cc_res.data[i].dci.rnti == rnti, "No DL data allocs allowed before Msg3 is scheduled\n"); + } + } + } + } + } + + return SRSLTE_SUCCESS; +} + int test_all_ues(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) { - // for (uint32_t cc = 0; cc < enb_ctxt.cell_params->size(); ++cc) { - // for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].nof_data_elems; ++i) { - // const sched_interface::dl_sched_data_t& data = sf_out.dl_cc_result[cc].data[i]; - // CONDERROR( - // enb_ctxt.ue_db.count(data.dci.rnti) == 0, "Allocated DL grant for non-existent rnti=0x%x\n", - // data.dci.rnti); - // TESTASSERT(test_pdsch_grant(*enb_ctxt.ue_db.at(data.dci.rnti), sf_out.tti_rx, cc, data) == SRSLTE_SUCCESS); - // } - // } + for (uint32_t cc = 0; cc < enb_ctxt.cell_params->size(); ++cc) { + for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].nof_data_elems; ++i) { + const sched_interface::dl_sched_data_t& data = sf_out.dl_cc_result[cc].data[i]; + CONDERROR( + enb_ctxt.ue_db.count(data.dci.rnti) == 0, "Allocated DL grant for non-existent rnti=0x%x\n", data.dci.rnti); + TESTASSERT(test_pdsch_grant(*enb_ctxt.ue_db.at(data.dci.rnti), sf_out.tti_rx, cc, data) == SRSLTE_SUCCESS); + } + } TESTASSERT(test_ul_sched_result(enb_ctxt, sf_out) == SRSLTE_SUCCESS); + TESTASSERT(test_ra(enb_ctxt, sf_out) == SRSLTE_SUCCESS); + return SRSLTE_SUCCESS; } diff --git a/srsenb/test/mac/sched_ue_ded_test_suite.h b/srsenb/test/mac/sched_ue_ded_test_suite.h index c2869e51a..802ae220f 100644 --- a/srsenb/test/mac/sched_ue_ded_test_suite.h +++ b/srsenb/test/mac/sched_ue_ded_test_suite.h @@ -57,6 +57,16 @@ int test_pdsch_grant(const sim_ue_ctxt_t& ue_ctxt, */ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out); +/** + * Checks whether the RAR, Msg3, Msg4 were scheduled within the expected windows. Current tests: + * - RAR alloc falls within RAR window and only takes place once per user + * - No UL allocs before Msg4 that are not Msg3 + * - Msg3 is allocated in expected TTI, without PDCCH, and PRBs advertised in RAR + * - First Data allocation happens after Msg3 is ACKed, and contains a ConRes CE + * - No RARs are allocated with wrong enb_cc_idx, preamble_idx or wrong user + */ +int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out); + /** * Call all tests that depend on the UE internal state for all registered UEs in the eNB * @param enb_ctxt current eNB state, including list of UEs diff --git a/srsenb/test/mac/scheduler_test_common.cc b/srsenb/test/mac/scheduler_test_common.cc index 158215201..9afea19f8 100644 --- a/srsenb/test/mac/scheduler_test_common.cc +++ b/srsenb/test/mac/scheduler_test_common.cc @@ -60,13 +60,15 @@ ue_ctxt_test::ue_ctxt_test(uint16_t rnti_, uint32_t preamble_idx_, srslte::tti_point prach_tti_, const ue_ctxt_test_cfg& cfg_, - const std::vector& cell_params_) : + const std::vector& cell_params_, + ue_sim& ue_ctxt_) : sim_cfg(cfg_), rnti(rnti_), prach_tti(prach_tti_), preamble_idx(preamble_idx_), cell_params(cell_params_), - current_tti_rx(prach_tti_) + current_tti_rx(prach_tti_), + ue_ctxt(&ue_ctxt_) { set_cfg(cfg_.ue_cfg); } @@ -80,10 +82,6 @@ int ue_ctxt_test::set_cfg(const sched::ue_cfg_t& ue_cfg_) active_ccs.emplace_back(); active_ccs.back().ue_cc_idx = active_ccs.size() - 1; active_ccs.back().enb_cc_idx = cc.enb_cc_idx; - for (size_t i = 0; i < active_ccs.back().dl_harqs.size(); ++i) { - active_ccs.back().dl_harqs[i].pid = i; - active_ccs.back().ul_harqs[i].pid = i; - } } else { CONDERROR(cc.enb_cc_idx != active_ccs[ue_cc_idx].enb_cc_idx, "changing ccs not supported\n"); } @@ -129,17 +127,19 @@ int ue_ctxt_test::fwd_pending_acks(sched* sched_ptr) if (p.tti_ack > current_tti_rx) { break; } - auto& h = active_ccs[p.ue_cc_idx].dl_harqs[p.pid]; + auto& h = ue_ctxt->get_ctxt().cc_list[p.ue_cc_idx].dl_harqs[p.pid]; CONDERROR(not h.active, "The ACKed DL Harq pid=%d is not active\n", h.pid); - CONDERROR(h.tti_tx + FDD_HARQ_DELAY_DL_MS != p.tti_ack, "dl ack hasn't arrived when expected\n"); + CONDERROR(to_tx_dl(h.last_tti_rx) + FDD_HARQ_DELAY_DL_MS != p.tti_ack, "dl ack hasn't arrived when expected\n"); CONDERROR(sched_ptr->dl_ack_info(current_tti_rx.to_uint(), rnti, p.cc_idx, p.tb, p.ack) <= 0, "The ACKed DL Harq pid=%d does not exist.\n", p.pid); if (p.ack) { - h.active = false; log_h->info("DL ACK tti=%u rnti=0x%x pid=%d\n", current_tti_rx.to_uint(), rnti, p.pid); } + if (p.ack or ue_ctxt->get_ctxt().is_last_dl_retx(p.ue_cc_idx, p.pid)) { + h.active = false; + } pending_dl_acks.pop(); } @@ -149,14 +149,13 @@ int ue_ctxt_test::fwd_pending_acks(sched* sched_ptr) if (p.tti_ack > current_tti_rx) { break; } - auto& h = active_ccs[p.ue_cc_idx].ul_harqs[p.pid]; + auto& h = ue_ctxt->get_ctxt().cc_list[p.ue_cc_idx].ul_harqs[p.pid]; CONDERROR(not h.active, "The ACKed UL Harq pid=%d is not active\n", h.pid); - CONDERROR(h.tti_tx != p.tti_ack, "UL CRC wasn't set when expected\n"); + CONDERROR(to_tx_ul(h.last_tti_rx) != p.tti_ack, "UL CRC wasn't set when expected\n"); CONDERROR(sched_ptr->ul_crc_info(current_tti_rx.to_uint(), rnti, p.cc_idx, p.ack) != SRSLTE_SUCCESS, "Failed UL ACK\n"); if (p.ack) { - h.active = false; log_h->info("UL ACK tti=%u rnti=0x%x pid=%d\n", current_tti_rx.to_uint(), rnti, p.pid); } pending_ul_acks.pop(); @@ -170,123 +169,11 @@ int ue_ctxt_test::test_sched_result(uint32_t enb_cc_idx, const sched::ul_sched_res_t& ul_result) { cc_result result{enb_cc_idx, &dl_result, &ul_result}; - TESTASSERT(test_harqs(result) == SRSLTE_SUCCESS); - TESTASSERT(test_ra(result) == SRSLTE_SUCCESS); TESTASSERT(test_scell_activation(result) == SRSLTE_SUCCESS); TESTASSERT(schedule_acks(result) == SRSLTE_SUCCESS); return SRSLTE_SUCCESS; } -/** - * Tests whether the RAR and Msg3 were scheduled within the expected windows. Individual tests: - * - No UL allocs before Msg3 - * - No DL data allocs before Msg3 is correctly ACKed - * - RAR alloc falls within RAR window and is unique per user - * - Msg3 is allocated in expected TTI, without PDCCH, and correct rnti - * - First Data allocation happens after Msg3, and contains a ConRes - * - No RARs are allocated with wrong enb_cc_idx, preamble_idx or wrong user - * TODO: - * - check Msg3 PRBs match the ones advertised in the RAR - */ -int ue_ctxt_test::test_ra(cc_result result) -{ - if (result.enb_cc_idx != active_ccs[0].enb_cc_idx) { - // only check for RAR/Msg3 presence for a UE's PCell - return SRSLTE_SUCCESS; - } - - /* TEST: RAR allocation */ - uint32_t rar_win_size = cell_params[result.enb_cc_idx].prach_rar_window; - std::array rar_window = {prach_tti + 3, prach_tti + 3 + rar_win_size}; - srslte::tti_point tti_tx_dl = to_tx_dl(current_tti_rx); - srslte::tti_point tti_tx_ul = to_tx_ul(current_tti_rx); - bool is_in_rar_window = tti_tx_dl >= rar_window[0] and tti_tx_dl <= rar_window[1]; - - if (not is_in_rar_window) { - CONDERROR(not rar_tti.is_valid() and tti_tx_dl > rar_window[1], - "rnti=0x%x RAR not scheduled within the RAR Window\n", - rnti); - for (uint32_t i = 0; i < result.dl_result->nof_rar_elems; ++i) { - CONDERROR(result.dl_result->rar[i].dci.rnti == rnti, "No RAR allocations allowed outside of user RAR window\n"); - } - } else { - // Inside RAR window - for (uint32_t i = 0; i < result.dl_result->nof_rar_elems; ++i) { - for (uint32_t j = 0; j < result.dl_result->rar[i].nof_grants; ++j) { - const auto& data = result.dl_result->rar[i].msg3_grant[j].data; - if (data.prach_tti == (uint32_t)prach_tti.to_uint() and data.preamble_idx == preamble_idx) { - CONDERROR(rar_tti.is_valid(), "There was more than one RAR for the same user\n"); - CONDERROR(rnti != data.temp_crnti, "RAR grant C-RNTI does not match the expected.\n"); - msg3_riv = result.dl_result->rar[i].msg3_grant[j].grant.rba; - rar_tti = tti_tx_dl; - } - } - } - } - - /* TEST: Check Msg3 */ - if (rar_tti.is_valid() and not msg3_tti.is_valid()) { - // RAR scheduled, Msg3 not yet scheduled - srslte::tti_point expected_msg3_tti = rar_tti + FDD_HARQ_DELAY_DL_MS + MSG3_DELAY_MS; - CONDERROR(expected_msg3_tti < tti_tx_ul and not msg3_tti.is_valid(), "No UL msg3 alloc was made\n"); - - if (expected_msg3_tti == tti_tx_ul) { - // Msg3 should exist - for (uint32_t i = 0; i < result.ul_result->nof_dci_elems; ++i) { - if (result.ul_result->pusch[i].dci.rnti == rnti) { - CONDERROR(msg3_tti.is_valid(), "Only one Msg3 allowed per user\n"); - CONDERROR(result.ul_result->pusch[i].needs_pdcch, "Msg3 allocations do not require PDCCH\n"); - CONDERROR(msg3_riv != result.ul_result->pusch[i].dci.type2_alloc.riv, - "The Msg3 was not allocated in the expected PRBs.\n"); - msg3_tti = tti_tx_ul; - } - } - } - } - - /* TEST: Check Msg4 */ - if (msg3_tti.is_valid() and not msg4_tti.is_valid()) { - // Msg3 scheduled, but Msg4 not yet scheduled - for (uint32_t i = 0; i < result.dl_result->nof_data_elems; ++i) { - if (result.dl_result->data[i].dci.rnti == rnti) { - CONDERROR(current_tti_rx < msg3_tti, "Msg4 cannot be scheduled without Msg3 being tx\n"); - for (uint32_t j = 0; j < result.dl_result->data[i].nof_pdu_elems[0]; ++j) { - if (result.dl_result->data[i].pdu[0][j].lcid == (uint32_t)srslte::dl_sch_lcid::CON_RES_ID) { - // ConRes found - CONDERROR(result.dl_result->data[i].dci.format != SRSLTE_DCI_FORMAT1, "ConRes must be format1\n"); - CONDERROR(msg4_tti.is_valid(), "Duplicate ConRes CE for the same rnti\n"); - msg4_tti = tti_tx_dl; - } - } - } - } - } - - /* TEST: Txs out of place */ - if (not msg4_tti.is_valid()) { - // Msg4 not yet received by user - for (uint32_t i = 0; i < result.dl_result->nof_data_elems; ++i) { - CONDERROR(result.dl_result->data[i].dci.rnti == rnti, "No DL data allocs allowed before Msg4 is scheduled\n"); - } - if (msg3_tti.is_valid() and msg3_tti != tti_tx_ul) { - // Msg3 scheduled. No UL alloc allowed unless it is a newtx (the Msg3 itself) - for (uint32_t i = 0; i < result.ul_result->nof_dci_elems; ++i) { - // Needs PDCCH - filters out UL retxs - bool msg3_retx = ((tti_tx_ul - msg3_tti) % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS)) == 0; - CONDERROR(result.ul_result->pusch[i].dci.rnti == rnti and not msg3_retx, - "No UL txs allowed except for Msg3 before user received Msg4\n"); - } - } else if (not msg3_tti.is_valid()) { - // No Msg3 sched TTI - for (uint32_t i = 0; i < result.ul_result->nof_dci_elems; ++i) { - CONDERROR(result.ul_result->pusch[i].dci.rnti == rnti, "No UL newtxs allowed before user received Msg4\n"); - } - } - } - - return SRSLTE_SUCCESS; -} - /** * Tests whether the SCells are correctly activated. Individual tests: * - no DL and UL allocations in inactive carriers @@ -323,99 +210,6 @@ int ue_ctxt_test::test_scell_activation(cc_result result) return SRSLTE_SUCCESS; } -/** - * Sanity checks of the DCI values in the scheduling result for a given user. Current checks: - * - invalid ue_cc_idx<->enb_cc_idx matching in dl_result - * - reusing same pid too early (ACK still didn't arrive yet) - * - invalid rv value (nof retxs is incorrect) and ndi value - */ -int ue_ctxt_test::test_harqs(cc_result result) -{ - cc_ue_ctxt_test* cc = get_cc_state(result.enb_cc_idx); - if (cc == nullptr) { - // unsupported carrier - return SRSLTE_SUCCESS; - } - - /* Test DL Harqs */ - for (uint32_t i = 0; i < result.dl_result->nof_data_elems; ++i) { - const auto& data = result.dl_result->data[i]; - if (data.dci.rnti != rnti) { - continue; - } - - CONDERROR(data.dci.ue_cc_idx != cc->ue_cc_idx, "invalid ue_cc_idx=%d in sched result\n", data.dci.ue_cc_idx); - CONDERROR(data.dci.pid >= cc->dl_harqs.size(), "invalid pid\n"); - auto& h = cc->dl_harqs[data.dci.pid]; - uint32_t nof_retx = sched_utils::get_nof_retx(data.dci.tb[0].rv); // 0..3 - - if (h.nof_txs == 0 or h.ndi != data.dci.tb[0].ndi) { - // It is newtx - CONDERROR(nof_retx != 0, "Invalid rv index for new tx\n"); - - h.active = true; - h.nof_retxs = 0; - h.ndi = data.dci.tb[0].ndi; - h.tti_tx = to_tx_dl(current_tti_rx); - } else { - // it is retx - CONDERROR(sched_utils::get_rvidx(h.nof_retxs + 1) != (uint32_t)data.dci.tb[0].rv, "Invalid rv index for retx\n"); - CONDERROR(h.ndi != data.dci.tb[0].ndi, "Invalid ndi for retx\n"); - CONDERROR(not h.active, "retx for inactive dl harq pid=%d\n", h.pid); - CONDERROR(h.tti_tx > current_tti_rx, "harq pid=%d reused too soon\n", h.pid); - CONDERROR(h.nof_retxs + 1 > sim_cfg.ue_cfg.maxharq_tx, - "The number of retx=%d exceeded its max=%d\n", - h.nof_retxs + 1, - sim_cfg.ue_cfg.maxharq_tx); - - h.nof_retxs++; - h.tti_tx = to_tx_dl(current_tti_rx); - } - h.nof_txs++; - } - - /* Test UL Harqs */ - for (uint32_t i = 0; i < result.ul_result->nof_dci_elems; ++i) { - const auto& pusch = result.ul_result->pusch[i]; - if (pusch.dci.rnti != rnti) { - continue; - } - - CONDERROR(pusch.dci.ue_cc_idx != cc->ue_cc_idx, "invalid ue_cc_idx=%d in sched result\n", pusch.dci.ue_cc_idx); - auto& h = cc->ul_harqs[to_tx_ul(current_tti_rx).to_uint() % cc->ul_harqs.size()]; - uint32_t nof_retx = sched_utils::get_nof_retx(pusch.dci.tb.rv); // 0..3 - - if (h.nof_txs == 0 or h.ndi != pusch.dci.tb.ndi) { - // newtx - CONDERROR(nof_retx != 0, "Invalid rv index for new tx\n"); - - h.active = true; - h.nof_retxs = 0; - h.ndi = pusch.dci.tb.ndi; - } else { - if (pusch.needs_pdcch) { - // adaptive retx - } else { - // non-adaptive retx - CONDERROR(pusch.dci.type2_alloc.riv != h.riv, "Non-adaptive retx must keep the same riv\n"); - } - if (pusch.tbs > 0) { - CONDERROR(sched_utils::get_rvidx(h.nof_retxs + 1) != (uint32_t)pusch.dci.tb.rv, "Invalid rv index for retx\n"); - } - CONDERROR(h.ndi != pusch.dci.tb.ndi, "Invalid ndi for retx\n"); - CONDERROR(not h.active, "Re-tx allocated for rnti=0x%x inactive UL harq pid=%d\n", rnti, h.pid); - CONDERROR(h.tti_tx > current_tti_rx, "UL harq pid=%d was reused too soon\n", h.pid); - - h.nof_retxs++; - } - h.tti_tx = to_tx_ul(current_tti_rx); - h.riv = pusch.dci.type2_alloc.riv; - h.nof_txs++; - } - - return SRSLTE_SUCCESS; -} - int ue_ctxt_test::schedule_acks(cc_result result) { auto* cc = get_cc_state(result.enb_cc_idx); @@ -452,7 +246,7 @@ int ue_ctxt_test::schedule_acks(cc_result result) ack_data.cc_idx = result.enb_cc_idx; ack_data.ue_cc_idx = pusch.dci.ue_cc_idx; ack_data.tb = 0; - ack_data.pid = to_tx_ul(current_tti_rx).to_uint() % cc->ul_harqs.size(); + ack_data.pid = to_tx_ul(current_tti_rx).to_uint() % (FDD_HARQ_DELAY_DL_MS + FDD_HARQ_DELAY_UL_MS); uint32_t nof_retx = sched_utils::get_nof_retx(pusch.dci.tb.rv); // 0..3 ack_data.ack = randf() < sim_cfg.prob_ul_ack_mask[nof_retx % sim_cfg.prob_ul_ack_mask.size()]; @@ -475,10 +269,11 @@ int user_state_sched_tester::add_user(uint16_t rnti, uint32_t preamble_idx, cons cell_params[cfg_.ue_cfg.supported_cc_list[0].enb_cc_idx].prach_config, tic.to_uint(), -1), "New user added in a non-PRACH TTI\n"); TESTASSERT(users.count(rnti) == 0); - ue_ctxt_test ue{rnti, preamble_idx, srslte::tti_point{tic.to_uint()}, cfg_, cell_params}; + sim_users.add_user(rnti, cfg_.ue_cfg, tic, preamble_idx); + + ue_ctxt_test ue{rnti, preamble_idx, tic, cfg_, cell_params, sim_users.at(rnti)}; users.insert(std::make_pair(rnti, ue)); - sim_users.add_user(rnti, cfg_.ue_cfg, tic); return SRSLTE_SUCCESS; } @@ -535,24 +330,12 @@ int user_state_sched_tester::test_ctrl_info(uint32_t } } - /* TEST: All DL allocs have a correct rnti */ - for (uint32_t i = 0; i < dl_result.nof_data_elems; ++i) { - uint16_t rnti = dl_result.data[i].dci.rnti; - CONDERROR(users.count(rnti) == 0, "The user rnti=0x%x allocated in DL does not exist\n", rnti); - } - - /* TEST: All UL allocs have a correct rnti */ - for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) { - uint16_t rnti = ul_result.pusch[i].dci.rnti; - CONDERROR(users.count(rnti) == 0, "The user rnti=0x%x allocated in UL does not exist\n", rnti); - } - return SRSLTE_SUCCESS; } int user_state_sched_tester::test_all(const sf_output_res_t& sf_out, uint32_t enb_cc_idx) { - // Perform UE-dedicated result tests + // Perform UE-dedicated sched result tests sim_enb_ctxt_t enb_ctxt; enb_ctxt.cell_params = &cell_params; enb_ctxt.ue_db = sim_users.get_ues_ctxt(); diff --git a/srsenb/test/mac/scheduler_test_common.h b/srsenb/test/mac/scheduler_test_common.h index 79bb4f1c9..8bbfd2da3 100644 --- a/srsenb/test/mac/scheduler_test_common.h +++ b/srsenb/test/mac/scheduler_test_common.h @@ -64,18 +64,6 @@ struct ue_ctxt_test { struct cc_ue_ctxt_test { uint32_t ue_cc_idx = 0; uint32_t enb_cc_idx = 0; - // Harq State - struct harq_state_t { - uint32_t pid = 0; - srslte::tti_point tti_tx; - bool active = false; - bool ndi = false; - uint32_t nof_retxs = 0; - uint32_t nof_txs = 0; - uint32_t riv = 0; - }; - std::array dl_harqs = {}; - std::array ul_harqs = {}; }; std::vector active_ccs; @@ -85,7 +73,8 @@ struct ue_ctxt_test { uint32_t preamble_idx_, srslte::tti_point prach_tti, const ue_ctxt_test_cfg& cfg_, - const std::vector& cell_params_); + const std::vector& cell_params_, + ue_sim& ue_ctxt_); int set_cfg(const sched::ue_cfg_t& ue_cfg_); cc_ue_ctxt_test* get_cc_state(uint32_t enb_cc_idx); @@ -104,9 +93,6 @@ private: const sched::dl_sched_res_t* dl_result; const sched::ul_sched_res_t* ul_result; }; - //! Test the timing of RAR, Msg3, Msg4 - int test_ra(cc_result result); - int test_harqs(cc_result result); //! Test correct activation of SCells int test_scell_activation(cc_result result); int schedule_acks(cc_result result); @@ -120,6 +106,7 @@ private: bool operator<(const pending_ack_t& other) const { return tti_ack > other.tti_ack; } }; std::priority_queue pending_dl_acks, pending_ul_acks; + ue_sim* ue_ctxt; }; class user_state_sched_tester diff --git a/srsenb/test/mac/scheduler_test_rand.cc b/srsenb/test/mac/scheduler_test_rand.cc index a8c5d840e..56b3eaac5 100644 --- a/srsenb/test/mac/scheduler_test_rand.cc +++ b/srsenb/test/mac/scheduler_test_rand.cc @@ -440,7 +440,7 @@ int main() srsenb::set_randseed(seed); printf("This is the chosen seed: %u\n", seed); - srslte::logmap::set_default_log_level(srslte::LOG_LEVEL_INFO); + srslte::logmap::set_default_log_level(srslte::LOG_LEVEL_DEBUG); uint32_t N_runs = 1, nof_ttis = 10240 + 10; for (uint32_t n = 0; n < N_runs; ++n) {