diff --git a/srsenb/test/mac/scheduler_test_rand.cc b/srsenb/test/mac/scheduler_test_rand.cc index cf744de9d..438b6e2dd 100644 --- a/srsenb/test/mac/scheduler_test_rand.cc +++ b/srsenb/test/mac/scheduler_test_rand.cc @@ -22,7 +22,6 @@ #include "srsenb/hdr/stack/mac/scheduler.h" #include "srsenb/hdr/stack/mac/scheduler_ue.h" #include -#include #include #include #include @@ -37,14 +36,46 @@ #include "srslte/phy/utils/debug.h" #include "srslte/radio/radio.h" +/******************************************************** + * 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 + * - 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 + * - empty harqs scheduled + * - invalid harq TTI + * - consistent NCCE loc + * - invalid retx number + * - DL adaptive retx/new tx <=> PDCCH alloc + * ... + *******************************************************/ + +/*************************** + * Setup Random generators + **************************/ // uint32_t const seed = std::random_device()(); -uint32_t const seed = 2452071795; // time(NULL); +uint32_t const seed = 2452071795; // time(nullptr); std::default_random_engine rand_gen(seed); std::uniform_real_distribution unif_dist(0, 1.0); -float randf() + +float randf() { return unif_dist(rand_gen); } + uint32_t err_counter = 0; uint32_t warn_counter = 0; struct ue_stats_t { @@ -73,42 +104,26 @@ class log_tester : public srslte::log_filter { public: explicit log_tester(std::string layer) : srslte::log_filter(layer) {} - void error(const char* message, ...) __attribute__((format(printf, 2, 3))); + ~log_tester() final + { + info("[TESTER] UE stats:\n"); + for (auto& e : ue_stats) { + info("0x%x: {DL RBs: %lu, UL RBs: %lu}\n", e.first, e.second.nof_dl_rbs, e.second.nof_ul_rbs); + } + info("[TESTER] This was the seed: %u\n", seed); + } }; -void log_tester::error(const char* message, ...) -{ - if (level >= srslte::LOG_LEVEL_ERROR) { - char* args_msg = NULL; - va_list args; - va_start(args, message); - if (vasprintf(&args_msg, message, args) > 0) - all_log(srslte::LOG_LEVEL_ERROR, tti, args_msg); - va_end(args); - free(args_msg); - } -} log_tester log_out("ALL"); -void log_on_exit() -{ - log_out.info("[TESTER] UE stats:\n"); - for (auto& e : ue_stats) { - log_out.info("0x%x: {DL RBs: %lu, UL RBs: %lu}\n", e.first, e.second.nof_dl_rbs, e.second.nof_ul_rbs); - } - log_out.info("[TESTER] This was the seed: %u\n", seed); -} - #define Warning(fmt, ...) \ log_out.warning(fmt, ##__VA_ARGS__); \ warn_counter++; #define TestError(fmt, ...) \ log_out.error(fmt, ##__VA_ARGS__); \ - log_on_exit(); \ exit(-1); #define CondError(cond, fmt, ...) \ if (cond) { \ log_out.error(fmt, ##__VA_ARGS__); \ - log_on_exit(); \ exit(-1); \ } @@ -119,17 +134,15 @@ void log_on_exit() struct sched_sim_args { struct tti_event_t { struct user_event_t { - uint32_t sr_data; - uint32_t dl_data; - uint32_t dl_nof_retxs; - user_event_t() : sr_data(0), dl_data(0), dl_nof_retxs(0) {} + uint32_t sr_data = 0; + uint32_t dl_data = 0; + uint32_t dl_nof_retxs = 0; }; std::map users; - bool new_user; - bool rem_user; + bool new_user = false; + bool rem_user = false; uint32_t new_rnti; uint32_t rem_rnti; - tti_event_t() : new_user(false), rem_user(false) {} }; std::vector tti_events; @@ -150,8 +163,8 @@ struct sched_tester : public srsenb::sched { 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 = NULL; // fast lookup - srsenb::sched_interface::dl_sched_data_t* dl_sched = NULL; // fast lookup + 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; }; @@ -172,20 +185,18 @@ struct sched_tester : public srsenb::sched { typedef std::map::iterator ue_it_t; }; struct ue_info { - int prach_tti, rar_tti, msg3_tti; + int prach_tti = -1, rar_tti = -1, msg3_tti = -1; srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; srsenb::sched_interface::ue_cfg_t user_cfg; - uint32_t dl_data; - uint32_t ul_data; - ue_info() : prach_tti(-1), rar_tti(-1), msg3_tti(-1), dl_data(0), ul_data(0) {} + uint32_t dl_data = 0; + uint32_t ul_data = 0; }; struct ack_info_t { - uint16_t rnti; - uint32_t tti; - bool dl_ack; - uint32_t retx_delay; + uint16_t rnti; + uint32_t tti; + bool dl_ack = false; + uint32_t retx_delay = 0; srsenb::dl_harq_proc dl_harq; - ack_info_t() : dl_ack(false), retx_delay(0) {} }; struct ul_ack_info_t { uint16_t rnti; @@ -234,8 +245,8 @@ void sched_tester::add_user(uint16_t rnti, info.user_cfg = ue_cfg_; tester_ues.insert(std::make_pair(rnti, info)); - if (ue_cfg(rnti, &ue_cfg_)) { - TestError("[TESTER] Registering new user rnti=0x%x to SCHED\n", rnti); + if (ue_cfg(rnti, &ue_cfg_) != SRSLTE_SUCCESS) { + TestError("[TESTER] Registering new user rnti=0x%x to SCHED\n", rnti) } dl_sched_rar_info_t rar_info = {}; rar_info.prach_tti = tti_data.tti_rx; @@ -312,12 +323,10 @@ void sched_tester::process_tti_args() void sched_tester::before_sched() { - typedef std::map::iterator it_t; - // check pending data buffers - for (it_t it = ue_db.begin(); it != ue_db.end(); ++it) { - uint16_t rnti = it->first; - srsenb::sched_ue* user = &it->second; + for (auto& it : ue_db) { + uint16_t rnti = it.first; + srsenb::sched_ue* user = &it.second; tester_user_results d; srsenb::ul_harq_proc* hul = user->get_ul_harq(tti_data.tti_tx_ul); d.ul_pending_data = get_ul_buffer(rnti); @@ -326,9 +335,9 @@ 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_data.tti_tx_dl); - d.has_dl_retx = (hdl != NULL) and hdl->has_pending_retx(0, tti_data.tti_tx_dl); - d.has_dl_tx = (hdl != NULL) or (it->second.get_empty_dl_harq() != NULL and d.dl_pending_data > 0); - d.has_ul_newtx = not d.has_ul_retx and d.ul_pending_data > 0; + d.has_dl_retx = (hdl != nullptr) and hdl->has_pending_retx(0, tti_data.tti_tx_dl); + d.has_dl_tx = (hdl != nullptr) or (it.second.get_empty_dl_harq() != 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)); tti_data.total_ues.dl_pending_data += d.dl_pending_data; tti_data.total_ues.ul_pending_data += d.ul_pending_data; @@ -449,15 +458,15 @@ void sched_tester::assert_no_empty_allocs() { // Test if allocations only take place for users with pending data or in RAR for (auto& iter : tti_data.ue_data) { - uint16_t rnti = iter.first; - srsenb::sched_ue* user = &ue_db[rnti]; + 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 != NULL and + 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) { // FIXME: 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_data.tti_tx_ul); + // srsenb::ul_harq_proc* hul = user->get_ul_harq(tti_data.tti_tx_ul); iter.second.ul_retx_got_delayed = iter.second.has_ul_retx and iter.second.ul_harq.is_empty(0); tti_data.total_ues.ul_retx_got_delayed |= iter.second.ul_retx_got_delayed; // Retxs cannot give space to newtx allocations @@ -467,9 +476,8 @@ void sched_tester::assert_no_empty_allocs() // There must be allocations if there is pending data/retxs. bool no_dl_allocs = true; - for (std::map::iterator it = tti_data.ue_data.begin(); it != tti_data.ue_data.end(); - ++it) { - if (it->second.dl_sched != NULL) { + for (auto& it : tti_data.ue_data) { + if (it.second.dl_sched != nullptr) { no_dl_allocs = false; } } @@ -629,13 +637,15 @@ void sched_tester::test_harqs() } for (const auto& ue : ue_db) { const auto& hprev = tti_data.ue_data[ue.first].ul_harq; - if (not hprev.has_pending_ack()) + if (not hprev.has_pending_ack()) { 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]; - if (phich.rnti == ue.first) + if (phich.rnti == ue.first) { break; + } } CondError(i == tti_data.sched_result_ul.nof_phich_elems, "[TESTER] harq had pending ack but no phich was allocked\n"); @@ -777,11 +787,11 @@ void sched_tester::test_collisions() CondError(srslte_ra_dl_dci_to_grant( &cfg.cell, &dl_sf, SRSLTE_TM1, false, &tti_data.sched_result_dl.data[i].dci, &grant) == SRSLTE_ERROR, "Failed to decode PDSCH grant\n"); - for (uint32_t i = 0; i < alloc_mask.size(); ++i) { - if (grant.prb_idx[0][i]) { - alloc_mask.set(i); + for (uint32_t j = 0; j < alloc_mask.size(); ++j) { + if (grant.prb_idx[0][j]) { + alloc_mask.set(j); } else { - alloc_mask.reset(i); + alloc_mask.reset(j); } } if ((dl_allocs & alloc_mask).any()) { @@ -798,9 +808,9 @@ void sched_tester::test_collisions() &cfg.cell, &dl_sf, SRSLTE_TM1, false, &tti_data.sched_result_dl.bc[i].dci, &grant) == SRSLTE_ERROR, "Failed to decode PDSCH grant\n"); alloc_mask.reset(); - for (uint32_t i = 0; i < alloc_mask.size(); ++i) { - if (grant.prb_idx[0][i]) { - alloc_mask.set(i); + for (uint32_t j = 0; j < alloc_mask.size(); ++j) { + if (grant.prb_idx[0][j]) { + alloc_mask.set(j); } } if ((dl_allocs & alloc_mask).any()) { @@ -816,11 +826,11 @@ void sched_tester::test_collisions() CondError(srslte_ra_dl_dci_to_grant( &cfg.cell, &dl_sf, SRSLTE_TM1, false, &tti_data.sched_result_dl.rar[i].dci, &grant) == SRSLTE_ERROR, "Failed to decode PDSCH grant\n"); - for (uint32_t i = 0; i < alloc_mask.size(); ++i) { - if (grant.prb_idx[0][i]) { - alloc_mask.set(i); + for (uint32_t j = 0; j < alloc_mask.size(); ++j) { + if (grant.prb_idx[0][j]) { + alloc_mask.set(j); } else { - alloc_mask.reset(i); + alloc_mask.reset(j); } } if ((dl_allocs & alloc_mask).any()) { @@ -924,7 +934,7 @@ void sched_tester::ack_txs() // for (auto it = ue_db.begin(); it != ue_db.end(); ++it) { // uint16_t rnti = it->first; // srsenb::ul_harq_proc* h = ue_db[rnti].get_ul_harq(tti_data.tti_rx); - // if (h != NULL and not h->is_empty()) { + // if (h != nullptr and not h->is_empty()) { // ul_crc_info(tti_data.tti_rx, rnti, ack); // } // } @@ -974,7 +984,7 @@ void test_scheduler_rand(srsenb::sched_interface::cell_cfg_t cell_cfg, const sch srsenb::sched_interface::dl_sched_res_t& sched_result_dl = tester.tti_data.sched_result_dl; srsenb::sched_interface::ul_sched_res_t& sched_result_ul = tester.tti_data.sched_result_ul; - tester.init(NULL, &log_out); + tester.init(nullptr, &log_out); tester.set_metric(&dl_metric, &ul_metric); tester.cell_cfg(&cell_cfg); @@ -1005,6 +1015,7 @@ sched_sim_args rand_sim_params(const srsenb::sched_interface::cell_cfg_t& cell_c float ul_sr_exps[] = {1, 4}; // log rand float dl_data_exps[] = {1, 4}; // log rand uint32_t max_nof_users = 500; + std::uniform_int_distribution<> connection_dur_dist(min_conn_dur, max_conn_dur); bzero(&sim_args.ue_cfg, sizeof(srsenb::sched_interface::ue_cfg_t)); sim_args.ue_cfg.aperiodic_cqi_period = 40; @@ -1029,8 +1040,8 @@ sched_sim_args rand_sim_params(const srsenb::sched_interface::cell_cfg_t& cell_c } } - for (uint32_t i = 0; i < current_rntis.size(); ++i) { - uint32_t rnti = current_rntis[i][0]; + for (auto& current_rnti : current_rntis) { + uint32_t rnti = current_rnti[0]; if (randf() < P_ul_sr) { float exp = ul_sr_exps[0] + randf() * (ul_sr_exps[1] - ul_sr_exps[0]); sim_args.tti_events[tti].users[rnti].sr_data = (uint32_t)pow(10, exp); @@ -1048,7 +1059,7 @@ sched_sim_args rand_sim_params(const srsenb::sched_interface::cell_cfg_t& cell_c std::vector elem(3); elem[0] = rnti_start; elem[1] = tti; - elem[2] = min_conn_dur + rand() % (max_conn_dur - min_conn_dur); + elem[2] = connection_dur_dist(rand_gen); current_rntis.push_back(elem); sim_args.tti_events[tti].new_user = true; sim_args.tti_events[tti].new_rnti = rnti_start++; @@ -1058,11 +1069,10 @@ sched_sim_args rand_sim_params(const srsenb::sched_interface::cell_cfg_t& cell_c return sim_args; } -int main(int argc, char* argv[]) +int main() { printf("[TESTER] This is the chosen seed: %u\n", seed); /* initialize random seed: */ - srand(seed); uint32_t N_runs = 1, nof_ttis = 10240 + 10; for (uint32_t n = 0; n < N_runs; ++n) {