diff --git a/srsenb/src/stack/mac/scheduler_ue.cc b/srsenb/src/stack/mac/scheduler_ue.cc index 78ccf7fd3..2e2f64442 100644 --- a/srsenb/src/stack/mac/scheduler_ue.cc +++ b/srsenb/src/stack/mac/scheduler_ue.cc @@ -1563,33 +1563,47 @@ void lch_manager::dl_buffer_state(uint8_t lcid, uint32_t tx_queue, uint32_t retx int lch_manager::get_max_prio_lcid() const { int min_prio_val = std::numeric_limits::max(), prio_lcid = -1; + + // Prioritize retxs for (uint32_t lcid = 0; lcid < MAX_LC; ++lcid) { - if (get_dl_tx_total(lcid) > 0 and lch[lcid].Bj > 0 and lch[lcid].cfg.priority < min_prio_val) { + if (get_dl_retx(lcid) > 0 and lch[lcid].cfg.priority < min_prio_val) { min_prio_val = lch[lcid].cfg.priority; prio_lcid = lcid; } } + if (prio_lcid >= 0) { + return prio_lcid; + } - if (prio_lcid < 0) { - // disregard Bj value in selection of lcid - size_t nof_lcids = 0; - std::array chosen_lcids = {}; - for (uint32_t lcid = 0; lcid < MAX_LC; ++lcid) { - if (get_dl_tx_total(lcid) > 0) { - if (lch[lcid].cfg.priority < min_prio_val) { - min_prio_val = lch[lcid].cfg.priority; - chosen_lcids[0] = lcid; - nof_lcids = 1; - } else if (lch[lcid].cfg.priority == min_prio_val) { - chosen_lcids[nof_lcids++] = lcid; - } - } + // Select lcid with new txs using Bj + for (uint32_t lcid = 0; lcid < MAX_LC; ++lcid) { + if (get_dl_tx(lcid) > 0 and lch[lcid].Bj > 0 and lch[lcid].cfg.priority < min_prio_val) { + min_prio_val = lch[lcid].cfg.priority; + prio_lcid = lcid; } - // logical chanels with equal priority should be served equally - if (nof_lcids > 0) { - prio_lcid = chosen_lcids[prio_idx % nof_lcids]; + } + if (prio_lcid >= 0) { + return prio_lcid; + } + + // Disregard Bj + size_t nof_lcids = 0; + std::array chosen_lcids = {}; + for (uint32_t lcid = 0; lcid < MAX_LC; ++lcid) { + if (get_dl_tx_total(lcid) > 0) { + if (lch[lcid].cfg.priority < min_prio_val) { + min_prio_val = lch[lcid].cfg.priority; + chosen_lcids[0] = lcid; + nof_lcids = 1; + } else if (lch[lcid].cfg.priority == min_prio_val) { + chosen_lcids[nof_lcids++] = lcid; + } } } + // logical chanels with equal priority should be served equally + if (nof_lcids > 0) { + prio_lcid = chosen_lcids[prio_idx % nof_lcids]; + } return prio_lcid; } diff --git a/srsenb/test/mac/CMakeLists.txt b/srsenb/test/mac/CMakeLists.txt index 0631c9e91..93cfd9e35 100644 --- a/srsenb/test/mac/CMakeLists.txt +++ b/srsenb/test/mac/CMakeLists.txt @@ -56,3 +56,6 @@ target_link_libraries(scheduler_ca_test srsenb_mac ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) add_test(scheduler_ca_test scheduler_ca_test) + +add_executable(sched_lc_ch_test sched_lc_ch_test.cc scheduler_test_common.cc) +target_link_libraries(sched_lc_ch_test srsenb_mac srslte_common srslte_mac scheduler_test_common) \ No newline at end of file diff --git a/srsenb/test/mac/sched_lc_ch_test.cc b/srsenb/test/mac/sched_lc_ch_test.cc new file mode 100644 index 000000000..7993e3b7b --- /dev/null +++ b/srsenb/test/mac/sched_lc_ch_test.cc @@ -0,0 +1,117 @@ +/* + * Copyright 2013-2020 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 "scheduler_test_common.h" +#include "scheduler_test_utils.h" +#include "srsenb/hdr/stack/mac/scheduler_ue.h" +#include "srslte/common/test_common.h" + +using namespace srsenb; +const uint32_t seed = std::chrono::system_clock::now().time_since_epoch().count(); + +int test_retx_prb_inf(srsenb::lch_manager& lch_handler, int lcid, uint32_t pdu_size) +{ + uint32_t nof_pdus = lch_handler.get_dl_retx(lcid) / pdu_size; + sched_interface::dl_sched_pdu_t pdu; + + for (uint32_t i = 0; i < nof_pdus; ++i) { + TESTASSERT(lch_handler.get_max_prio_lcid() == lcid); + TESTASSERT(lch_handler.alloc_rlc_pdu(&pdu, pdu_size) == (int)pdu_size); + TESTASSERT(pdu.lcid == (uint32_t)lcid); + TESTASSERT(pdu.nbytes == pdu_size); + TESTASSERT(lch_handler.get_dl_retx(lcid) == (int)((nof_pdus - i - 1) * pdu_size)); + } + return nof_pdus * pdu_size; +} + +int test_newtx_prb_inf(srsenb::lch_manager& lch_handler, int lcid, uint32_t pdu_size) +{ + uint32_t nof_pdus = lch_handler.get_dl_tx(lcid) / pdu_size; + sched_interface::dl_sched_pdu_t pdu; + + for (uint32_t i = 0; i < nof_pdus; ++i) { + TESTASSERT(lch_handler.get_max_prio_lcid() == lcid); + TESTASSERT(lch_handler.alloc_rlc_pdu(&pdu, pdu_size) == (int)pdu_size); + TESTASSERT(pdu.lcid == (uint32_t)lcid); + TESTASSERT(pdu.nbytes == pdu_size); + TESTASSERT(lch_handler.get_dl_tx(lcid) == (int)((nof_pdus - i - 1) * pdu_size)); + } + return nof_pdus * pdu_size; +} + +int test_lc_ch_pbr_infinity() +{ + srsenb::lch_manager lch_handler; + + srsenb::sched_interface::ue_cfg_t ue_cfg = generate_default_ue_cfg(); + ue_cfg = generate_setup_ue_cfg(ue_cfg); + ue_cfg.ue_bearers[srsenb::RB_ID_SRB1] = {}; + ue_cfg.ue_bearers[srsenb::RB_ID_SRB1].direction = sched_interface::ue_bearer_cfg_t::BOTH; + ue_cfg.ue_bearers[srsenb::RB_ID_DRB1] = {}; + ue_cfg.ue_bearers[srsenb::RB_ID_DRB1].direction = sched_interface::ue_bearer_cfg_t::BOTH; + ue_cfg.ue_bearers[srsenb::RB_ID_DRB1].priority = 5; + ue_cfg.ue_bearers[srsenb::RB_ID_DRB2] = {}; + ue_cfg.ue_bearers[srsenb::RB_ID_DRB2].direction = sched_interface::ue_bearer_cfg_t::BOTH; + ue_cfg.ue_bearers[srsenb::RB_ID_DRB2].priority = 3; + + lch_handler.set_cfg(ue_cfg); + lch_handler.new_tti(); + + lch_handler.dl_buffer_state(srsenb::RB_ID_SRB1, 50000, 10000); + lch_handler.dl_buffer_state(srsenb::RB_ID_DRB1, 5000, 10000); + lch_handler.dl_buffer_state(srsenb::RB_ID_DRB2, 5000, 10000); + + // TEST1 - retx of SRB1 is prioritized. Do not transmit other bearers until there are no SRB1 retxs + int nof_pending_bytes = lch_handler.get_dl_retx(srsenb::RB_ID_SRB1); + TESTASSERT(test_retx_prb_inf(lch_handler, srsenb::RB_ID_SRB1, 500) == nof_pending_bytes); + + // TEST2 - the DRB2 has lower prio level than SRB1, but has retxs + nof_pending_bytes = lch_handler.get_dl_retx(srsenb::RB_ID_DRB2); + TESTASSERT(test_retx_prb_inf(lch_handler, srsenb::RB_ID_DRB2, 500) == nof_pending_bytes); + + // TEST3 - the DRB1 has lower prio level, but has retxs + nof_pending_bytes = lch_handler.get_dl_retx(srsenb::RB_ID_DRB1); + TESTASSERT(test_retx_prb_inf(lch_handler, srsenb::RB_ID_DRB1, 500) == nof_pending_bytes); + + // TEST4 - The SRB1 newtx buffer is emptied before other bearers newtxs + nof_pending_bytes = lch_handler.get_dl_tx(srsenb::RB_ID_SRB1); + TESTASSERT(test_newtx_prb_inf(lch_handler, srsenb::RB_ID_SRB1, 500) == nof_pending_bytes); + + // TEST5 - The DRB2 newtx buffer is emptied before DRB1 newtxs + nof_pending_bytes = lch_handler.get_dl_tx(srsenb::RB_ID_DRB2); + TESTASSERT(test_newtx_prb_inf(lch_handler, srsenb::RB_ID_DRB2, 500) == nof_pending_bytes); + + // TEST6 - The DRB1 buffer is emptied + nof_pending_bytes = lch_handler.get_dl_tx(srsenb::RB_ID_DRB1); + TESTASSERT(test_newtx_prb_inf(lch_handler, srsenb::RB_ID_DRB1, 500) == nof_pending_bytes); + + return SRSLTE_SUCCESS; +} + +int main() +{ + srsenb::set_randseed(seed); + srslte::console("This is the chosen seed: %u\n", seed); + srslte::logmap::get("TEST")->set_level(srslte::LOG_LEVEL_INFO); + + TESTASSERT(test_lc_ch_pbr_infinity() == SRSLTE_SUCCESS); + srslte::console("Success\n"); +} diff --git a/srsenb/test/mac/scheduler_test_utils.h b/srsenb/test/mac/scheduler_test_utils.h index 2a333477f..061760455 100644 --- a/srsenb/test/mac/scheduler_test_utils.h +++ b/srsenb/test/mac/scheduler_test_utils.h @@ -116,7 +116,7 @@ inline srsenb::sched_interface::ue_cfg_t generate_setup_ue_cfg(const srsenb::sch inline srsenb::sched_interface::ue_cfg_t generate_reconf_ue_cfg(const srsenb::sched_interface::ue_cfg_t& final_cfg) { - srsenb::sched_interface::ue_cfg_t cfg = final_cfg; + srsenb::sched_interface::ue_cfg_t cfg = generate_setup_ue_cfg(final_cfg); cfg.supported_cc_list.resize(1); cfg.ue_bearers = {};