diff --git a/srsenb/src/stack/mac/scheduler_grid.cc b/srsenb/src/stack/mac/scheduler_grid.cc index 6ccd1a387..4a52182c3 100644 --- a/srsenb/src/stack/mac/scheduler_grid.cc +++ b/srsenb/src/stack/mac/scheduler_grid.cc @@ -854,10 +854,11 @@ void sf_sched::set_ul_sched_result(const pdcch_grid_t::alloc_result_t& dci_resul } // Print Resulting UL Allocation - log_h->info("SCHED: %s %s rnti=0x%x, pid=%d, dci=(%d,%d), prb=(%d,%d), n_rtx=%d, tbs=%d, bsr=%d (%d-%d)\n", + log_h->info("SCHED: %s %s rnti=0x%x, cc=%d, pid=%d, dci=(%d,%d), prb=(%d,%d), n_rtx=%d, tbs=%d, bsr=%d (%d-%d)\n", ul_alloc.is_msg3() ? "Msg3" : "UL", ul_alloc.is_retx() ? "retx" : "tx", user->get_rnti(), + cc_cfg->enb_cc_idx, h->get_id(), pusch->dci.location.L, pusch->dci.location.ncce, diff --git a/srsenb/src/stack/mac/scheduler_ue.cc b/srsenb/src/stack/mac/scheduler_ue.cc index fd7744bdc..d9ecda6f9 100644 --- a/srsenb/src/stack/mac/scheduler_ue.cc +++ b/srsenb/src/stack/mac/scheduler_ue.cc @@ -133,7 +133,7 @@ void sched_ue::set_cfg(const sched_interface::ue_cfg_t& cfg_) } if (scell_activation_state_changed) { pending_ces.emplace_back(srslte::sch_subh::SCELL_ACTIVATION); - log_h->info("SCHED: Scheduling SCell Activation CMD for rnti=0x%x\n", rnti); + log_h->info("SCHED: Enqueueing SCell Activation CMD for rnti=0x%x\n", rnti); } } } @@ -169,12 +169,14 @@ void sched_ue::reset() void sched_ue::set_bearer_cfg(uint32_t lc_id, sched_interface::ue_bearer_cfg_t* cfg_) { std::lock_guard lock(mutex); + cfg.ue_bearers[lc_id] = *cfg_; set_bearer_cfg_unlocked(lc_id, *cfg_); } void sched_ue::rem_bearer(uint32_t lc_id) { std::lock_guard lock(mutex); + cfg.ue_bearers[lc_id] = sched_interface::ue_bearer_cfg_t{}; set_bearer_cfg_unlocked(lc_id, sched_interface::ue_bearer_cfg_t{}); } @@ -870,9 +872,12 @@ void sched_ue::set_bearer_cfg_unlocked(uint32_t lc_id, const sched_interface::ue { if (lc_id < sched_interface::MAX_LC) { bool is_idle = lch[lc_id].cfg.direction == sched_interface::ue_bearer_cfg_t::IDLE; + bool is_equal = memcmp(&cfg_, &lch[lc_id].cfg, sizeof(cfg_)) == 0; lch[lc_id].cfg = cfg_; if (lch[lc_id].cfg.direction != sched_interface::ue_bearer_cfg_t::IDLE) { - Info("SCHED: Set bearer config lc_id=%d, direction=%d\n", lc_id, (int)lch[lc_id].cfg.direction); + if (not is_equal) { + Info("SCHED: Set bearer config lc_id=%d, direction=%d\n", lc_id, (int)lch[lc_id].cfg.direction); + } } else if (not is_idle) { Info("SCHED: Removed bearer config lc_id=%d, direction=%d\n", lc_id, (int)lch[lc_id].cfg.direction); } diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index af1bc9808..0ae7396e9 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -444,6 +444,7 @@ void ue::allocate_ce(srslte::sch_pdu* pdu, uint32_t lcid) } else { Error("CE: Setting SCell Activation CE. No space for a subheader\n"); } + break; default: Error("CE: Allocating CE=0x%x. Not supported\n", lcid); break; diff --git a/srsenb/test/mac/scheduler_ca_test.cc b/srsenb/test/mac/scheduler_ca_test.cc index 0cd14009c..0e17e6ca6 100644 --- a/srsenb/test/mac/scheduler_ca_test.cc +++ b/srsenb/test/mac/scheduler_ca_test.cc @@ -19,6 +19,7 @@ * */ +#include "lib/include/srslte/common/pdu.h" #include "scheduler_test_common.h" #include "scheduler_test_utils.h" #include "srsenb/hdr/stack/mac/scheduler.h" @@ -56,109 +57,6 @@ public: }; srslte::scoped_log log_global{}; -/****************************** - * Setup Scheduler Tester Args - *****************************/ - -sched_sim_events generate_default_sim_events(uint32_t nof_prb, uint32_t nof_ccs) -{ - sched_sim_events sim_events; - sim_sched_args& sim_args = sim_events.sim_args; - - sim_args.nof_ttis = 10240 + 10; - sim_args.P_retx = 0.1; - - sim_args.ue_cfg = generate_default_ue_cfg(); - - // setup two cells - std::vector cell_cfg(nof_ccs, generate_default_cell_cfg(nof_prb)); - cell_cfg[0].scell_list.resize(1); - cell_cfg[0].scell_list[0].enb_cc_idx = 1; - cell_cfg[0].scell_list[0].cross_carrier_scheduling = false; - cell_cfg[0].scell_list[0].ul_allowed = true; - cell_cfg[1].cell.id = 2; // id=2 - cell_cfg[1].scell_list = cell_cfg[0].scell_list; - 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) { - sim_args.ue_cfg.supported_cc_list[i].active = true; - sim_args.ue_cfg.supported_cc_list[i].enb_cc_idx = i; - } - - return sim_events; -} - -sched_sim_events generate_sim1() -{ - /* Simulation Configuration */ - uint32_t nof_prb = 25; - uint32_t nof_ccs = 2; - - sched_sim_events sim_events = generate_default_sim_events(nof_prb, nof_ccs); - - /* Internal configurations. Do not touch */ - float ul_sr_exps[] = {1, 4}; // log rand - float dl_data_exps[] = {1, 4}; // log rand - float P_ul_sr = randf() * 0.5, P_dl = randf() * 0.5; - - sched_sim_event_generator generator; - - /* Setup Events */ - uint32_t prach_tti = 1, msg4_tot_delay = 10; // TODO: check correct value - uint32_t msg4_size = 20; // TODO: Check - uint32_t duration = 1000; - - // Event PRACH: at prach_tti - generator.step_until(prach_tti); - tti_ev::user_cfg_ev* user = generator.add_new_default_user(duration); - uint16_t rnti = user->rnti; - - // Event (TTI=prach_tti+msg4_tot_delay): First Tx (Msg4). Goes in SRB0 and contains ConRes - generator.step_tti(msg4_tot_delay); - generator.add_dl_data(rnti, msg4_size); - - // Event (20 TTIs): Data back and forth - auto generate_data = [&](uint32_t nof_ttis) { - for (uint32_t i = 0; i < nof_ttis; ++i) { - generator.step_tti(); - bool ul_flag = randf() < P_ul_sr, dl_flag = randf() < P_dl; - if (dl_flag) { - float exp = dl_data_exps[0] + randf() * (dl_data_exps[1] - dl_data_exps[0]); - generator.add_dl_data(rnti, pow(10, exp)); - } - if (ul_flag) { - float exp = ul_sr_exps[0] + randf() * (ul_sr_exps[1] - ul_sr_exps[0]); - generator.add_ul_data(rnti, pow(10, exp)); - } - } - }; - generate_data(20); - - // Event: Reconf Complete. Activate SCells - user = generator.user_reconf(rnti); - user->ue_cfg->supported_cc_list.resize(nof_ccs); - for (uint32_t i = 0; i < user->ue_cfg->supported_cc_list.size(); ++i) { - user->ue_cfg->supported_cc_list[i].active = true; - user->ue_cfg->supported_cc_list[i].enb_cc_idx = i; - } - // now we have two CCs - - // Generate a bit more data, now it should go through both cells - generate_data(20); - // We should have scheduled the SCell Activation by now - - sim_events.tti_events = std::move(generator.tti_events); - sim_events.sim_args.nof_ttis = sim_events.tti_events.size(); - - return sim_events; -} - /****************************** * Scheduler Tester for CA *****************************/ @@ -189,10 +87,12 @@ public: // tti specific params tti_info_t tti_info; + uint32_t tti_counter = 0; // testers std::vector output_tester; std::unique_ptr ue_tester; + std::unique_ptr sched_stats; private: struct ack_info_t { @@ -219,6 +119,7 @@ int sched_ca_tester::cell_cfg(const std::vector& cell_params) { sched::cell_cfg(cell_params); // call parent ue_tester.reset(new user_state_sched_tester{cell_params}); + sched_stats.reset(new sched_result_stats{cell_params}); output_tester.clear(); output_tester.reserve(cell_params.size()); for (uint32_t i = 0; i < cell_params.size(); ++i) { @@ -435,6 +336,8 @@ void sched_ca_tester::run_tti(uint32_t tti_rx, const tti_ev& tti_events) process_results(); set_acks(); + + tti_counter++; } int sched_ca_tester::process_results() @@ -444,6 +347,7 @@ int sched_ca_tester::process_results() TESTASSERT(output_tester[i].test_all( tti_info.tti_params, tti_info.dl_sched_result[i], tti_info.ul_sched_result[i]) == SRSLTE_SUCCESS); } + sched_stats->process_results(tti_info.tti_params, tti_info.dl_sched_result, tti_info.ul_sched_result); return SRSLTE_SUCCESS; } @@ -504,22 +408,144 @@ int sched_ca_tester::set_acks() return SRSLTE_SUCCESS; } -int test_scheduler_ca(const sched_sim_events& sim_events) +/****************************** + * Scheduler Tests + *****************************/ + +sim_sched_args generate_default_sim_args(uint32_t nof_prb, uint32_t nof_ccs) { - sched_ca_tester tester; - tester.sim_args = sim_events.sim_args; + sim_sched_args sim_args; - // Setup scheduler - tester.init(nullptr); - TESTASSERT(tester.cell_cfg(sim_events.sim_args.cell_cfg) == SRSLTE_SUCCESS); + sim_args.nof_ttis = 10240 + 10; + sim_args.P_retx = 0.1; - uint32_t tti_start = 0; // rand_int(0, 10240); - for (uint32_t nof_ttis = 0; nof_ttis < sim_events.sim_args.nof_ttis; ++nof_ttis) { - uint32_t tti = (tti_start + nof_ttis) % 10240; - log_global->step(tti); - tester.run_tti(tti, sim_events.tti_events[nof_ttis]); + sim_args.ue_cfg = generate_default_ue_cfg(); + + // setup two cells + std::vector cell_cfg(nof_ccs, generate_default_cell_cfg(nof_prb)); + cell_cfg[0].scell_list.resize(1); + cell_cfg[0].scell_list[0].enb_cc_idx = 1; + cell_cfg[0].scell_list[0].cross_carrier_scheduling = false; + cell_cfg[0].scell_list[0].ul_allowed = true; + cell_cfg[1].cell.id = 2; // id=2 + cell_cfg[1].scell_list = cell_cfg[0].scell_list; + 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) { + sim_args.ue_cfg.supported_cc_list[i].active = true; + sim_args.ue_cfg.supported_cc_list[i].enb_cc_idx = i; } + return sim_args; +} + +int run_sim1() +{ + /* Simulation Configuration Arguments */ + uint32_t nof_prb = 25; + uint32_t nof_ccs = 2; + + /* Simulation Objects Setup */ + sched_sim_event_generator generator; + // Setup scheduler + sched_ca_tester tester; + tester.sim_args = generate_default_sim_args(nof_prb, nof_ccs); + tester.init(nullptr); + TESTASSERT(tester.cell_cfg(tester.sim_args.cell_cfg) == SRSLTE_SUCCESS); + + /* Internal configurations. Do not touch */ + float ul_sr_exps[] = {1, 4}; // log rand + float dl_data_exps[] = {1, 4}; // log rand + float P_ul_sr = randf() * 0.5, P_dl = randf() * 0.5; + uint32_t tti_start = 0; // rand_int(0, 10240); + const uint16_t rnti1 = 70; + uint32_t pcell_idx = 0; + + /* Setup Simulation */ + uint32_t prach_tti = 1, msg4_tot_delay = 10; // TODO: check correct value + uint32_t msg4_size = 20; // TODO: Check + uint32_t duration = 1000; + auto process_ttis = [&generator, &tti_start, &tester]() { + for (; tester.tti_counter <= generator.tti_counter;) { + uint32_t tti = (tti_start + tester.tti_counter) % 10240; + log_global->step(tti); + tester.run_tti(tti, generator.tti_events[tester.tti_counter]); + } + }; + + /* Simulation */ + + // Event PRACH: PRACH takes place for "rnti1", and carrier "pcell_idx" + generator.step_until(prach_tti); + tti_ev::user_cfg_ev* user = generator.add_new_default_user(duration); + user->ue_cfg->supported_cc_list[0].enb_cc_idx = pcell_idx; + user->rnti = rnti1; + process_ttis(); + TESTASSERT(tester.ue_tester->user_exists(rnti1)); + + // Event (TTI=prach_tti+msg4_tot_delay): First Tx (Msg4). Goes in SRB0 and contains ConRes + generator.step_tti(msg4_tot_delay); + generator.add_dl_data(rnti1, msg4_size); + process_ttis(); + + // Event (20 TTIs): Data back and forth + auto generate_data = [&](uint32_t nof_ttis, float prob_dl, float prob_ul) { + for (uint32_t i = 0; i < nof_ttis; ++i) { + generator.step_tti(); + bool ul_flag = randf() < prob_ul, dl_flag = randf() < prob_dl; + if (dl_flag) { + float exp = dl_data_exps[0] + randf() * (dl_data_exps[1] - dl_data_exps[0]); + generator.add_dl_data(rnti1, pow(10, exp)); + } + if (ul_flag) { + float exp = ul_sr_exps[0] + randf() * (ul_sr_exps[1] - ul_sr_exps[0]); + generator.add_ul_data(rnti1, pow(10, exp)); + } + } + }; + generate_data(20, P_dl, P_ul_sr); + process_ttis(); + + // Event: Reconf Complete. Activate SCells. Check if CE correctly transmitted + generator.step_tti(); + user = generator.user_reconf(rnti1); + *user->ue_cfg = *tester.get_ue_cfg(rnti1); // use current cfg as starting point, and add more supported ccs + user->ue_cfg->supported_cc_list.resize(nof_ccs); + for (uint32_t i = 0; i < user->ue_cfg->supported_cc_list.size(); ++i) { + user->ue_cfg->supported_cc_list[i].active = true; + user->ue_cfg->supported_cc_list[i].enb_cc_idx = i; + } + process_ttis(); + // When a new DL tx takes place, it should also encode the CE + for (uint32_t i = 0; i < 100; ++i) { + TESTASSERT(tester.tti_info.dl_sched_result[pcell_idx].nof_data_elems > 0); + if (tester.tti_info.dl_sched_result[pcell_idx].data[0].nof_pdu_elems[0] > 0) { + // it is a new DL tx + TESTASSERT(tester.tti_info.dl_sched_result[pcell_idx].data[0].pdu[0][0].lcid == + srslte::sch_subh::cetype::SCELL_ACTIVATION); + break; + } + generator.step_tti(); + process_ttis(); + // now we have two CCs + } + // now we have two CCs + + // Event: Generate a bit more data, now it should go through both cells + generate_data(10, 1.0, 1.0); + process_ttis(); + TESTASSERT(tester.sched_stats->users[rnti1].tot_dl_sched_data[0] > 0); + TESTASSERT(tester.sched_stats->users[rnti1].tot_dl_sched_data[1] > 0); + TESTASSERT(tester.sched_stats->users[rnti1].tot_ul_sched_data[0] > 0); + TESTASSERT(tester.sched_stats->users[rnti1].tot_ul_sched_data[1] > 0); + + log_global->info("[TESTER] Sim1 finished successfully\n"); return SRSLTE_SUCCESS; } @@ -530,9 +556,7 @@ int main() uint32_t N_runs = 1; for (uint32_t n = 0; n < N_runs; ++n) { printf("Sim run number: %u\n", n + 1); - sched_sim_events sim_events = generate_sim1(); - - TESTASSERT(test_scheduler_ca(sim_events) == SRSLTE_SUCCESS); + TESTASSERT(run_sim1() == SRSLTE_SUCCESS); } return 0; diff --git a/srsenb/test/mac/scheduler_test_common.cc b/srsenb/test/mac/scheduler_test_common.cc index 01056977a..e96202aa9 100644 --- a/srsenb/test/mac/scheduler_test_common.cc +++ b/srsenb/test/mac/scheduler_test_common.cc @@ -522,3 +522,31 @@ int user_state_sched_tester::test_all(uint32_t enb TESTASSERT(test_scell_activation(enb_cc_idx, dl_result, ul_result) == SRSLTE_SUCCESS); return SRSLTE_SUCCESS; } + +void sched_result_stats::process_results(const tti_params_t& tti_params, + const std::vector& dl_result, + const std::vector& ul_result) +{ + for (uint32_t ccidx = 0; ccidx < dl_result.size(); ++ccidx) { + for (uint32_t i = 0; i < dl_result[ccidx].nof_data_elems; ++i) { + user_stats* user = get_user(dl_result[ccidx].data[i].dci.rnti); + user->tot_dl_sched_data[ccidx] += dl_result[ccidx].data[i].tbs[0]; + user->tot_dl_sched_data[ccidx] += dl_result[ccidx].data[i].tbs[1]; + } + for (uint32_t i = 0; i < ul_result[ccidx].nof_dci_elems; ++i) { + user_stats* user = get_user(ul_result[ccidx].pusch[i].dci.rnti); + user->tot_ul_sched_data[ccidx] += ul_result[ccidx].pusch[i].tbs; + } + } +} + +sched_result_stats::user_stats* sched_result_stats::get_user(uint16_t rnti) +{ + if (users.count(rnti) != 0) { + return &users[rnti]; + } + users[rnti].rnti = rnti; + users[rnti].tot_dl_sched_data.resize(cell_params.size(), 0); + users[rnti].tot_ul_sched_data.resize(cell_params.size(), 0); + return &users[rnti]; +} diff --git a/srsenb/test/mac/scheduler_test_common.h b/srsenb/test/mac/scheduler_test_common.h index 7eed23c30..ffb6b3ebe 100644 --- a/srsenb/test/mac/scheduler_test_common.h +++ b/srsenb/test/mac/scheduler_test_common.h @@ -123,6 +123,32 @@ private: tti_params_t tti_params{10241}; }; +class sched_result_stats +{ +public: + explicit sched_result_stats(std::vector cell_params_) : + cell_params(std::move(cell_params_)) + { + } + + void process_results(const tti_params_t& tti_params, + const std::vector& dl_result, + const std::vector& ul_result); + + struct user_stats { + uint16_t rnti; + std::vector tot_dl_sched_data; // includes retxs + std::vector tot_ul_sched_data; + }; + + std::map users; + +private: + user_stats* get_user(uint16_t rnti); + + const std::vector cell_params; +}; + } // namespace srsenb #endif // SRSLTE_SCHEDULER_TEST_COMMON_H diff --git a/srsenb/test/mac/scheduler_test_utils.h b/srsenb/test/mac/scheduler_test_utils.h index e3cd88f02..0d707d914 100644 --- a/srsenb/test/mac/scheduler_test_utils.h +++ b/srsenb/test/mac/scheduler_test_utils.h @@ -33,8 +33,8 @@ * Setup Random generators **************************/ -// uint32_t const seed = std::chrono::system_clock::now().time_since_epoch().count(); -uint32_t const seed = 2452071795; +uint32_t const seed = std::chrono::system_clock::now().time_since_epoch().count(); +// uint32_t const seed = 2452071795; // uint32_t const seed = 1581009287; // prb==25 std::default_random_engine rand_gen(seed); std::uniform_real_distribution unif_dist(0, 1.0); @@ -134,7 +134,7 @@ struct sched_sim_events { struct sched_sim_event_generator { uint16_t next_rnti = 70; - uint32_t current_tti = 0; + uint32_t tti_counter = 0; struct user_data { uint16_t rnti; @@ -148,29 +148,31 @@ struct sched_sim_event_generator { void step_tti(uint32_t nof_ttis = 1) { - current_tti += nof_ttis; - if (current_tti >= tti_events.size()) { - tti_events.resize(current_tti + 1); + tti_counter += nof_ttis; + if (tti_counter >= tti_events.size()) { + tti_events.resize(tti_counter + 1); } rem_old_users(); } - void step_until(uint32_t tti) + int step_until(uint32_t tti) { - if (current_tti >= tti) { + if (tti_counter >= tti) { // error - return; + return -1; } - current_tti = tti; - if (current_tti >= tti_events.size()) { - tti_events.resize(current_tti + 1); + int jump = tti - tti_counter; + tti_counter = tti; + if (tti_counter >= tti_events.size()) { + tti_events.resize(tti_counter + 1); } rem_old_users(); + return jump; } tti_ev::user_cfg_ev* add_new_default_user(uint32_t duration) { - std::vector& user_updates = tti_events[current_tti].user_updates; + std::vector& user_updates = tti_events[tti_counter].user_updates; user_updates.emplace_back(); auto& user = user_updates.back(); user.rnti = next_rnti++; @@ -178,7 +180,7 @@ struct sched_sim_event_generator { 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 = current_tti; + current_users.back().tti_start = tti_counter; current_users.back().tti_duration = duration; return &user; } @@ -187,7 +189,9 @@ struct sched_sim_event_generator { { TESTASSERT(user_exists(rnti)); tti_ev::user_cfg_ev* user = get_user_cfg(rnti); - user->buffer_ev.reset(new tti_ev::user_buffer_ev{}); + if (user->buffer_ev == nullptr) { + user->buffer_ev.reset(new tti_ev::user_buffer_ev{}); + } user->buffer_ev->dl_data = new_data; return SRSLTE_SUCCESS; } @@ -196,8 +200,9 @@ struct sched_sim_event_generator { { TESTASSERT(user_exists(rnti)); tti_ev::user_cfg_ev* user = get_user_cfg(rnti); - TESTASSERT(user != nullptr); - user->buffer_ev.reset(new tti_ev::user_buffer_ev{}); + if (user->buffer_ev == nullptr) { + user->buffer_ev.reset(new tti_ev::user_buffer_ev{}); + } user->buffer_ev->sr_data = new_data; return SRSLTE_SUCCESS; } @@ -217,7 +222,7 @@ struct sched_sim_event_generator { private: tti_ev::user_cfg_ev* get_user_cfg(uint16_t rnti) { - std::vector& user_updates = tti_events[current_tti].user_updates; + std::vector& user_updates = tti_events[tti_counter].user_updates; auto it = std::find_if( user_updates.begin(), user_updates.end(), [&rnti](tti_ev::user_cfg_ev& user) { return user.rnti == rnti; }); if (it == user_updates.end()) { @@ -239,7 +244,7 @@ private: { // 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 < current_tti; + return u.tti_start + u.tti_duration < tti_counter; }); // set the call rem_user(...) at the right tti