From b44754f0ae6291a3d928c6835d248dc95926b64b Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Sat, 22 Feb 2020 19:44:38 +0000 Subject: [PATCH] the CA and random sched testers now use same structs and common interface. --- srsenb/test/mac/CMakeLists.txt | 10 - srsenb/test/mac/scheduler_ca_test.cc | 99 ----- srsenb/test/mac/scheduler_test.cc | 141 ------- srsenb/test/mac/scheduler_test_common.cc | 136 ++++++- srsenb/test/mac/scheduler_test_common.h | 28 +- srsenb/test/mac/scheduler_test_rand.cc | 489 +++++------------------ srsenb/test/mac/scheduler_test_utils.h | 48 ++- 7 files changed, 267 insertions(+), 684 deletions(-) delete mode 100644 srsenb/test/mac/scheduler_test.cc diff --git a/srsenb/test/mac/CMakeLists.txt b/srsenb/test/mac/CMakeLists.txt index 540d865e0..8a7299db4 100644 --- a/srsenb/test/mac/CMakeLists.txt +++ b/srsenb/test/mac/CMakeLists.txt @@ -18,16 +18,6 @@ # and at http://www.gnu.org/licenses/. # -# Scheduler test -add_executable(scheduler_test scheduler_test.cc) -target_link_libraries(scheduler_test srsenb_mac - srsenb_phy - srslte_common - srslte_phy - rrc_asn1 - ${CMAKE_THREAD_LIBS_INIT} - ${Boost_LIBRARIES}) - # Scheduler test random add_executable(scheduler_test_rand scheduler_test_rand.cc scheduler_test_common.cc) target_link_libraries(scheduler_test_rand srsenb_mac diff --git a/srsenb/test/mac/scheduler_ca_test.cc b/srsenb/test/mac/scheduler_ca_test.cc index 8adb19916..533b369f4 100644 --- a/srsenb/test/mac/scheduler_ca_test.cc +++ b/srsenb/test/mac/scheduler_ca_test.cc @@ -55,104 +55,8 @@ class sched_ca_tester : public common_sched_tester { public: int process_tti_events(const tti_ev& tti_events); - int run_tti(const tti_ev& tti_events) override; }; -int sched_ca_tester::process_tti_events(const tti_ev& tti_ev) -{ - for (const tti_ev::user_cfg_ev& ue_ev : tti_ev.user_updates) { - // There is a new configuration - if (ue_ev.ue_cfg != nullptr) { - if (not ue_tester->user_exists(ue_ev.rnti)) { - // new user - TESTASSERT(add_user(ue_ev.rnti, *ue_ev.ue_cfg) == SRSLTE_SUCCESS); - } else { - // reconfiguration - TESTASSERT(ue_cfg(ue_ev.rnti, *ue_ev.ue_cfg) == SRSLTE_SUCCESS); - ue_tester->user_reconf(ue_ev.rnti, *ue_ev.ue_cfg); - } - } - - // There is a user to remove - if (ue_ev.rem_user) { - // bearer_ue_rem(ue_ev.rnti, 0); - ue_rem(ue_ev.rnti); - ue_tester->rem_user(ue_ev.rnti); - log_global->info("[TESTER] Removing user rnti=0x%x\n", ue_ev.rnti); - } - - // configure carriers - if (ue_ev.bearer_cfg != nullptr) { - CONDERROR(not ue_tester->user_exists(ue_ev.rnti), "User rnti=0x%x does not exist\n", ue_ev.rnti); - // TODO: Instantiate more bearers - bearer_ue_cfg(ue_ev.rnti, 0, ue_ev.bearer_cfg.get()); - } - - // push UL SRs and DL packets - if (ue_ev.buffer_ev != nullptr) { - auto* user = ue_tester->get_user_state(ue_ev.rnti); - CONDERROR(user == nullptr, "TESTER ERROR: Trying to schedule data for user that does not exist\n"); - - if (ue_ev.buffer_ev->dl_data > 0) { - // If Msg3 has already been received - if (user->msg3_tic.is_valid() and user->msg3_tic <= tic) { - // If Msg4 not yet sent, allocate data in SRB0 buffer - uint32_t lcid = (user->msg4_tic.is_valid()) ? 2 : 0; - uint32_t pending_dl_new_data = ue_db[ue_ev.rnti].get_pending_dl_new_data(); - if (lcid == 2 and not user->drb_cfg_flag) { - // If RRCSetup finished - if (pending_dl_new_data == 0) { - // setup lcid==2 bearer - sched::ue_bearer_cfg_t cfg = {}; - cfg.direction = ue_bearer_cfg_t::BOTH; - ue_tester->bearer_cfg(ue_ev.rnti, 2, cfg); - bearer_ue_cfg(ue_ev.rnti, 2, &cfg); - } else { - // Let SRB0 get emptied - continue; - } - } - // Update DL buffer - uint32_t tot_dl_data = pending_dl_new_data + ue_ev.buffer_ev->dl_data; // TODO: derive pending based on rx - dl_rlc_buffer_state(ue_ev.rnti, lcid, tot_dl_data, 0); // TODO: Check retx_queue - } - } - - if (ue_ev.buffer_ev->sr_data > 0 and user->drb_cfg_flag) { - uint32_t tot_ul_data = - ue_db[ue_ev.rnti].get_pending_ul_new_data(tti_info.tti_params.tti_tx_ul) + ue_ev.buffer_ev->sr_data; - uint32_t lcid = 2; - ul_bsr(ue_ev.rnti, lcid, tot_ul_data, true); - } - } - } - return SRSLTE_SUCCESS; -} - -int sched_ca_tester::run_tti(const tti_ev& tti_events) -{ - new_test_tti(); - log_global->info("[TESTER] ---- tti=%u | nof_ues=%zd ----\n", tic.tti_rx(), ue_db.size()); - - process_tti_events(tti_events); - process_ack_txs(); - // before_sched(); - - // Call scheduler for all carriers - tti_info.dl_sched_result.resize(sched_cell_params.size()); - for (uint32_t i = 0; i < sched_cell_params.size(); ++i) { - dl_sched(tti_info.tti_params.tti_tx_dl, i, tti_info.dl_sched_result[i]); - } - tti_info.ul_sched_result.resize(sched_cell_params.size()); - for (uint32_t i = 0; i < sched_cell_params.size(); ++i) { - ul_sched(tti_info.tti_params.tti_tx_ul, i, tti_info.ul_sched_result[i]); - } - - process_results(); - schedule_acks(); - return SRSLTE_SUCCESS; -} - /****************************** * Scheduler Tests *****************************/ @@ -176,9 +80,6 @@ sim_sched_args generate_default_sim_args(uint32_t nof_prb, uint32_t nof_ccs) cell_cfg[1].scell_list[0].enb_cc_idx = 0; sim_args.cell_cfg = std::move(cell_cfg); - sim_args.bearer_cfg = {}; - sim_args.bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; - /* Setup Derived Params */ sim_args.ue_cfg.supported_cc_list.resize(nof_ccs); for (uint32_t i = 0; i < sim_args.ue_cfg.supported_cc_list.size(); ++i) { diff --git a/srsenb/test/mac/scheduler_test.cc b/srsenb/test/mac/scheduler_test.cc deleted file mode 100644 index aaddd0224..000000000 --- a/srsenb/test/mac/scheduler_test.cc +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2013-2019 Software Radio Systems Limited - * - * This file is part of srsLTE. - * - * srsLTE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsLTE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#include - -#include "srsenb/hdr/phy/phy.h" -#include "srsenb/hdr/stack/mac/mac.h" - -#include "srslte/common/log_filter.h" -#include "srslte/interfaces/enb_interfaces.h" -#include "srslte/interfaces/sched_interface.h" -#include "srslte/phy/utils/debug.h" -#include "srslte/radio/radio.h" - -uint8_t sib1_payload[18] = - {0x60, 0x40, 0x04, 0x03, 0x00, 0x01, 0x1a, 0x2d, 0x00, 0x18, 0x02, 0x81, 0x80, 0x42, 0x0c, 0x80, 0x00, 0x00}; -uint8_t sib2_payload[41] = {0x00, 0x80, 0x1c, 0x31, 0x18, 0x6f, 0xe1, 0x20, 0x00, 0x35, 0x84, 0x8c, 0xe2, 0xd0, - 0x00, 0x02, 0x00, 0x78, 0xee, 0x31, 0x6a, 0xa5, 0x37, 0x30, 0xa0, 0x70, 0xc9, 0x49, - 0xfa, 0x8d, 0xd2, 0x78, 0x1a, 0x02, 0x77, 0x4a, 0x92, 0x40, 0x00, 0x00, 0x00}; - -// Define dummy RLC always transmitts -class rlc : public srsenb::rlc_interface_mac -{ -public: - uint32_t get_buffer_state(uint16_t rnti, uint32_t lcid) { return 1; } - - int read_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) - { - for (uint32_t i = 0; i < nof_bytes; i++) { - payload[i] = i; - } - return nof_bytes; - } - - void read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) {} - - void read_pdu_bcch_dlsch(uint32_t sib_index, uint8_t payload[srsenb::sched_interface::MAX_SIB_PAYLOAD_LEN]) - { - switch (sib_index) { - case 0: - memcpy(payload, sib1_payload, 18); - break; - case 1: - memcpy(payload, sib2_payload, 41); - break; - } - } - - void write_pdu(uint16_t rnti, uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) {} - -private: -}; - -// Create classes -srslte::log_filter log_out("ALL"); -srsenb::sched my_sched; -srsenb::dl_metric_rr dl_metric; -srsenb::ul_metric_rr ul_metric; -rlc my_rlc; - -int main(int argc, char* argv[]) -{ - - log_out.set_level(srslte::LOG_LEVEL_INFO); - - /* Set PHY cell configuration */ - srslte_cell_t cell_cfg_phy; - cell_cfg_phy.id = 1; - cell_cfg_phy.cp = SRSLTE_CP_NORM; - cell_cfg_phy.nof_ports = 1; - cell_cfg_phy.nof_prb = 25; - cell_cfg_phy.phich_length = SRSLTE_PHICH_NORM; - cell_cfg_phy.phich_resources = SRSLTE_PHICH_R_1; - - std::vector cell_cfg(1); - - /* Set MAC cell configuration */ - cell_cfg[0] = {}; - cell_cfg[0].cell = cell_cfg_phy; - cell_cfg[0].sibs[0].len = 18; - cell_cfg[0].sibs[0].period_rf = 8; - cell_cfg[0].sibs[1].len = 41; - cell_cfg[0].sibs[1].period_rf = 16; - cell_cfg[0].si_window_ms = 40; - - my_sched.init(nullptr); - my_sched.cell_cfg(cell_cfg); - - srsenb::sched_interface::dl_sched_res_t sched_result_dl; - srsenb::sched_interface::ul_sched_res_t sched_result_ul; - - srsenb::sched_interface::ue_cfg_t ue_cfg = {}; - ue_cfg.supported_cc_list.emplace_back(); - ue_cfg.supported_cc_list.back().enb_cc_idx = 0; - uint16_t rnti = 30; - - ue_cfg.aperiodic_cqi_period = 40; - ue_cfg.maxharq_tx = 5; - - srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; - bzero(&bearer_cfg, sizeof(srsenb::sched_interface::ue_bearer_cfg_t)); - bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; - - my_sched.ue_cfg(rnti, ue_cfg); - my_sched.bearer_ue_cfg(rnti, 0, &bearer_cfg); - // my_sched.dl_rlc_buffer_state(rnti, 0, 1e6, 0); - my_sched.ul_bsr(rnti, 0, 1e6f, true); - - bool running = true; - uint32_t tti = 0; - while (running) { - log_out.step(tti); - if (tti > 50) { - running = false; - } - my_sched.dl_sched(tti, 0, sched_result_dl); - my_sched.ul_sched(tti, 0, sched_result_ul); - tti = (tti + 1) % 10240; - if (tti >= 4) { - my_sched.ul_crc_info(tti, rnti, 0, tti % 2); - } - } -} diff --git a/srsenb/test/mac/scheduler_test_common.cc b/srsenb/test/mac/scheduler_test_common.cc index ec80b2746..a1d50c3e2 100644 --- a/srsenb/test/mac/scheduler_test_common.cc +++ b/srsenb/test/mac/scheduler_test_common.cc @@ -329,6 +329,9 @@ int user_state_sched_tester::add_user(uint16_t r uint32_t preamble_idx, const srsenb::sched_interface::ue_cfg_t& ue_cfg) { + CONDERROR(!srslte_prach_tti_opportunity_config_fdd( + cell_params[ue_cfg.supported_cc_list[0].enb_cc_idx].prach_config, tic.tti_rx(), -1), + "[TESTER] New user added in a non-PRACH TTI\n"); TESTASSERT(users.count(rnti) == 0); ue_state ue; ue.user_cfg = ue_cfg; @@ -368,16 +371,14 @@ void user_state_sched_tester::rem_user(uint16_t rnti) /** * Tests whether the RAR and Msg3 were scheduled within the expected windows. Individual tests: - * - a user does not get UL allocs before Msg3 - * - a user does not get DL data allocs before Msg3 is correctly received - * - a user RAR alloc falls within its RAR window - * - There is only one RAR in the RAR window for a given user + * - 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 - * - space is enough for Msg3 */ int user_state_sched_tester::test_ra(uint32_t enb_cc_idx, const sched_interface::dl_sched_res_t& dl_result, @@ -392,9 +393,10 @@ int user_state_sched_tester::test_ra(uint32_t enb_ // No UL allocations before Msg3 for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) { if (ul_result.pusch[i].dci.rnti == rnti) { - CONDERROR(ul_result.pusch[i].needs_pdcch and not userinfo.msg3_tic.is_valid(), - "[TESTER] No UL data allocation allowed before Msg3\n"); - CONDERROR(not userinfo.rar_tic.is_valid(), "[TESTER] No UL allocs allowed before RAR\n"); + CONDERROR(not userinfo.rar_tic.is_valid(), "No UL allocs allowed before RAR\n"); + CONDERROR(ul_result.pusch[i].needs_pdcch and not userinfo.msg3_tic.is_valid() and + userinfo.msg3_tic.tti_rx() > tic.tti_rx(), + "No UL newtxs allocs allowed before Msg3 Rx\n"); tti_counter msg3_tic = userinfo.rar_tic + FDD_HARQ_DELAY_MS + MSG3_DELAY_MS; CONDERROR(msg3_tic > tic.tic_tx_ul(), "No UL allocs allowed before Msg3 alloc\n"); } @@ -403,8 +405,8 @@ int user_state_sched_tester::test_ra(uint32_t enb_ // No DL data allocations before Msg3 is received for (uint32_t i = 0; i < dl_result.nof_data_elems; ++i) { if (dl_result.data[i].dci.rnti == rnti) { - CONDERROR(not userinfo.msg3_tic.is_valid(), "[TESTER] No DL data alloc allowed before Msg3 alloc\n"); - CONDERROR(tic < userinfo.msg3_tic, "[TESTER] Msg4 cannot be tx without Msg3 being received\n"); + CONDERROR(not userinfo.msg3_tic.is_valid(), "No DL data alloc allowed before Msg3 alloc\n"); + CONDERROR(tic + FDD_HARQ_DELAY_MS < userinfo.msg3_tic, "Msg4 cannot be tx without Msg3 being acked\n"); } } @@ -420,7 +422,7 @@ int user_state_sched_tester::test_ra(uint32_t enb_ tti_counter tic_tx_dl = tic.tic_tx_dl(); CONDERROR(not userinfo.rar_tic.is_valid() and tic.tic_tx_dl() > rar_window[1], - "[TESTER] RAR not scheduled within the RAR Window\n"); + "RAR not scheduled within the RAR Window\n"); if (tic_tx_dl <= rar_window[1] and tic_tx_dl >= rar_window[0]) { // Inside RAR window for (uint32_t i = 0; i < dl_result.nof_rar_elems; ++i) { @@ -428,23 +430,24 @@ int user_state_sched_tester::test_ra(uint32_t enb_ auto& data = dl_result.rar[i].msg3_grant[j].data; if (data.prach_tti == (uint32_t)userinfo.prach_tic.tti_rx() and data.preamble_idx == userinfo.preamble_idx) { CONDERROR(userinfo.rar_tic.is_valid(), "There was more than one RAR for the same user\n"); - userinfo.rar_tic = tic_tx_dl; + CONDERROR(rnti != data.temp_crnti, "[TESTER] RAR grant C-RNTI does not match the expected.\n"); + userinfo.msg3_riv = dl_result.rar[i].msg3_grant[j].grant.rba; + userinfo.rar_tic = tic_tx_dl; } } } } - // Check whether Msg3 was allocated in expected TTI + /* TEST: Check Msg3 */ if (userinfo.rar_tic.is_valid()) { tti_counter expected_msg3_tti = userinfo.rar_tic + FDD_HARQ_DELAY_MS + MSG3_DELAY_MS; if (expected_msg3_tti == tic.tic_tx_ul()) { for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) { if (ul_result.pusch[i].dci.rnti == rnti) { CONDERROR(userinfo.msg3_tic.is_valid(), "Only one Msg3 allowed per user\n"); - CONDERROR(ul_result.pusch[i].needs_pdcch, "[TESTER] Msg3 allocations do not require PDCCH\n"); - // CONDERROR(tti_data.ul_pending_msg3.rnti != rnti, "[TESTER] The UL pending msg3 RNTI did not - // match\n"); CONDERROR(not tti_data.ul_pending_msg3_present, "[TESTER] The UL pending msg3 - // RNTI did not match\n"); + CONDERROR(ul_result.pusch[i].needs_pdcch, "Msg3 allocations do not require PDCCH\n"); + CONDERROR(userinfo.msg3_riv != ul_result.pusch[i].dci.type2_alloc.riv, + "The Msg3 was not allocated in the expected PRBs.\n"); userinfo.msg3_tic = tic.tic_tx_ul(); msg3_count++; } @@ -623,6 +626,9 @@ int common_sched_tester::sim_cfg(sim_sched_args args) int common_sched_tester::add_user(uint16_t rnti, const ue_cfg_t& ue_cfg_) { CONDERROR(ue_cfg(rnti, ue_cfg_) != SRSLTE_SUCCESS, "[TESTER] Configuring new user rnti=0x%x to sched\n", rnti); + // CONDERROR(!srslte_prach_tti_opportunity_config_fdd( + // sched_cell_params[CARRIER_IDX].cfg.prach_config, tti_info.tti_params.tti_rx, -1), + // "[TESTER] New user added in a non-PRACH TTI\n"); dl_sched_rar_info_t rar_info = {}; rar_info.prach_tti = tti_info.tti_params.tti_rx; @@ -640,6 +646,8 @@ int common_sched_tester::add_user(uint16_t rnti, const ue_cfg_t& ue_cfg_) void common_sched_tester::rem_user(uint16_t rnti) { + tester_log->info("[TESTER] Removing user rnti=0x%x\n", rnti); + sched::ue_rem(rnti); ue_tester->rem_user(rnti); } @@ -655,6 +663,8 @@ void common_sched_tester::new_test_tti() tti_info.nof_prachs = 0; tti_info.dl_sched_result.clear(); tti_info.ul_sched_result.clear(); + tti_info.dl_sched_result.resize(sched_cell_params.size()); + tti_info.ul_sched_result.resize(sched_cell_params.size()); tester_log->step(tti_info.tti_params.tti_rx); @@ -818,6 +828,98 @@ int common_sched_tester::process_results() return SRSLTE_SUCCESS; } +int common_sched_tester::process_tti_events(const tti_ev& tti_ev) +{ + for (const tti_ev::user_cfg_ev& ue_ev : tti_ev.user_updates) { + // There is a new configuration + if (ue_ev.ue_cfg != nullptr) { + if (not ue_tester->user_exists(ue_ev.rnti)) { + // new user + TESTASSERT(add_user(ue_ev.rnti, *ue_ev.ue_cfg) == SRSLTE_SUCCESS); + } else { + // reconfiguration + TESTASSERT(ue_cfg(ue_ev.rnti, *ue_ev.ue_cfg) == SRSLTE_SUCCESS); + ue_tester->user_reconf(ue_ev.rnti, *ue_ev.ue_cfg); + } + } + + // There is a user to remove + if (ue_ev.rem_user) { + rem_user(ue_ev.rnti); + } + + // configure carriers + if (ue_ev.bearer_cfg != nullptr) { + CONDERROR(not ue_tester->user_exists(ue_ev.rnti), "User rnti=0x%x does not exist\n", ue_ev.rnti); + // TODO: Instantiate more bearers + bearer_ue_cfg(ue_ev.rnti, 0, ue_ev.bearer_cfg.get()); + } + + // push UL SRs and DL packets + if (ue_ev.buffer_ev != nullptr) { + auto* user = ue_tester->get_user_state(ue_ev.rnti); + CONDERROR(user == nullptr, "TESTER ERROR: Trying to schedule data for user that does not exist\n"); + + if (ue_ev.buffer_ev->dl_data > 0) { + // If Msg3 has already been received + if (user->msg3_tic.is_valid() and user->msg3_tic <= tic) { + // If Msg4 not yet sent, allocate data in SRB0 buffer + uint32_t lcid = (user->msg4_tic.is_valid()) ? 2 : 0; + uint32_t pending_dl_new_data = ue_db[ue_ev.rnti].get_pending_dl_new_data(); + if (lcid == 2 and not user->drb_cfg_flag) { + // If RRCSetup finished + if (pending_dl_new_data == 0) { + // setup lcid==2 bearer + sched::ue_bearer_cfg_t cfg = {}; + cfg.direction = ue_bearer_cfg_t::BOTH; + ue_tester->bearer_cfg(ue_ev.rnti, 2, cfg); + bearer_ue_cfg(ue_ev.rnti, 2, &cfg); + } else { + // Let SRB0 get emptied + continue; + } + } + // Update DL buffer + uint32_t tot_dl_data = pending_dl_new_data + ue_ev.buffer_ev->dl_data; // TODO: derive pending based on rx + dl_rlc_buffer_state(ue_ev.rnti, lcid, tot_dl_data, 0); // TODO: Check retx_queue + } + } + + if (ue_ev.buffer_ev->sr_data > 0 and user->drb_cfg_flag) { + uint32_t tot_ul_data = + ue_db[ue_ev.rnti].get_pending_ul_new_data(tti_info.tti_params.tti_tx_ul) + ue_ev.buffer_ev->sr_data; + uint32_t lcid = 2; + ul_bsr(ue_ev.rnti, lcid, tot_ul_data, true); + } + } + } + return SRSLTE_SUCCESS; +} + +int common_sched_tester::run_tti(const tti_ev& tti_events) +{ + new_test_tti(); + tester_log->info("[TESTER] ---- tti=%u | nof_ues=%zd ----\n", tic.tti_rx(), ue_db.size()); + + process_tti_events(tti_events); + process_ack_txs(); + before_sched(); + + // Call scheduler for all carriers + tti_info.dl_sched_result.resize(sched_cell_params.size()); + for (uint32_t i = 0; i < sched_cell_params.size(); ++i) { + dl_sched(tti_info.tti_params.tti_tx_dl, i, tti_info.dl_sched_result[i]); + } + tti_info.ul_sched_result.resize(sched_cell_params.size()); + for (uint32_t i = 0; i < sched_cell_params.size(); ++i) { + ul_sched(tti_info.tti_params.tti_tx_ul, i, tti_info.ul_sched_result[i]); + } + + process_results(); + TESTASSERT(schedule_acks() == SRSLTE_SUCCESS); + return SRSLTE_SUCCESS; +} + int common_sched_tester::test_next_ttis(const std::vector& tti_events) { uint32_t next_idx = tic.is_valid() ? tic.total_count() - sim_args0.start_tti + 1 : 0; diff --git a/srsenb/test/mac/scheduler_test_common.h b/srsenb/test/mac/scheduler_test_common.h index a1ae68881..f3657dea5 100644 --- a/srsenb/test/mac/scheduler_test_common.h +++ b/srsenb/test/mac/scheduler_test_common.h @@ -84,13 +84,11 @@ class user_state_sched_tester { public: struct ue_state { - tti_counter prach_tic, rar_tic, msg3_tic, msg4_tic; - // int prach_tic = -1, rar_tic = -1, msg3_tic = -1, msg4_tic = -1; + tti_counter prach_tic, rar_tic, msg3_tic, msg4_tic; bool drb_cfg_flag = false; srsenb::sched_interface::ue_cfg_t user_cfg; - uint32_t dl_data = 0; - uint32_t ul_data = 0; uint32_t preamble_idx = 0; + uint32_t msg3_riv = 0; }; explicit user_state_sched_tester(const std::vector& cell_params_) : @@ -174,15 +172,18 @@ public: std::vector ul_sched_result; }; - int sim_cfg(sim_sched_args args); - int add_user(uint16_t rnti, const ue_cfg_t& ue_cfg_); - void rem_user(uint16_t rnti); - int process_ack_txs(); - int schedule_acks(); - int process_results(); + ~common_sched_tester() override = default; + + int sim_cfg(sim_sched_args args); + virtual int add_user(uint16_t rnti, const ue_cfg_t& ue_cfg_); + virtual void rem_user(uint16_t rnti); + int process_ack_txs(); + int schedule_acks(); + virtual int process_results(); + int process_tti_events(const tti_ev& tti_ev); - int test_next_ttis(const std::vector& tti_events); - virtual int run_tti(const tti_ev& tti_events) = 0; + int test_next_ttis(const std::vector& tti_events); + int run_tti(const tti_ev& tti_events); // args sim_sched_args sim_args0; ///< arguments used to generate TTI events @@ -214,7 +215,8 @@ protected: srsenb::ul_harq_proc ul_harq; }; - void new_test_tti(); + virtual void new_test_tti(); + virtual void before_sched() {} // control params std::multimap to_ack; diff --git a/srsenb/test/mac/scheduler_test_rand.cc b/srsenb/test/mac/scheduler_test_rand.cc index a37a65aa0..4b8c61772 100644 --- a/srsenb/test/mac/scheduler_test_rand.cc +++ b/srsenb/test/mac/scheduler_test_rand.cc @@ -45,19 +45,13 @@ /******************************************************** * Random Tester for Scheduler. * Current Checks: - * - Check if users are only added during a PRACH TTI - * - Allocation (DCI+RBs) of users that no longer exist - * - RAR is scheduled within the RAR window - * - Msg3 checks: - * - scheduled/received at expected TTI - * - with the correct RNTI and without PDCCH alloc - * - unexpected msg3 arrival + * - Check correct timing of PRACH, RAR, and Msg3 + * - Check whether Msg4 contains ConRes + * - Check allocs of users that no longer exist + * - Check collisions in PDCCH, PUSCH, and PDSCH + * - Unexpected Msg3, RAR allocs or with wrong values * - Users without data to Tx cannot be allocated in UL * - Retxs always take precedence - * - DCI: - * - collisions detected - * - mismatch between the union of all dcis and - * scheduler class aggregate dci value * - Invalid BC SIB index or TBS * - Harqs: * - invalid pids scheduled @@ -66,7 +60,6 @@ * - consistent NCCE loc * - invalid retx number * - DL adaptive retx/new tx <=> PDCCH alloc - * ... *******************************************************/ // uint32_t const seed = std::chrono::system_clock::now().time_since_epoch().count(); @@ -109,100 +102,44 @@ srslte::scoped_log log_global{}; constexpr uint32_t CARRIER_IDX = 0; -struct sched_sim_args { - struct tti_event_t { - struct user_event_t { - uint32_t sr_data = 0; - uint32_t dl_data = 0; - uint32_t dl_nof_retxs = 0; - }; - std::map users; - bool new_user = false; - bool rem_user = false; - uint32_t new_rnti; - uint32_t rem_rnti; - }; - - std::vector tti_events2; - sim_sched_args sim_args; - // std::vector sim_events; -}; - // Designed for testing purposes struct sched_tester : public srsenb::common_sched_tester { struct tester_user_results { - uint32_t dl_pending_data = 0; - uint32_t ul_pending_data = 0; ///< data pending for UL - bool has_dl_retx = false; - bool has_dl_tx = false; - bool has_ul_tx = false; ///< has either tx or retx - bool has_ul_retx = false; - bool has_ul_newtx = false; ///< *no* retx, but has tx - bool ul_retx_got_delayed = false; - srsenb::sched_interface::ul_sched_data_t* ul_sched = nullptr; // fast lookup - srsenb::sched_interface::dl_sched_data_t* dl_sched = nullptr; // fast lookup - srsenb::dl_harq_proc dl_harqs[2 * FDD_HARQ_DELAY_MS]; - srsenb::ul_harq_proc ul_harq; + uint32_t dl_pending_data = 0; + uint32_t ul_pending_data = 0; ///< data pending for UL + bool has_dl_tx = false; + bool has_ul_tx = false; ///< has either tx or retx + bool has_ul_retx = false; + bool has_ul_newtx = false; ///< *no* retx, but has tx + bool ul_retx_got_delayed = false; + srsenb::dl_harq_proc dl_harqs[2 * FDD_HARQ_DELAY_MS]; + srsenb::ul_harq_proc ul_harq; }; struct sched_tti_data { - uint32_t current_cfi; - uint32_t nof_prachs = 0; - bool ul_pending_msg3_present = false; - srsenb::sf_sched::pending_msg3_t ul_pending_msg3; - srslte::bounded_bitset<128, true> used_cce; std::map ue_data; ///< stores buffer state of each user tester_user_results total_ues; ///< stores combined UL/DL buffer state - srsenb::sched_interface::ul_sched_res_t sched_result_ul; - srsenb::sched_interface::dl_sched_res_t sched_result_dl; - }; - struct ue_info { - bool drb_cfg_flag = false; - srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; - uint32_t preamble_idx = 0; }; - sched_sim_args sim_events; - - // tester control data - std::map tester_ues; - // sched results sched_tti_data tti_data; - int add_user(uint16_t rnti, - srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg, - srsenb::sched_interface::ue_cfg_t ue_cfg_); - void rem_user(uint16_t rnti); - int test_tti_result(); + ~sched_tester() override = default; + + void rem_user(uint16_t rnti) override; + int test_pdcch_collisions(); int assert_no_empty_allocs(); - int test_collisions(); + int test_sch_collisions(); int test_harqs(); - int run_tti(const tti_ev& tti_events) final; private: - void new_test_tti(); - int process_tti_args(); - void before_sched(); - int process_results(); + void new_test_tti() override; + void before_sched() override; + int process_results() override; }; -int sched_tester::add_user(uint16_t rnti, - srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg, - srsenb::sched_interface::ue_cfg_t ue_cfg_) -{ - TESTASSERT(common_sched_tester::add_user(rnti, ue_cfg_) == SRSLTE_SUCCESS); - ue_info info; - info.bearer_cfg = bearer_cfg; - info.preamble_idx = tti_data.nof_prachs++; - tester_ues.insert(std::make_pair(rnti, info)); - - return SRSLTE_SUCCESS; -} - void sched_tester::rem_user(uint16_t rnti) { common_sched_tester::rem_user(rnti); - tester_ues.erase(rnti); tti_data.ue_data.erase(rnti); } @@ -210,70 +147,8 @@ void sched_tester::new_test_tti() { common_sched_tester::new_test_tti(); // NOTE: make a local copy, since some of these variables may be cleared during scheduling - auto& pending_msg3s = carrier_schedulers[0]->get_sf_sched_ptr(tti_info.tti_params.tti_rx)->get_pending_msg3(); - tti_data.ul_pending_msg3_present = false; - if (not pending_msg3s.empty()) { - tti_data.ul_pending_msg3_present = true; - tti_data.ul_pending_msg3 = pending_msg3s.front(); - } - tti_data.current_cfi = sched_cfg.nof_ctrl_symbols; - tti_data.used_cce.resize(srslte_regs_pdcch_ncce(sched_cell_params[CARRIER_IDX].regs.get(), tti_data.current_cfi)); - tti_data.used_cce.reset(); tti_data.ue_data.clear(); - tti_data.total_ues = tester_user_results(); - tti_data.nof_prachs = 0; -} - -int sched_tester::process_tti_args() -{ - // may add a new user - if (sim_events.tti_events2[tti_info.tti_params.tti_rx].new_user) { - CONDERROR(!srslte_prach_tti_opportunity_config_fdd( - sched_cell_params[CARRIER_IDX].cfg.prach_config, tti_info.tti_params.tti_rx, -1), - "[TESTER] New user added in a non-PRACH TTI\n"); - uint16_t rnti = sim_events.tti_events2[tti_info.tti_params.tti_rx].new_rnti; - add_user(rnti, sim_events.sim_args.bearer_cfg, sim_events.sim_args.ue_cfg); - } - - // may remove an existing user - if (sim_events.tti_events2[tti_info.tti_params.tti_rx].rem_user) { - uint16_t rnti = sim_events.tti_events2[tti_info.tti_params.tti_rx].rem_rnti; - bearer_ue_rem(rnti, 0); - ue_rem(rnti); - rem_user(rnti); - log_global->info("[TESTER] Removing user rnti=0x%x\n", rnti); - } - - // push UL SRs and DL packets - for (auto& e : sim_events.tti_events2[tti_info.tti_params.tti_rx].users) { - if (e.second.sr_data > 0 and tester_ues[e.first].drb_cfg_flag) { - uint32_t tot_ul_data = ue_db[e.first].get_pending_ul_new_data(tti_info.tti_params.tti_tx_ul) + e.second.sr_data; - uint32_t lcid = 0; - ul_bsr(e.first, lcid, tot_ul_data, true); - } - auto* user = ue_tester->get_user_state(e.first); - if (e.second.dl_data > 0 and user->msg3_tic.is_valid() and user->msg3_tic.tti_rx() < tti_info.tti_params.tti_rx) { - // If Msg4 not yet sent, allocate data in SRB0 buffer - uint32_t lcid = (user->msg4_tic.is_valid()) ? 2 : 0; - uint32_t pending_dl_new_data = ue_db[e.first].get_pending_dl_new_data(); - if (lcid == 2 and not tester_ues[e.first].drb_cfg_flag) { - // If RRCSetup finished - if (pending_dl_new_data == 0) { - // setup lcid==2 bearer - tester_ues[e.first].drb_cfg_flag = true; - bearer_ue_cfg(e.first, 2, &tester_ues[e.first].bearer_cfg); - } else { - // Let SRB0 get emptied - continue; - } - } - // TODO: Does it need TTI for checking pending data? - uint32_t tot_dl_data = pending_dl_new_data + e.second.dl_data; - dl_rlc_buffer_state(e.first, lcid, tot_dl_data, 0); - } - } - - return SRSLTE_SUCCESS; + tti_data.total_ues = tester_user_results(); } void sched_tester::before_sched() @@ -291,7 +166,6 @@ void sched_tester::before_sched() d.has_ul_retx = hul->has_pending_retx(); d.has_ul_tx = d.has_ul_retx or d.ul_pending_data > 0; srsenb::dl_harq_proc* hdl = user->get_pending_dl_harq(tti_info.tti_params.tti_tx_dl, CARRIER_IDX); - d.has_dl_retx = (hdl != nullptr) and hdl->has_pending_retx(0, tti_info.tti_params.tti_tx_dl); d.has_dl_tx = (hdl != nullptr) or (it.second.get_empty_dl_harq(CARRIER_IDX) != nullptr and d.dl_pending_data > 0); d.has_ul_newtx = not d.has_ul_retx and d.ul_pending_data > 0; tti_data.ue_data.insert(std::make_pair(rnti, d)); @@ -314,51 +188,14 @@ void sched_tester::before_sched() int sched_tester::process_results() { - tti_info.dl_sched_result.resize(1); - tti_info.dl_sched_result[0] = tti_data.sched_result_dl; - tti_info.ul_sched_result.resize(1); - tti_info.ul_sched_result[0] = tti_data.sched_result_ul; - for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { - uint16_t rnti = tti_data.sched_result_ul.pusch[i].dci.rnti; - tti_data.ue_data[rnti].ul_sched = &tti_data.sched_result_ul.pusch[i]; - CONDERROR(tester_ues.count(rnti) == 0, - "[TESTER] [%d] The user rnti=0x%x that no longer exists got allocated.\n", - tti_info.tti_params.tti_rx, - rnti); - } - for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) { - uint16_t rnti = tti_data.sched_result_dl.data[i].dci.rnti; - tti_data.ue_data[rnti].dl_sched = &tti_data.sched_result_dl.data[i]; - CONDERROR(tester_ues.count(rnti) == 0, - "[TESTER] [%d] The user rnti=0x%x that no longer exists got allocated.\n", - tti_info.tti_params.tti_rx, - rnti); - } - - test_tti_result(); - ue_tester->test_ra(0, tti_info.dl_sched_result[CARRIER_IDX], tti_info.ul_sched_result[CARRIER_IDX]); - test_collisions(); + test_pdcch_collisions(); + TESTASSERT(ue_tester->test_all(0, tti_info.dl_sched_result[CARRIER_IDX], tti_info.ul_sched_result[CARRIER_IDX]) == + SRSLTE_SUCCESS); + test_sch_collisions(); assert_no_empty_allocs(); test_harqs(); - output_tester[CARRIER_IDX].test_sib_scheduling(tti_info.tti_params, tti_data.sched_result_dl); - - return SRSLTE_SUCCESS; -} - -int sched_tester::run_tti(const tti_ev& tti_events) -{ - new_test_tti(); - log_global->info("[TESTER] ---- tti=%u | nof_ues=%zd ----\n", tic.tti_rx(), ue_db.size()); - - process_tti_args(); - - process_ack_txs(); - before_sched(); + output_tester[CARRIER_IDX].test_sib_scheduling(tti_info.tti_params, tti_info.dl_sched_result[CARRIER_IDX]); - dl_sched(tti_info.tti_params.tti_tx_dl, CARRIER_IDX, tti_data.sched_result_dl); - ul_sched(tti_info.tti_params.tti_tx_ul, CARRIER_IDX, tti_data.sched_result_ul); - - process_results(); return SRSLTE_SUCCESS; } @@ -369,10 +206,14 @@ int sched_tester::assert_no_empty_allocs() uint16_t rnti = iter.first; // srsenb::sched_ue* user = &ue_db[rnti]; - if (!iter.second.has_ul_tx and tti_data.ue_data[rnti].ul_sched != nullptr and - tti_data.ue_data[rnti].ul_sched->needs_pdcch) { - // TODO: This test does not work for adaptive re-tx - TESTERROR("[TESTER] There was a user without data that got allocated in UL\n"); + if (not iter.second.has_ul_tx) { + for (uint32_t i = 0; i < tti_info.ul_sched_result[CARRIER_IDX].nof_dci_elems; ++i) { + auto& pusch = tti_info.ul_sched_result[CARRIER_IDX].pusch[i]; + if (pusch.dci.rnti == rnti and pusch.needs_pdcch) { + // TODO: This test does not work for adaptive re-tx + TESTERROR("[TESTER] There was a user without data that got allocated in UL\n"); + } + } } // srsenb::ul_harq_proc* hul = user->get_ul_harq(tti_info.tti_params.tti_tx_ul); iter.second.ul_retx_got_delayed = iter.second.has_ul_retx and iter.second.ul_harq.is_empty(0); @@ -397,45 +238,25 @@ int sched_tester::assert_no_empty_allocs() /** * Tests whether there were collisions in the DCI allocations */ -int sched_tester::test_tti_result() +int sched_tester::test_pdcch_collisions() { + srslte::bounded_bitset<128, true> used_cce; + used_cce.resize(srslte_regs_pdcch_ncce(sched_cell_params[CARRIER_IDX].regs.get(), sched_cfg.nof_ctrl_symbols)); + /* TEST: Check if there are collisions in the PDCCH */ - TESTASSERT(output_tester[CARRIER_IDX].test_pdcch_collisions( - tti_data.sched_result_dl, tti_data.sched_result_ul, &tti_data.used_cce) == SRSLTE_SUCCESS); + TESTASSERT(output_tester[CARRIER_IDX].test_pdcch_collisions(tti_info.dl_sched_result[CARRIER_IDX], + tti_info.ul_sched_result[CARRIER_IDX], + &used_cce) == SRSLTE_SUCCESS); /* TEST: Check whether dci values are correct */ - TESTASSERT(output_tester[CARRIER_IDX].test_dci_values_consistency(tti_data.sched_result_dl, - tti_data.sched_result_ul) == SRSLTE_SUCCESS); - - const srsenb::sf_sched* tti_sched = carrier_schedulers[0]->get_sf_sched_ptr(tti_info.tti_params.tti_rx); - - for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { - const auto& pusch = tti_data.sched_result_ul.pusch[i]; - CONDERROR(ue_db.count(pusch.dci.rnti) == 0, "The allocated rnti=0x%x does not exist\n", pusch.dci.rnti); - } - for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) { - auto& data = tti_data.sched_result_dl.data[i]; - CONDERROR(ue_db.count(data.dci.rnti) == 0, "Allocated rnti=0x%x that does not exist\n", data.dci.rnti); - } - for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_rar_elems; ++i) { - const auto& rar = tti_data.sched_result_dl.rar[i]; - for (uint32_t j = 0; j < rar.nof_grants; ++j) { - const auto& msg3_grant = rar.msg3_grant[j]; - const auto& msg3_list = - carrier_schedulers[0]->get_sf_sched_ptr(tti_sched->get_tti_rx() + MSG3_DELAY_MS)->get_pending_msg3(); - const auto& p = msg3_list.front(); - CONDERROR(msg3_list.empty(), "Pending Msg3 should have been set\n"); - uint32_t rba = srslte_ra_type2_to_riv(p.L, p.n_prb, sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb); - CONDERROR(msg3_grant.grant.rba != rba, "Pending Msg3 RBA is not valid\n"); - } - } + TESTASSERT(output_tester[CARRIER_IDX].test_dci_values_consistency( + tti_info.dl_sched_result[CARRIER_IDX], tti_info.ul_sched_result[CARRIER_IDX]) == SRSLTE_SUCCESS); /* verify if sched_result "used_cce" coincide with sched "used_cce" */ auto* tti_alloc = carrier_schedulers[0]->get_sf_sched_ptr(tti_info.tti_params.tti_rx); - if (tti_data.used_cce != tti_alloc->get_pdcch_mask()) { + if (used_cce != tti_alloc->get_pdcch_mask()) { std::string mask_str = tti_alloc->get_pdcch_mask().to_string(); - TESTERROR( - "[TESTER] The used_cce do not match: (%s!=%s)\n", mask_str.c_str(), tti_data.used_cce.to_string().c_str()); + TESTERROR("[TESTER] The used_cce do not match: (%s!=%s)\n", mask_str.c_str(), used_cce.to_string().c_str()); } // TODO: Check postponed retxs @@ -457,8 +278,8 @@ int sched_tester::test_tti_result() int sched_tester::test_harqs() { /* check consistency of DL harq procedures and allocations */ - for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) { - const auto& data = tti_data.sched_result_dl.data[i]; + for (uint32_t i = 0; i < tti_info.dl_sched_result[CARRIER_IDX].nof_data_elems; ++i) { + const auto& data = tti_info.dl_sched_result[CARRIER_IDX].data[i]; uint32_t h_id = data.dci.pid; uint16_t rnti = data.dci.rnti; const srsenb::dl_harq_proc* h = ue_db[rnti].get_dl_harq(h_id, CARRIER_IDX); @@ -473,17 +294,17 @@ int sched_tester::test_harqs() CONDERROR(tti_data.ue_data[rnti].dl_harqs[h_id].nof_retx(0) + 1 != h->nof_retx(0), "[TESTER] A dl harq of user rnti=0x%x was likely overwritten.\n", rnti); - CONDERROR(h->nof_retx(0) >= sim_events.sim_args.ue_cfg.maxharq_tx, + CONDERROR(h->nof_retx(0) >= sim_args0.ue_cfg.maxharq_tx, "[TESTER] The number of retx=%d exceeded its max=%d\n", h->nof_retx(0), - sim_events.sim_args.ue_cfg.maxharq_tx); + sim_args0.ue_cfg.maxharq_tx); } else { // newtx CONDERROR(h->nof_retx(0) != 0, "[TESTER] A new harq was scheduled but with invalid number of retxs\n"); } } - for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { - const auto& pusch = tti_data.sched_result_ul.pusch[i]; + for (uint32_t i = 0; i < tti_info.ul_sched_result[CARRIER_IDX].nof_dci_elems; ++i) { + const auto& pusch = tti_info.ul_sched_result[CARRIER_IDX].pusch[i]; uint16_t rnti = pusch.dci.rnti; const auto& ue_data = tti_data.ue_data[rnti]; const srsenb::ul_harq_proc* h = ue_db[rnti].get_ul_harq(tti_info.tti_params.tti_tx_ul, CARRIER_IDX); @@ -506,8 +327,8 @@ int sched_tester::test_harqs() } /* Check PHICH allocations */ - for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_phich_elems; ++i) { - const auto& phich = tti_data.sched_result_ul.phich[i]; + for (uint32_t i = 0; i < tti_info.ul_sched_result[CARRIER_IDX].nof_phich_elems; ++i) { + const auto& phich = tti_info.ul_sched_result[CARRIER_IDX].phich[i]; CONDERROR(tti_data.ue_data.count(phich.rnti) == 0, "[TESTER] Allocated PHICH rnti no longer exists\n"); const auto& hprev = tti_data.ue_data[phich.rnti].ul_harq; const auto* h = ue_db[phich.rnti].get_ul_harq(tti_info.tti_params.tti_tx_ul, CARRIER_IDX); @@ -525,19 +346,16 @@ int sched_tester::test_harqs() continue; } uint32_t i = 0; - for (; i < tti_data.sched_result_ul.nof_phich_elems; ++i) { - const auto& phich = tti_data.sched_result_ul.phich[i]; + for (; i < tti_info.ul_sched_result[CARRIER_IDX].nof_phich_elems; ++i) { + const auto& phich = tti_info.ul_sched_result[CARRIER_IDX].phich[i]; if (phich.rnti == ue.first) { break; } } - CONDERROR(i == tti_data.sched_result_ul.nof_phich_elems, + CONDERROR(i == tti_info.ul_sched_result[CARRIER_IDX].nof_phich_elems, "[TESTER] harq had pending ack but no phich was allocked\n"); } - // schedule future acks - TESTASSERT(schedule_acks() == SRSLTE_SUCCESS); - // Check whether some pids got old if (check_old_pids) { for (auto& user : ue_db) { @@ -557,65 +375,43 @@ int sched_tester::test_harqs() return SRSLTE_SUCCESS; } -int sched_tester::test_collisions() +int sched_tester::test_sch_collisions() { const srsenb::sf_sched* tti_sched = carrier_schedulers[0]->get_sf_sched_ptr(tti_info.tti_params.tti_rx); srsenb::prbmask_t ul_allocs(sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb); /* TEST: any collision in PUCCH and PUSCH */ TESTASSERT(output_tester[CARRIER_IDX].test_pusch_collisions( - tti_info.tti_params, tti_data.sched_result_ul, ul_allocs) == SRSLTE_SUCCESS); + tti_info.tti_params, tti_info.ul_sched_result[CARRIER_IDX], ul_allocs) == SRSLTE_SUCCESS); /* TEST: check whether cumulative UL PRB masks coincide */ if (ul_allocs != tti_sched->get_ul_mask()) { TESTERROR("[TESTER] The UL PRB mask and the scheduler result UL mask are not consistent\n"); } - /* TEST: Check if there is a collision with Msg3 or Msg3 alloc data is not consistent */ - if (tti_data.ul_pending_msg3_present) { - bool passed = false; - for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { - if (tti_data.ul_pending_msg3.rnti == tti_data.sched_result_ul.pusch[i].dci.rnti) { - CONDERROR(passed, "[TESTER] There can only be one msg3 allocation per UE\n"); - CONDERROR(tti_data.sched_result_ul.pusch[i].needs_pdcch, "[TESTER] Msg3 allocations do not need PDCCH DCI\n"); - uint32_t L, RBstart; - srslte_ra_type2_from_riv(tti_data.sched_result_ul.pusch[i].dci.type2_alloc.riv, - &L, - &RBstart, - sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb, - sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb); - if (RBstart != tti_data.ul_pending_msg3.n_prb or L != tti_data.ul_pending_msg3.L) { - TESTERROR("[TESTER] The Msg3 allocation does not coincide with the expected.\n"); - } - passed = true; - } - } - CONDERROR(not passed, "[TESTER] No Msg3 allocation was found in the sched_result\n"); - } - // update ue stats with number of allocated UL PRBs - for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { + for (uint32_t i = 0; i < tti_info.ul_sched_result[CARRIER_IDX].nof_dci_elems; ++i) { uint32_t L, RBstart; - srslte_ra_type2_from_riv(tti_data.sched_result_ul.pusch[i].dci.type2_alloc.riv, + srslte_ra_type2_from_riv(tti_info.ul_sched_result[CARRIER_IDX].pusch[i].dci.type2_alloc.riv, &L, &RBstart, sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb, sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb); - ue_stats[tti_data.sched_result_ul.pusch[i].dci.rnti].nof_ul_rbs += L; + ue_stats[tti_info.ul_sched_result[CARRIER_IDX].pusch[i].dci.rnti].nof_ul_rbs += L; } /* TEST: check any collision in PDSCH */ srsenb::rbgmask_t rbgmask(sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb); - TESTASSERT(output_tester[CARRIER_IDX].test_pdsch_collisions(tti_info.tti_params, tti_data.sched_result_dl, rbgmask) == - SRSLTE_SUCCESS); + TESTASSERT(output_tester[CARRIER_IDX].test_pdsch_collisions( + tti_info.tti_params, tti_info.dl_sched_result[CARRIER_IDX], rbgmask) == SRSLTE_SUCCESS); // update ue stats with number of DL RB allocations srslte::bounded_bitset<100, true> alloc_mask(sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb); - for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) { + for (uint32_t i = 0; i < tti_info.dl_sched_result[CARRIER_IDX].nof_data_elems; ++i) { TESTASSERT(srsenb::extract_dl_prbmask(sched_cell_params[CARRIER_IDX].cfg.cell, - tti_data.sched_result_dl.data[i].dci, + tti_info.dl_sched_result[CARRIER_IDX].data[i].dci, &alloc_mask) == SRSLTE_SUCCESS); - ue_stats[tti_data.sched_result_dl.data[i].dci.rnti].nof_dl_rbs += alloc_mask.count(); + ue_stats[tti_info.dl_sched_result[CARRIER_IDX].data[i].dci.rnti].nof_dl_rbs += alloc_mask.count(); } // TEST: check if resulting DL mask is equal to scheduler internal DL mask @@ -631,129 +427,65 @@ int sched_tester::test_collisions() return SRSLTE_SUCCESS; } -srsenb::sched_interface::cell_cfg_t generate_cell_cfg() -{ - srsenb::sched_interface::cell_cfg_t cell_cfg = {}; - srslte_cell_t& cell_cfg_phy = cell_cfg.cell; - - std::uniform_int_distribution dist_prb_idx(0, 5); - uint32_t prb_idx = dist_prb_idx(srsenb::get_rand_gen()); - - /* Set PHY cell configuration */ - cell_cfg_phy.id = 1; - cell_cfg_phy.cp = SRSLTE_CP_NORM; - cell_cfg_phy.nof_ports = 1; - cell_cfg_phy.nof_prb = std::array({6, 15, 25, 50, 75, 100})[prb_idx]; - cell_cfg_phy.phich_length = SRSLTE_PHICH_NORM; - cell_cfg_phy.phich_resources = SRSLTE_PHICH_R_1; - - cell_cfg.sibs[0].len = 18; - cell_cfg.sibs[0].period_rf = 8; - cell_cfg.sibs[1].len = 41; - cell_cfg.sibs[1].period_rf = 16; - cell_cfg.si_window_ms = 40; - cell_cfg.nrb_pucch = 2; - cell_cfg.prach_freq_offset = (cell_cfg_phy.nof_prb == 6) ? 0 : 2; - cell_cfg.prach_rar_window = 3; - cell_cfg.maxharq_msg3tx = 3; - - return cell_cfg; -} - -void test_scheduler_rand(const sched_sim_args& args) +void test_scheduler_rand(sched_sim_events sim) { // Create classes sched_tester tester; srsenb::sched my_sched; - log_global->set_level(srslte::LOG_LEVEL_INFO); - - tester.sim_events = args; - sim_sched_args sim_args = args.sim_args; - sim_args.ue_cfg = args.sim_args.ue_cfg; - sim_args.bearer_cfg = args.sim_args.bearer_cfg; - sim_args.start_tti = 0; - sim_args.sim_log = log_global.get(); - tester.init(nullptr); - tester.sim_cfg(sim_args); - - uint32_t tti = 0; - uint32_t nof_ttis = 0; - while (nof_ttis <= args.tti_events2.size()) { - log_global->step(tti); + tester.sim_cfg(std::move(sim.sim_args)); - tester.run_tti({}); - - nof_ttis++; - tti = (tti + 1) % 10240; - } + tester.test_next_ttis(sim.tti_events); } -sched_sim_args rand_sim_params(uint32_t nof_ttis) +sched_sim_events rand_sim_params(uint32_t nof_ttis) { - sched_sim_args sim_gen; - std::vector > current_rntis; - uint16_t rnti_start = 70; - uint32_t max_conn_dur = 10000, min_conn_dur = 5000; - float P_ul_sr = srsenb::randf() * 0.5, P_dl = srsenb::randf() * 0.5; - float P_prach = 0.99f; // 0.1f + randf()*0.3f; - float ul_sr_exps[] = {1, 4}; // log rand - float dl_data_exps[] = {1, 4}; // log rand - uint32_t max_nof_users = 5; - std::uniform_int_distribution<> connection_dur_dist(min_conn_dur, max_conn_dur); - - sim_gen.sim_args.cell_cfg = {generate_cell_cfg()}; - - sim_gen.sim_args.ue_cfg = generate_default_ue_cfg(); - - bzero(&sim_gen.sim_args.bearer_cfg, sizeof(srsenb::sched_interface::ue_bearer_cfg_t)); - sim_gen.sim_args.bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; - - sim_gen.sim_args.P_retx = 0.1; - sim_gen.tti_events2.resize(nof_ttis); - // sim_gen.sim_events.resize(nof_ttis); - - for (uint32_t tti = 0; tti < sim_gen.tti_events2.size(); ++tti) { - if (not current_rntis.empty()) { - // may rem user - for (uint32_t i = 0; i < current_rntis.size(); ++i) { - if (current_rntis[i][2] + current_rntis[i][1] <= tti) { - auto it_to_rem = current_rntis.begin() + i; - sim_gen.tti_events2[tti].rem_user = true; - sim_gen.tti_events2[tti].rem_rnti = (*it_to_rem)[0]; - current_rntis.erase(it_to_rem); - } + sched_sim_events sim_gen; + uint32_t max_conn_dur = 10000, min_conn_dur = 500; + float P_ul_sr = srsenb::randf() * 0.5, P_dl = srsenb::randf() * 0.5; + float P_prach = 0.99f; // 0.1f + randf()*0.3f; + float ul_sr_exps[] = {1, 4}; // log rand + float dl_data_exps[] = {1, 4}; // log rand + uint32_t max_nof_users = 5; + std::uniform_int_distribution<> connection_dur_dist(min_conn_dur, max_conn_dur); + std::uniform_int_distribution dist_prb_idx(0, 5); + uint32_t prb_idx = dist_prb_idx(srsenb::get_rand_gen()); + uint32_t nof_prb = std::array({6, 15, 25, 50, 75, 100})[prb_idx]; + + sched_sim_event_generator generator; + + sim_gen.sim_args.cell_cfg = {generate_default_cell_cfg(nof_prb)}; + sim_gen.sim_args.ue_cfg = generate_default_ue_cfg(); + sim_gen.sim_args.P_retx = 0.1; + sim_gen.sim_args.start_tti = 0; + sim_gen.sim_args.sim_log = log_global.get(); + generator.tti_events.resize(nof_ttis); + + for (uint32_t tti = 0; tti < nof_ttis; ++tti) { + for (auto& u : generator.current_users) { + uint32_t rnti = u.first; + if (srsenb::randf() < P_ul_sr) { + float exp = ul_sr_exps[0] + srsenb::randf() * (ul_sr_exps[1] - ul_sr_exps[0]); + generator.add_ul_data(rnti, (uint32_t)pow(10, exp)); } - - for (auto& current_rnti : current_rntis) { - uint32_t rnti = current_rnti[0]; - if (srsenb::randf() < P_ul_sr) { - float exp = ul_sr_exps[0] + srsenb::randf() * (ul_sr_exps[1] - ul_sr_exps[0]); - sim_gen.tti_events2[tti].users[rnti].sr_data = (uint32_t)pow(10, exp); - } - if (srsenb::randf() < P_dl) { - float exp = dl_data_exps[0] + srsenb::randf() * (dl_data_exps[1] - dl_data_exps[0]); - sim_gen.tti_events2[tti].users[rnti].dl_data = (uint32_t)pow(10, exp); - } + if (srsenb::randf() < P_dl) { + float exp = dl_data_exps[0] + srsenb::randf() * (dl_data_exps[1] - dl_data_exps[0]); + generator.add_dl_data(rnti, (uint32_t)pow(10, exp)); } } // may add new user (For now, we only support one UE per PRACH) bool is_prach_tti = srslte_prach_tti_opportunity_config_fdd(sim_gen.sim_args.cell_cfg[CARRIER_IDX].prach_config, tti, -1); - if (is_prach_tti and current_rntis.size() < max_nof_users and srsenb::randf() < P_prach) { - std::vector elem(3); - elem[0] = rnti_start; - elem[1] = tti; - elem[2] = connection_dur_dist(srsenb::get_rand_gen()); - current_rntis.push_back(elem); - sim_gen.tti_events2[tti].new_user = true; - sim_gen.tti_events2[tti].new_rnti = rnti_start; - rnti_start++; + if (is_prach_tti and generator.current_users.size() < max_nof_users and srsenb::randf() < P_prach) { + generator.add_new_default_user(connection_dur_dist(srsenb::get_rand_gen())); } + generator.step_tti(); } + sim_gen.tti_events = std::move(generator.tti_events); + return sim_gen; } @@ -761,16 +493,15 @@ int main() { // Setup seed srsenb::set_randseed(seed); + printf("[TESTER] This is the chosen seed: %u\n", seed); srslte::logmap::set_default_log_level(srslte::LOG_LEVEL_INFO); - printf("[TESTER] This is the chosen seed: %u\n", seed); - /* initialize random seed: */ uint32_t N_runs = 1, nof_ttis = 10240 + 10; for (uint32_t n = 0; n < N_runs; ++n) { printf("Sim run number: %u\n", n + 1); - sched_sim_args sim_args = rand_sim_params(nof_ttis); - test_scheduler_rand(sim_args); + sched_sim_events sim = rand_sim_params(nof_ttis); + test_scheduler_rand(std::move(sim)); } return 0; diff --git a/srsenb/test/mac/scheduler_test_utils.h b/srsenb/test/mac/scheduler_test_utils.h index 800ea4e43..58593571e 100644 --- a/srsenb/test/mac/scheduler_test_utils.h +++ b/srsenb/test/mac/scheduler_test_utils.h @@ -27,6 +27,7 @@ #include "srslte/interfaces/sched_interface.h" #include #include +#include struct tti_counter { tti_counter() = default; @@ -153,7 +154,6 @@ struct sim_sched_args { uint32_t start_tti = 0; float P_retx; srsenb::sched_interface::ue_cfg_t ue_cfg; - srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; std::vector cell_cfg; srslte::log* sim_log = nullptr; }; @@ -170,14 +170,16 @@ struct sched_sim_event_generator { struct user_data { uint16_t rnti; - uint32_t tti_start; - uint32_t tti_duration; + uint32_t tti_start = 0; + uint32_t tti_duration = 0; }; - std::vector current_users; + std::unordered_map current_users; // generated events std::vector tti_events; + sched_sim_event_generator() { tti_events.push_back(tti_ev{}); } + void step_tti(uint32_t nof_ttis = 1) { tti_counter += nof_ttis; @@ -210,10 +212,10 @@ struct sched_sim_event_generator { user.rnti = next_rnti++; // creates a user with one supported CC (PRACH stage) user.ue_cfg.reset(new srsenb::sched_interface::ue_cfg_t{generate_default_ue_cfg()}); - current_users.emplace_back(); - current_users.back().rnti = user.rnti; - current_users.back().tti_start = tti_counter; - current_users.back().tti_duration = duration; + auto& u = current_users[user.rnti]; + u.rnti = user.rnti; + u.tti_start = tti_counter; + u.tti_duration = duration; return &user; } @@ -265,34 +267,30 @@ private: return &(*it); } - bool user_exists(uint16_t rnti) - { - return std::find_if(current_users.begin(), current_users.end(), [&rnti](const user_data& u) { - return u.rnti == rnti; - }) != current_users.end(); - } + bool user_exists(uint16_t rnti) { return current_users.find(rnti) != current_users.end(); } void rem_old_users() { // remove users that pass their connection duration - auto rem_it = std::remove_if(current_users.begin(), current_users.end(), [this](const user_data& u) { - return u.tti_start + u.tti_duration < tti_counter; - }); - - // set the call rem_user(...) at the right tti - for (auto it = rem_it; it != current_users.end(); ++it) { - uint32_t rem_tti = it->tti_start + it->tti_duration; - auto& l = tti_events[rem_tti].user_updates; - auto user_it = std::find_if(l.begin(), l.end(), [&it](tti_ev::user_cfg_ev& u) { return it->rnti == u.rnti; }); + for (auto it = current_users.begin(); it != current_users.end();) { + user_data& user = it->second; + uint32_t rem_tti = user.tti_start + user.tti_duration; + if (rem_tti > tti_counter) { + ++it; + continue; + } + // set the call rem_user(...) at the right tti + auto& l = tti_events[rem_tti].user_updates; + auto user_it = std::find_if(l.begin(), l.end(), [&it](tti_ev::user_cfg_ev& u) { return it->first == u.rnti; }); if (user_it == l.end()) { l.emplace_back(); l.back().rem_user = true; + l.back().rnti = it->first; } else { user_it->rem_user = true; } + it = current_users.erase(it); } - - current_users.erase(rem_it, current_users.end()); } };