diff --git a/srsenb/hdr/stack/mac/scheduler_common.h b/srsenb/hdr/stack/mac/scheduler_common.h index bb58bad56..a4fbe0f68 100644 --- a/srsenb/hdr/stack/mac/scheduler_common.h +++ b/srsenb/hdr/stack/mac/scheduler_common.h @@ -32,7 +32,7 @@ namespace srsenb { * Constants **********************/ -constexpr uint32_t tti_duration_ms = 1000; +constexpr float tti_duration_ms = 1; /*********************** * Helper Types diff --git a/srsenb/src/stack/mac/scheduler_ue.cc b/srsenb/src/stack/mac/scheduler_ue.cc index 2e2f64442..0abe43624 100644 --- a/srsenb/src/stack/mac/scheduler_ue.cc +++ b/srsenb/src/stack/mac/scheduler_ue.cc @@ -1626,11 +1626,6 @@ int lch_manager::alloc_rlc_pdu(sched_interface::dl_sched_pdu_t* rlc_pdu, int rem } if (alloc_bytes > 0) { - // Update Bj - if (lch[lcid].cfg.pbr != pbr_infinity) { - lch[lcid].Bj -= alloc_bytes; - } - rlc_pdu->nbytes = alloc_bytes; rlc_pdu->lcid = lcid; Debug("SCHED: Allocated lcid=%d, nbytes=%d, tbs_bytes=%d\n", rlc_pdu->lcid, rlc_pdu->nbytes, rem_bytes); @@ -1649,6 +1644,10 @@ int lch_manager::alloc_tx_bytes(uint8_t lcid, uint32_t rem_bytes) { int alloc = std::min((int)rem_bytes, get_dl_tx(lcid)); lch[lcid].buf_tx -= alloc; + if (alloc > 0 and lch[lcid].cfg.pbr != pbr_infinity) { + // Update Bj + lch[lcid].Bj -= alloc; + } return alloc; } diff --git a/srsenb/test/mac/sched_lc_ch_test.cc b/srsenb/test/mac/sched_lc_ch_test.cc index 7993e3b7b..6d7b95c9c 100644 --- a/srsenb/test/mac/sched_lc_ch_test.cc +++ b/srsenb/test/mac/sched_lc_ch_test.cc @@ -27,31 +27,38 @@ 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) +/// Tests if a PDU was allocated with lcid and pdu_size bytes +int test_pdu_alloc_successful(srsenb::lch_manager& lch_handler, + sched_interface::dl_sched_pdu_t& pdu, + int lcid, + uint32_t pdu_size) +{ + 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); + return SRSLTE_SUCCESS; +} + +int test_retx_until_empty(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(test_pdu_alloc_successful(lch_handler, pdu, lcid, pdu_size) == SRSLTE_SUCCESS); 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) +int test_newtx_until_empty(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(test_pdu_alloc_successful(lch_handler, pdu, lcid, pdu_size) == SRSLTE_SUCCESS); TESTASSERT(lch_handler.get_dl_tx(lcid) == (int)((nof_pdus - i - 1) * pdu_size)); } return nof_pdus * pdu_size; @@ -81,27 +88,92 @@ int test_lc_ch_pbr_infinity() // 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); + TESTASSERT(test_retx_until_empty(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); + TESTASSERT(test_retx_until_empty(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); + TESTASSERT(test_retx_until_empty(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); + TESTASSERT(test_newtx_until_empty(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); + TESTASSERT(test_newtx_until_empty(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); + TESTASSERT(test_newtx_until_empty(lch_handler, srsenb::RB_ID_DRB1, 500) == nof_pending_bytes); + + return SRSLTE_SUCCESS; +} + +int test_lc_ch_pbr_finite() +{ + srsenb::lch_manager lch_handler; + sched_interface::dl_sched_pdu_t pdu; + + 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].pbr = 256; // kBps + ue_cfg.ue_bearers[srsenb::RB_ID_DRB1].bsd = 50; // msec + 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].pbr = 8; // kBps + ue_cfg.ue_bearers[srsenb::RB_ID_DRB2].bsd = 50; // msec + ue_cfg.ue_bearers[srsenb::RB_ID_DRB2].priority = 3; + + lch_handler.set_cfg(ue_cfg); + for (uint32_t i = 0; i < 50; ++i) { + lch_handler.new_tti(); + } + // Bj={0, infinity, 0, 12800, 400} + + lch_handler.dl_buffer_state(srsenb::RB_ID_SRB1, 50000, 1000); + lch_handler.dl_buffer_state(srsenb::RB_ID_DRB1, 50000, 1000); + lch_handler.dl_buffer_state(srsenb::RB_ID_DRB2, 50000, 0); + + // TEST1 - SRB1 retxs are emptied first + int nof_pending_bytes = lch_handler.get_dl_retx(srsenb::RB_ID_SRB1); + TESTASSERT(test_retx_until_empty(lch_handler, srsenb::RB_ID_SRB1, 500) == nof_pending_bytes); + + // TEST2 - DRB1 retxs are emptied + nof_pending_bytes = lch_handler.get_dl_retx(srsenb::RB_ID_DRB1); + TESTASSERT(test_retx_until_empty(lch_handler, srsenb::RB_ID_DRB1, 500) == nof_pending_bytes); + + // TEST3 - SRB1 newtxs are emptied (PBR==infinity) + nof_pending_bytes = lch_handler.get_dl_tx(srsenb::RB_ID_SRB1); + TESTASSERT(test_newtx_until_empty(lch_handler, srsenb::RB_ID_SRB1, 500) == nof_pending_bytes); + + // TEST4 - DRB2 has higher priority so it gets allocated until Bj <= 0 + TESTASSERT(test_pdu_alloc_successful(lch_handler, pdu, srsenb::RB_ID_DRB2, 200) == SRSLTE_SUCCESS); + // Bj={0, infinity, 0, 12800, 200} + TESTASSERT(test_pdu_alloc_successful(lch_handler, pdu, srsenb::RB_ID_DRB2, 600) == SRSLTE_SUCCESS); + // Bj={0, infinity, 0, 256000, -400} + + // TEST5 - DRB1 has lower prio, but DRB2 Bj <= 0. + for (uint32_t i = 0; i < 50; ++i) { + lch_handler.new_tti(); + TESTASSERT(test_pdu_alloc_successful(lch_handler, pdu, srsenb::RB_ID_DRB1, 50) == SRSLTE_SUCCESS); + } + + // TEST6 - new tti restores DRB2 Bj>=0, and DRB2 gets allocated + lch_handler.new_tti(); + // Bj={0, infinity, 0, 256000, 8} + TESTASSERT(test_pdu_alloc_successful(lch_handler, pdu, srsenb::RB_ID_DRB2, 50) == SRSLTE_SUCCESS); + // Bj={0, infinity, 0, 256000, -42} + lch_handler.new_tti(); + TESTASSERT(test_pdu_alloc_successful(lch_handler, pdu, srsenb::RB_ID_DRB1, 50) == SRSLTE_SUCCESS); return SRSLTE_SUCCESS; } @@ -113,5 +185,6 @@ int main() srslte::logmap::get("TEST")->set_level(srslte::LOG_LEVEL_INFO); TESTASSERT(test_lc_ch_pbr_infinity() == SRSLTE_SUCCESS); + TESTASSERT(test_lc_ch_pbr_finite() == SRSLTE_SUCCESS); srslte::console("Success\n"); }