modernize the random sched test

master
Francisco Paisana 5 years ago
parent 3828e03f33
commit ad0b3ce6e2

@ -22,7 +22,6 @@
#include "srsenb/hdr/stack/mac/scheduler.h" #include "srsenb/hdr/stack/mac/scheduler.h"
#include "srsenb/hdr/stack/mac/scheduler_ue.h" #include "srsenb/hdr/stack/mac/scheduler_ue.h"
#include <algorithm> #include <algorithm>
#include <cstdlib>
#include <random> #include <random>
#include <set> #include <set>
#include <srslte/srslte.h> #include <srslte/srslte.h>
@ -37,14 +36,46 @@
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/radio/radio.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 = 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::default_random_engine rand_gen(seed);
std::uniform_real_distribution<float> unif_dist(0, 1.0); std::uniform_real_distribution<float> unif_dist(0, 1.0);
float randf()
float randf()
{ {
return unif_dist(rand_gen); return unif_dist(rand_gen);
} }
uint32_t err_counter = 0; uint32_t err_counter = 0;
uint32_t warn_counter = 0; uint32_t warn_counter = 0;
struct ue_stats_t { struct ue_stats_t {
@ -73,42 +104,26 @@ class log_tester : public srslte::log_filter
{ {
public: public:
explicit log_tester(std::string layer) : srslte::log_filter(layer) {} explicit log_tester(std::string layer) : srslte::log_filter(layer) {}
void error(const char* message, ...) __attribute__((format(printf, 2, 3))); ~log_tester() final
}; {
void log_tester::error(const char* message, ...) info("[TESTER] UE stats:\n");
{ for (auto& e : ue_stats) {
if (level >= srslte::LOG_LEVEL_ERROR) { info("0x%x: {DL RBs: %lu, UL RBs: %lu}\n", e.first, e.second.nof_dl_rbs, e.second.nof_ul_rbs);
char* args_msg = NULL; }
va_list args; info("[TESTER] This was the seed: %u\n", seed);
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"); 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, ...) \ #define Warning(fmt, ...) \
log_out.warning(fmt, ##__VA_ARGS__); \ log_out.warning(fmt, ##__VA_ARGS__); \
warn_counter++; warn_counter++;
#define TestError(fmt, ...) \ #define TestError(fmt, ...) \
log_out.error(fmt, ##__VA_ARGS__); \ log_out.error(fmt, ##__VA_ARGS__); \
log_on_exit(); \
exit(-1); exit(-1);
#define CondError(cond, fmt, ...) \ #define CondError(cond, fmt, ...) \
if (cond) { \ if (cond) { \
log_out.error(fmt, ##__VA_ARGS__); \ log_out.error(fmt, ##__VA_ARGS__); \
log_on_exit(); \
exit(-1); \ exit(-1); \
} }
@ -119,17 +134,15 @@ void log_on_exit()
struct sched_sim_args { struct sched_sim_args {
struct tti_event_t { struct tti_event_t {
struct user_event_t { struct user_event_t {
uint32_t sr_data; uint32_t sr_data = 0;
uint32_t dl_data; uint32_t dl_data = 0;
uint32_t dl_nof_retxs; uint32_t dl_nof_retxs = 0;
user_event_t() : sr_data(0), dl_data(0), dl_nof_retxs(0) {}
}; };
std::map<uint16_t, user_event_t> users; std::map<uint16_t, user_event_t> users;
bool new_user; bool new_user = false;
bool rem_user; bool rem_user = false;
uint32_t new_rnti; uint32_t new_rnti;
uint32_t rem_rnti; uint32_t rem_rnti;
tti_event_t() : new_user(false), rem_user(false) {}
}; };
std::vector<tti_event_t> tti_events; std::vector<tti_event_t> tti_events;
@ -150,8 +163,8 @@ struct sched_tester : public srsenb::sched {
bool has_ul_retx = false; bool has_ul_retx = false;
bool has_ul_newtx = false; ///< *no* retx, but has tx bool has_ul_newtx = false; ///< *no* retx, but has tx
bool ul_retx_got_delayed = false; bool ul_retx_got_delayed = false;
srsenb::sched_interface::ul_sched_data_t* ul_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 = NULL; // 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::dl_harq_proc dl_harqs[2 * FDD_HARQ_DELAY_MS];
srsenb::ul_harq_proc ul_harq; srsenb::ul_harq_proc ul_harq;
}; };
@ -172,20 +185,18 @@ struct sched_tester : public srsenb::sched {
typedef std::map<uint16_t, tester_user_results>::iterator ue_it_t; typedef std::map<uint16_t, tester_user_results>::iterator ue_it_t;
}; };
struct ue_info { 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_bearer_cfg_t bearer_cfg;
srsenb::sched_interface::ue_cfg_t user_cfg; srsenb::sched_interface::ue_cfg_t user_cfg;
uint32_t dl_data; uint32_t dl_data = 0;
uint32_t ul_data; uint32_t ul_data = 0;
ue_info() : prach_tti(-1), rar_tti(-1), msg3_tti(-1), dl_data(0), ul_data(0) {}
}; };
struct ack_info_t { struct ack_info_t {
uint16_t rnti; uint16_t rnti;
uint32_t tti; uint32_t tti;
bool dl_ack; bool dl_ack = false;
uint32_t retx_delay; uint32_t retx_delay = 0;
srsenb::dl_harq_proc dl_harq; srsenb::dl_harq_proc dl_harq;
ack_info_t() : dl_ack(false), retx_delay(0) {}
}; };
struct ul_ack_info_t { struct ul_ack_info_t {
uint16_t rnti; uint16_t rnti;
@ -234,8 +245,8 @@ void sched_tester::add_user(uint16_t rnti,
info.user_cfg = ue_cfg_; info.user_cfg = ue_cfg_;
tester_ues.insert(std::make_pair(rnti, info)); tester_ues.insert(std::make_pair(rnti, info));
if (ue_cfg(rnti, &ue_cfg_)) { if (ue_cfg(rnti, &ue_cfg_) != SRSLTE_SUCCESS) {
TestError("[TESTER] Registering new user rnti=0x%x to SCHED\n", rnti); TestError("[TESTER] Registering new user rnti=0x%x to SCHED\n", rnti)
} }
dl_sched_rar_info_t rar_info = {}; dl_sched_rar_info_t rar_info = {};
rar_info.prach_tti = tti_data.tti_rx; rar_info.prach_tti = tti_data.tti_rx;
@ -312,12 +323,10 @@ void sched_tester::process_tti_args()
void sched_tester::before_sched() void sched_tester::before_sched()
{ {
typedef std::map<uint16_t, srsenb::sched_ue>::iterator it_t;
// check pending data buffers // check pending data buffers
for (it_t it = ue_db.begin(); it != ue_db.end(); ++it) { for (auto& it : ue_db) {
uint16_t rnti = it->first; uint16_t rnti = it.first;
srsenb::sched_ue* user = &it->second; srsenb::sched_ue* user = &it.second;
tester_user_results d; tester_user_results d;
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);
d.ul_pending_data = get_ul_buffer(rnti); 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_retx = hul->has_pending_retx();
d.has_ul_tx = d.has_ul_retx or d.ul_pending_data > 0; 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); 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_retx = (hdl != nullptr) 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_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; 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.ue_data.insert(std::make_pair(rnti, d));
tti_data.total_ues.dl_pending_data += d.dl_pending_data; tti_data.total_ues.dl_pending_data += d.dl_pending_data;
tti_data.total_ues.ul_pending_data += d.ul_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 // Test if allocations only take place for users with pending data or in RAR
for (auto& iter : tti_data.ue_data) { for (auto& iter : tti_data.ue_data) {
uint16_t rnti = iter.first; uint16_t rnti = iter.first;
srsenb::sched_ue* user = &ue_db[rnti]; // 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) { tti_data.ue_data[rnti].ul_sched->needs_pdcch) {
// FIXME: This test does not work for adaptive re-tx // FIXME: This test does not work for adaptive re-tx
TestError("[TESTER] There was a user without data that got allocated in UL\n"); 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); 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; tti_data.total_ues.ul_retx_got_delayed |= iter.second.ul_retx_got_delayed;
// Retxs cannot give space to newtx allocations // 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. // There must be allocations if there is pending data/retxs.
bool no_dl_allocs = true; bool no_dl_allocs = true;
for (std::map<uint16_t, tester_user_results>::iterator it = tti_data.ue_data.begin(); it != tti_data.ue_data.end(); for (auto& it : tti_data.ue_data) {
++it) { if (it.second.dl_sched != nullptr) {
if (it->second.dl_sched != NULL) {
no_dl_allocs = false; no_dl_allocs = false;
} }
} }
@ -629,13 +637,15 @@ void sched_tester::test_harqs()
} }
for (const auto& ue : ue_db) { for (const auto& ue : ue_db) {
const auto& hprev = tti_data.ue_data[ue.first].ul_harq; const auto& hprev = tti_data.ue_data[ue.first].ul_harq;
if (not hprev.has_pending_ack()) if (not hprev.has_pending_ack()) {
continue; continue;
}
uint32_t i = 0; uint32_t i = 0;
for (; i < tti_data.sched_result_ul.nof_phich_elems; ++i) { for (; i < tti_data.sched_result_ul.nof_phich_elems; ++i) {
const auto& phich = tti_data.sched_result_ul.phich[i]; const auto& phich = tti_data.sched_result_ul.phich[i];
if (phich.rnti == ue.first) if (phich.rnti == ue.first) {
break; break;
}
} }
CondError(i == tti_data.sched_result_ul.nof_phich_elems, CondError(i == tti_data.sched_result_ul.nof_phich_elems,
"[TESTER] harq had pending ack but no phich was allocked\n"); "[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( 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, &cfg.cell, &dl_sf, SRSLTE_TM1, false, &tti_data.sched_result_dl.data[i].dci, &grant) == SRSLTE_ERROR,
"Failed to decode PDSCH grant\n"); "Failed to decode PDSCH grant\n");
for (uint32_t i = 0; i < alloc_mask.size(); ++i) { for (uint32_t j = 0; j < alloc_mask.size(); ++j) {
if (grant.prb_idx[0][i]) { if (grant.prb_idx[0][j]) {
alloc_mask.set(i); alloc_mask.set(j);
} else { } else {
alloc_mask.reset(i); alloc_mask.reset(j);
} }
} }
if ((dl_allocs & alloc_mask).any()) { 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, &cfg.cell, &dl_sf, SRSLTE_TM1, false, &tti_data.sched_result_dl.bc[i].dci, &grant) == SRSLTE_ERROR,
"Failed to decode PDSCH grant\n"); "Failed to decode PDSCH grant\n");
alloc_mask.reset(); alloc_mask.reset();
for (uint32_t i = 0; i < alloc_mask.size(); ++i) { for (uint32_t j = 0; j < alloc_mask.size(); ++j) {
if (grant.prb_idx[0][i]) { if (grant.prb_idx[0][j]) {
alloc_mask.set(i); alloc_mask.set(j);
} }
} }
if ((dl_allocs & alloc_mask).any()) { if ((dl_allocs & alloc_mask).any()) {
@ -816,11 +826,11 @@ void sched_tester::test_collisions()
CondError(srslte_ra_dl_dci_to_grant( 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, &cfg.cell, &dl_sf, SRSLTE_TM1, false, &tti_data.sched_result_dl.rar[i].dci, &grant) == SRSLTE_ERROR,
"Failed to decode PDSCH grant\n"); "Failed to decode PDSCH grant\n");
for (uint32_t i = 0; i < alloc_mask.size(); ++i) { for (uint32_t j = 0; j < alloc_mask.size(); ++j) {
if (grant.prb_idx[0][i]) { if (grant.prb_idx[0][j]) {
alloc_mask.set(i); alloc_mask.set(j);
} else { } else {
alloc_mask.reset(i); alloc_mask.reset(j);
} }
} }
if ((dl_allocs & alloc_mask).any()) { 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) { // for (auto it = ue_db.begin(); it != ue_db.end(); ++it) {
// uint16_t rnti = it->first; // uint16_t rnti = it->first;
// srsenb::ul_harq_proc* h = ue_db[rnti].get_ul_harq(tti_data.tti_rx); // 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); // 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::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; 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.set_metric(&dl_metric, &ul_metric);
tester.cell_cfg(&cell_cfg); 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 ul_sr_exps[] = {1, 4}; // log rand
float dl_data_exps[] = {1, 4}; // log rand float dl_data_exps[] = {1, 4}; // log rand
uint32_t max_nof_users = 500; 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)); bzero(&sim_args.ue_cfg, sizeof(srsenb::sched_interface::ue_cfg_t));
sim_args.ue_cfg.aperiodic_cqi_period = 40; 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) { for (auto& current_rnti : current_rntis) {
uint32_t rnti = current_rntis[i][0]; uint32_t rnti = current_rnti[0];
if (randf() < P_ul_sr) { if (randf() < P_ul_sr) {
float exp = ul_sr_exps[0] + randf() * (ul_sr_exps[1] - ul_sr_exps[0]); 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); 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<uint32_t> elem(3); std::vector<uint32_t> elem(3);
elem[0] = rnti_start; elem[0] = rnti_start;
elem[1] = tti; 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); current_rntis.push_back(elem);
sim_args.tti_events[tti].new_user = true; sim_args.tti_events[tti].new_user = true;
sim_args.tti_events[tti].new_rnti = rnti_start++; 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; return sim_args;
} }
int main(int argc, char* argv[]) int main()
{ {
printf("[TESTER] This is the chosen seed: %u\n", seed); printf("[TESTER] This is the chosen seed: %u\n", seed);
/* initialize random seed: */ /* initialize random seed: */
srand(seed);
uint32_t N_runs = 1, nof_ttis = 10240 + 10; uint32_t N_runs = 1, nof_ttis = 10240 + 10;
for (uint32_t n = 0; n < N_runs; ++n) { for (uint32_t n = 0; n < N_runs; ++n) {

Loading…
Cancel
Save