mirror of https://github.com/PentHertz/srsLTE.git
started to use a type-safe tti counter for comparisons. Uniformized the common_sched_tester api. Next, need to use the same struct to register events.
This commit is contained in:
parent
518f813f13
commit
385fa226e0
|
@ -26,17 +26,7 @@
|
|||
|
||||
using namespace srsenb;
|
||||
|
||||
template <class MapContainer, class Predicate>
|
||||
void erase_if(MapContainer& c, Predicate should_remove)
|
||||
{
|
||||
for (auto it = c.begin(); it != c.end();) {
|
||||
if (should_remove(*it)) {
|
||||
it = c.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t const seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
|
||||
/*******************
|
||||
* Logging *
|
||||
|
@ -61,100 +51,13 @@ srslte::scoped_log<sched_test_log> log_global{};
|
|||
* Scheduler Tester for CA
|
||||
*****************************/
|
||||
|
||||
class sched_ca_tester : public srsenb::sched
|
||||
class sched_ca_tester : public common_sched_tester
|
||||
{
|
||||
public:
|
||||
struct tti_info_t {
|
||||
tti_params_t tti_params{10241};
|
||||
uint32_t nof_prachs = 0;
|
||||
std::vector<sched_interface::dl_sched_res_t> dl_sched_result;
|
||||
std::vector<sched_interface::ul_sched_res_t> ul_sched_result;
|
||||
};
|
||||
|
||||
int cell_cfg(const std::vector<cell_cfg_t>& cell_params) final;
|
||||
int add_user(uint16_t rnti, const ue_cfg_t& ue_cfg_);
|
||||
void new_test_tti(uint32_t tti_rx);
|
||||
int process_tti_events(const tti_ev& tti_events);
|
||||
int process_ack_txs();
|
||||
int set_acks();
|
||||
|
||||
void run_tti(uint32_t tti, const tti_ev& tti_events);
|
||||
|
||||
int process_results();
|
||||
|
||||
// args
|
||||
sim_sched_args sim_args; ///< arguments used to generate TTI events
|
||||
|
||||
// tti specific params
|
||||
tti_info_t tti_info;
|
||||
uint32_t tti_counter = 0;
|
||||
|
||||
// testers
|
||||
std::vector<output_sched_tester> output_tester;
|
||||
std::unique_ptr<user_state_sched_tester> ue_tester;
|
||||
std::unique_ptr<sched_result_stats> sched_stats;
|
||||
|
||||
private:
|
||||
struct ack_info_t {
|
||||
uint16_t rnti;
|
||||
uint32_t tti;
|
||||
uint32_t ue_cc_idx;
|
||||
bool ack = false;
|
||||
uint32_t retx_delay = 0;
|
||||
srsenb::dl_harq_proc dl_harq;
|
||||
};
|
||||
struct ul_ack_info_t {
|
||||
uint16_t rnti;
|
||||
uint32_t tti_ack, tti_tx_ul;
|
||||
uint32_t ue_cc_idx;
|
||||
bool ack = false;
|
||||
srsenb::ul_harq_proc ul_harq;
|
||||
};
|
||||
|
||||
std::multimap<uint32_t, ack_info_t> to_ack;
|
||||
std::multimap<uint32_t, ul_ack_info_t> to_ul_ack;
|
||||
int process_tti_events(const tti_ev& tti_events);
|
||||
int run_tti(const tti_ev& tti_events) override;
|
||||
};
|
||||
|
||||
int sched_ca_tester::cell_cfg(const std::vector<cell_cfg_t>& 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) {
|
||||
output_tester.emplace_back(sched_cell_params[i]);
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int sched_ca_tester::add_user(uint16_t rnti, const ue_cfg_t& ue_cfg_)
|
||||
{
|
||||
CONDERROR(ue_cfg(rnti, ue_cfg_) != SRSLTE_SUCCESS, "[TESTER] Configuring new user rnti=0x%x to sched\n", rnti);
|
||||
|
||||
dl_sched_rar_info_t rar_info = {};
|
||||
rar_info.prach_tti = tti_info.tti_params.tti_rx;
|
||||
rar_info.temp_crnti = rnti;
|
||||
rar_info.msg3_size = 7;
|
||||
rar_info.preamble_idx = tti_info.nof_prachs++;
|
||||
uint32_t pcell_idx = ue_cfg_.supported_cc_list[0].enb_cc_idx;
|
||||
dl_rach_info(pcell_idx, rar_info);
|
||||
|
||||
ue_tester->add_user(rnti, rar_info.preamble_idx, ue_cfg_);
|
||||
|
||||
log_global->info("[TESTER] Adding user rnti=0x%x\n", rnti);
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void sched_ca_tester::new_test_tti(uint32_t tti_rx)
|
||||
{
|
||||
tti_info.tti_params = tti_params_t{tti_rx};
|
||||
tti_info.nof_prachs = 0;
|
||||
tti_info.dl_sched_result.clear();
|
||||
tti_info.ul_sched_result.clear();
|
||||
ue_tester->new_tti(tti_rx);
|
||||
}
|
||||
|
||||
int sched_ca_tester::process_tti_events(const tti_ev& tti_ev)
|
||||
{
|
||||
for (const tti_ev::user_cfg_ev& ue_ev : tti_ev.user_updates) {
|
||||
|
@ -192,9 +95,9 @@ int sched_ca_tester::process_tti_events(const tti_ev& tti_ev)
|
|||
|
||||
if (ue_ev.buffer_ev->dl_data > 0) {
|
||||
// If Msg3 has already been received
|
||||
if (user->msg3_tti >= 0 and (uint32_t) user->msg3_tti <= tti_info.tti_params.tti_rx) {
|
||||
if (user->msg3_tic.is_valid() and user->msg3_tic <= tic) {
|
||||
// If Msg4 not yet sent, allocate data in SRB0 buffer
|
||||
uint32_t lcid = (user->msg4_tti >= 0) ? 2 : 0;
|
||||
uint32_t lcid = (user->msg4_tic.is_valid()) ? 2 : 0;
|
||||
uint32_t pending_dl_new_data = ue_db[ue_ev.rnti].get_pending_dl_new_data();
|
||||
if (lcid == 2 and not user->drb_cfg_flag) {
|
||||
// If RRCSetup finished
|
||||
|
@ -226,99 +129,10 @@ int sched_ca_tester::process_tti_events(const tti_ev& tti_ev)
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int sched_ca_tester::process_ack_txs()
|
||||
int sched_ca_tester::run_tti(const tti_ev& tti_events)
|
||||
{
|
||||
/* check if user was removed. If so, clean respective acks */
|
||||
erase_if(to_ack,
|
||||
[this](std::pair<const uint32_t, ack_info_t>& elem) { return this->ue_db.count(elem.second.rnti) == 0; });
|
||||
erase_if(to_ul_ack,
|
||||
[this](std::pair<const uint32_t, ul_ack_info_t>& elem) { return this->ue_db.count(elem.second.rnti) == 0; });
|
||||
|
||||
/* Ack DL HARQs */
|
||||
for (const auto& ack_it : to_ack) {
|
||||
if (ack_it.second.tti != tti_info.tti_params.tti_rx) {
|
||||
continue;
|
||||
}
|
||||
const ack_info_t& dl_ack = ack_it.second;
|
||||
|
||||
srsenb::dl_harq_proc* h = ue_db[dl_ack.rnti].get_dl_harq(ack_it.second.dl_harq.get_id(), dl_ack.ue_cc_idx);
|
||||
const srsenb::dl_harq_proc& hack = dl_ack.dl_harq;
|
||||
CONDERROR(hack.is_empty(), "[TESTER] The acked DL harq was not active\n");
|
||||
|
||||
bool ret = false;
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; ++tb) {
|
||||
if (dl_ack.dl_harq.is_empty(tb)) {
|
||||
continue;
|
||||
}
|
||||
ret |= dl_ack_info(tti_info.tti_params.tti_rx, dl_ack.rnti, dl_ack.ue_cc_idx, tb, dl_ack.ack) > 0;
|
||||
}
|
||||
CONDERROR(not ret, "[TESTER] The dl harq proc that was ACKed does not exist\n");
|
||||
|
||||
if (dl_ack.ack) {
|
||||
CONDERROR(!h->is_empty(), "[TESTER] ACKed dl harq was not emptied\n");
|
||||
CONDERROR(h->has_pending_retx(0, tti_info.tti_params.tti_tx_dl),
|
||||
"[TESTER] ACKed dl harq still has pending retx\n");
|
||||
log_global->info("[TESTER] DL ACK tti=%u rnti=0x%x pid=%d\n",
|
||||
tti_info.tti_params.tti_rx,
|
||||
dl_ack.rnti,
|
||||
dl_ack.dl_harq.get_id());
|
||||
} else {
|
||||
CONDERROR(h->is_empty() and hack.nof_retx(0) + 1 < hack.max_nof_retx(), "[TESTER] NACKed DL harq got emptied\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Ack UL HARQs */
|
||||
for (const auto& ack_it : to_ul_ack) {
|
||||
if (ack_it.first != tti_info.tti_params.tti_rx) {
|
||||
continue;
|
||||
}
|
||||
const ul_ack_info_t& ul_ack = ack_it.second;
|
||||
|
||||
srsenb::ul_harq_proc* h = ue_db[ul_ack.rnti].get_ul_harq(tti_info.tti_params.tti_rx, ul_ack.ue_cc_idx);
|
||||
const srsenb::ul_harq_proc& hack = ul_ack.ul_harq;
|
||||
CONDERROR(h == nullptr or h->get_tti() != hack.get_tti(), "[TESTER] UL Harq TTI does not match the ACK TTI\n");
|
||||
CONDERROR(h->is_empty(0), "[TESTER] The acked UL harq is not active\n");
|
||||
CONDERROR(hack.is_empty(0), "[TESTER] The acked UL harq was not active\n");
|
||||
|
||||
ul_crc_info(tti_info.tti_params.tti_rx, ul_ack.rnti, ul_ack.ue_cc_idx, ul_ack.ack);
|
||||
|
||||
CONDERROR(!h->get_pending_data(), "[TESTER] UL harq lost its pending data\n");
|
||||
CONDERROR(!h->has_pending_ack(), "[TESTER] ACK/NACKed UL harq should have a pending ACK\n");
|
||||
|
||||
if (ul_ack.ack) {
|
||||
CONDERROR(!h->is_empty(), "[TESTER] ACKed UL harq did not get emptied\n");
|
||||
CONDERROR(h->has_pending_retx(), "[TESTER] ACKed UL harq still has pending retx\n");
|
||||
log_global->info(
|
||||
"[TESTER] UL ACK tti=%u rnti=0x%x pid=%d\n", tti_info.tti_params.tti_rx, ul_ack.rnti, hack.get_id());
|
||||
} else {
|
||||
// NACK
|
||||
CONDERROR(!h->is_empty() and !h->has_pending_retx(), "[TESTER] If NACKed, UL harq has to have pending retx\n");
|
||||
CONDERROR(h->is_empty() and hack.nof_retx(0) + 1 < hack.max_nof_retx(),
|
||||
"[TESTER] Nacked UL harq did get emptied\n");
|
||||
}
|
||||
}
|
||||
|
||||
// erase processed acks
|
||||
to_ack.erase(tti_info.tti_params.tti_rx);
|
||||
to_ul_ack.erase(tti_info.tti_params.tti_rx);
|
||||
|
||||
// bool ack = true; //(tti_data.tti_rx % 3) == 0;
|
||||
// if (tti_data.tti_rx >= FDD_HARQ_DELAY_MS) {
|
||||
// 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 != nullptr and not h->is_empty()) {
|
||||
// ul_crc_info(tti_data.tti_rx, rnti, ack);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void sched_ca_tester::run_tti(uint32_t tti_rx, const tti_ev& tti_events)
|
||||
{
|
||||
new_test_tti(tti_rx);
|
||||
log_global->info("[TESTER] ---- tti=%u | nof_ues=%zd ----\n", tti_rx, ue_db.size());
|
||||
new_test_tti();
|
||||
log_global->info("[TESTER] ---- tti=%u | nof_ues=%zd ----\n", tic.tti_rx(), ue_db.size());
|
||||
|
||||
process_tti_events(tti_events);
|
||||
process_ack_txs();
|
||||
|
@ -335,76 +149,7 @@ 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()
|
||||
{
|
||||
for (uint32_t i = 0; i < sched_cell_params.size(); ++i) {
|
||||
TESTASSERT(ue_tester->test_all(i, tti_info.dl_sched_result[i], tti_info.ul_sched_result[i]) == SRSLTE_SUCCESS);
|
||||
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;
|
||||
}
|
||||
|
||||
int sched_ca_tester::set_acks()
|
||||
{
|
||||
for (uint32_t ccidx = 0; ccidx < sched_cell_params.size(); ++ccidx) {
|
||||
// schedule future acks
|
||||
for (uint32_t i = 0; i < tti_info.dl_sched_result[ccidx].nof_data_elems; ++i) {
|
||||
ack_info_t ack_data;
|
||||
ack_data.rnti = tti_info.dl_sched_result[ccidx].data[i].dci.rnti;
|
||||
ack_data.tti = FDD_HARQ_DELAY_MS + tti_info.tti_params.tti_tx_dl;
|
||||
ack_data.ue_cc_idx = ue_db[ack_data.rnti].get_cell_index(ccidx).second;
|
||||
const srsenb::dl_harq_proc* dl_h =
|
||||
ue_db[ack_data.rnti].get_dl_harq(tti_info.dl_sched_result[ccidx].data[i].dci.pid, ccidx);
|
||||
ack_data.dl_harq = *dl_h;
|
||||
if (ack_data.dl_harq.nof_retx(0) == 0) {
|
||||
ack_data.ack = randf() > sim_args.P_retx;
|
||||
} else { // always ack after three retxs
|
||||
ack_data.ack = ack_data.dl_harq.nof_retx(0) == 3;
|
||||
}
|
||||
|
||||
// Remove harq from the ack list if there was a harq rewrite
|
||||
auto it = to_ack.begin();
|
||||
while (it != to_ack.end() and it->first < ack_data.tti) {
|
||||
if (it->second.rnti == ack_data.rnti and it->second.dl_harq.get_id() == ack_data.dl_harq.get_id() and
|
||||
it->second.ue_cc_idx == ack_data.ue_cc_idx) {
|
||||
CONDERROR(it->second.tti + 2 * FDD_HARQ_DELAY_MS > ack_data.tti,
|
||||
"[TESTER] The retx dl harq id=%d was transmitted too soon\n",
|
||||
ack_data.dl_harq.get_id());
|
||||
auto toerase_it = it++;
|
||||
to_ack.erase(toerase_it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
// add new ack to the list
|
||||
to_ack.insert(std::make_pair(ack_data.tti, ack_data));
|
||||
}
|
||||
|
||||
/* Schedule UL ACKs */
|
||||
for (uint32_t i = 0; i < tti_info.ul_sched_result[ccidx].nof_dci_elems; ++i) {
|
||||
const auto& pusch = tti_info.ul_sched_result[ccidx].pusch[i];
|
||||
ul_ack_info_t ack_data;
|
||||
ack_data.rnti = pusch.dci.rnti;
|
||||
ack_data.ul_harq = *ue_db[ack_data.rnti].get_ul_harq(tti_info.tti_params.tti_tx_ul, ccidx);
|
||||
ack_data.tti_tx_ul = tti_info.tti_params.tti_tx_ul;
|
||||
ack_data.tti_ack = tti_info.tti_params.tti_tx_ul + FDD_HARQ_DELAY_MS;
|
||||
ack_data.ue_cc_idx = ue_db[ack_data.rnti].get_cell_index(ccidx).second;
|
||||
if (ack_data.ul_harq.nof_retx(0) == 0) {
|
||||
ack_data.ack = randf() > sim_args.P_retx;
|
||||
} else {
|
||||
ack_data.ack = ack_data.ul_harq.nof_retx(0) == 3;
|
||||
}
|
||||
to_ul_ack.insert(std::make_pair(ack_data.tti_tx_ul, ack_data));
|
||||
}
|
||||
}
|
||||
schedule_acks();
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -416,8 +161,7 @@ sim_sched_args generate_default_sim_args(uint32_t nof_prb, uint32_t nof_ccs)
|
|||
{
|
||||
sim_sched_args sim_args;
|
||||
|
||||
sim_args.nof_ttis = 10240 + 10;
|
||||
sim_args.P_retx = 0.1;
|
||||
sim_args.P_retx = 0.1;
|
||||
|
||||
sim_args.ue_cfg = generate_default_ue_cfg();
|
||||
|
||||
|
@ -448,36 +192,40 @@ sim_sched_args generate_default_sim_args(uint32_t nof_prb, uint32_t nof_ccs)
|
|||
int run_sim1()
|
||||
{
|
||||
/* Simulation Configuration Arguments */
|
||||
uint32_t nof_prb = 25;
|
||||
uint32_t nof_ccs = 2;
|
||||
uint32_t nof_prb = 25;
|
||||
uint32_t nof_ccs = 2;
|
||||
uint32_t start_tti = 0; // rand_int(0, 10240);
|
||||
|
||||
/* Setup simulation arguments struct */
|
||||
sim_sched_args sim_args = generate_default_sim_args(nof_prb, nof_ccs);
|
||||
sim_args.sim_log = log_global.get();
|
||||
sim_args.start_tti = start_tti;
|
||||
|
||||
/* 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);
|
||||
tester.sim_cfg(sim_args);
|
||||
|
||||
/* 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]);
|
||||
}
|
||||
};
|
||||
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_count) % 10240;
|
||||
// log_global->step(tti);
|
||||
// tester.run_tti(generator.tti_events[tester.tti_count]);
|
||||
// }
|
||||
// };
|
||||
|
||||
/* Simulation */
|
||||
|
||||
|
@ -486,13 +234,13 @@ int run_sim1()
|
|||
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();
|
||||
tester.test_next_ttis(generator.tti_events);
|
||||
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();
|
||||
tester.test_next_ttis(generator.tti_events);
|
||||
|
||||
// Event (20 TTIs): Data back and forth
|
||||
auto generate_data = [&](uint32_t nof_ttis, float prob_dl, float prob_ul) {
|
||||
|
@ -510,7 +258,7 @@ int run_sim1()
|
|||
}
|
||||
};
|
||||
generate_data(20, P_dl, P_ul_sr);
|
||||
process_ttis();
|
||||
tester.test_next_ttis(generator.tti_events);
|
||||
|
||||
// Event: Reconf Complete. Activate SCells. Check if CE correctly transmitted
|
||||
generator.step_tti();
|
||||
|
@ -521,7 +269,7 @@ int run_sim1()
|
|||
user->ue_cfg->supported_cc_list[i].active = true;
|
||||
user->ue_cfg->supported_cc_list[i].enb_cc_idx = i;
|
||||
}
|
||||
process_ttis();
|
||||
tester.test_next_ttis(generator.tti_events);
|
||||
// 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);
|
||||
|
@ -532,14 +280,14 @@ int run_sim1()
|
|||
break;
|
||||
}
|
||||
generator.step_tti();
|
||||
process_ttis();
|
||||
tester.test_next_ttis(generator.tti_events);
|
||||
// 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();
|
||||
tester.test_next_ttis(generator.tti_events);
|
||||
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);
|
||||
|
@ -551,6 +299,9 @@ int run_sim1()
|
|||
|
||||
int main()
|
||||
{
|
||||
// Setup rand seed
|
||||
set_randseed(seed);
|
||||
|
||||
srslte::logmap::get_instance()->set_default_log_level(srslte::LOG_LEVEL_INFO);
|
||||
printf("[TESTER] This is the chosen seed: %u\n", seed);
|
||||
uint32_t N_runs = 1;
|
||||
|
|
|
@ -29,6 +29,32 @@
|
|||
|
||||
using namespace srsenb;
|
||||
|
||||
/***************************
|
||||
* Random Utils
|
||||
**************************/
|
||||
|
||||
std::default_random_engine rand_gen;
|
||||
|
||||
float ::srsenb::randf()
|
||||
{
|
||||
static std::uniform_real_distribution<float> unif_dist(0, 1.0);
|
||||
return unif_dist(rand_gen);
|
||||
}
|
||||
|
||||
void ::srsenb::set_randseed(uint64_t seed)
|
||||
{
|
||||
rand_gen = std::default_random_engine(seed);
|
||||
}
|
||||
|
||||
std::default_random_engine& ::srsenb::get_rand_gen()
|
||||
{
|
||||
return rand_gen;
|
||||
}
|
||||
|
||||
/***************************
|
||||
* Sched Testers
|
||||
**************************/
|
||||
|
||||
int output_sched_tester::test_pusch_collisions(const tti_params_t& tti_params,
|
||||
const sched_interface::ul_sched_res_t& ul_result,
|
||||
prbmask_t& ul_allocs) const
|
||||
|
@ -294,6 +320,11 @@ int srsenb::extract_dl_prbmask(const srslte_cell_t& cell,
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void user_state_sched_tester::new_tti(uint32_t tti_rx)
|
||||
{
|
||||
tic++;
|
||||
}
|
||||
|
||||
int user_state_sched_tester::add_user(uint16_t rnti,
|
||||
uint32_t preamble_idx,
|
||||
const srsenb::sched_interface::ue_cfg_t& ue_cfg)
|
||||
|
@ -301,7 +332,7 @@ int user_state_sched_tester::add_user(uint16_t r
|
|||
TESTASSERT(users.count(rnti) == 0);
|
||||
ue_state ue;
|
||||
ue.user_cfg = ue_cfg;
|
||||
ue.prach_tti = tti_params.tti_rx;
|
||||
ue.prach_tic = tic;
|
||||
ue.preamble_idx = preamble_idx;
|
||||
users.insert(std::make_pair(rnti, ue));
|
||||
return SRSLTE_SUCCESS;
|
||||
|
@ -361,89 +392,104 @@ int user_state_sched_tester::test_ra(uint32_t enb_
|
|||
// No UL allocations before Msg3
|
||||
for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) {
|
||||
if (ul_result.pusch[i].dci.rnti == rnti) {
|
||||
CONDERROR(ul_result.pusch[i].needs_pdcch and userinfo.msg3_tti < 0,
|
||||
CONDERROR(ul_result.pusch[i].needs_pdcch and not userinfo.msg3_tic.is_valid(),
|
||||
"[TESTER] No UL data allocation allowed before Msg3\n");
|
||||
CONDERROR(userinfo.rar_tti < 0, "[TESTER] No UL allocation allowed before RAR\n");
|
||||
uint32_t msg3_tti = (uint32_t)(userinfo.rar_tti + FDD_HARQ_DELAY_MS + MSG3_DELAY_MS) % 10240;
|
||||
CONDERROR(msg3_tti > tti_params.tti_tx_ul, "No UL allocs allowed before Msg3 alloc\n");
|
||||
CONDERROR(not userinfo.rar_tic.is_valid(), "[TESTER] No UL allocs allowed before RAR\n");
|
||||
tti_counter msg3_tic = userinfo.rar_tic + FDD_HARQ_DELAY_MS + MSG3_DELAY_MS;
|
||||
CONDERROR(msg3_tic > tic.tic_tx_ul(), "No UL allocs allowed before Msg3 alloc\n");
|
||||
}
|
||||
}
|
||||
|
||||
// No DL data allocations before Msg3 is received
|
||||
for (uint32_t i = 0; i < dl_result.nof_data_elems; ++i) {
|
||||
if (dl_result.data[i].dci.rnti == rnti) {
|
||||
CONDERROR(userinfo.msg3_tti < 0, "[TESTER] No DL data alloc allowed before Msg3 alloc\n");
|
||||
CONDERROR(tti_params.tti_rx < (uint32_t)userinfo.msg3_tti,
|
||||
"[TESTER] Msg4 cannot be tx without Msg3 being received\n");
|
||||
CONDERROR(not userinfo.msg3_tic.is_valid(), "[TESTER] No DL data alloc allowed before Msg3 alloc\n");
|
||||
CONDERROR(tic < userinfo.msg3_tic, "[TESTER] Msg4 cannot be tx without Msg3 being received\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (enb_cc_idx != userinfo.user_cfg.supported_cc_list[0].enb_cc_idx) {
|
||||
uint32_t primary_cc_idx = userinfo.user_cfg.supported_cc_list[0].enb_cc_idx;
|
||||
if (enb_cc_idx != primary_cc_idx) {
|
||||
// only check for RAR/Msg3 presence for a UE's PCell
|
||||
continue;
|
||||
}
|
||||
|
||||
// No RAR allocations outside of rar_window
|
||||
uint32_t prach_tti = (uint32_t)userinfo.prach_tti;
|
||||
uint32_t primary_cc_idx = userinfo.user_cfg.supported_cc_list[0].enb_cc_idx;
|
||||
std::array<uint32_t, 2> rar_window = {prach_tti + 3, prach_tti + 3 + cell_params[primary_cc_idx].prach_rar_window};
|
||||
std::array<tti_counter, 2> rar_window = {
|
||||
userinfo.prach_tic + 3, userinfo.prach_tic + 3 + (int)cell_params[primary_cc_idx].prach_rar_window};
|
||||
|
||||
CONDERROR(userinfo.rar_tti < 0 and tti_params.tti_tx_dl > rar_window[1],
|
||||
tti_counter tic_tx_dl = tic.tic_tx_dl();
|
||||
CONDERROR(not userinfo.rar_tic.is_valid() and tic.tic_tx_dl() > rar_window[1],
|
||||
"[TESTER] RAR not scheduled within the RAR Window\n");
|
||||
if (tti_params.tti_tx_dl <= rar_window[1] and tti_params.tti_tx_dl >= rar_window[0]) {
|
||||
if (tic_tx_dl <= rar_window[1] and tic_tx_dl >= rar_window[0]) {
|
||||
// Inside RAR window
|
||||
for (uint32_t i = 0; i < dl_result.nof_rar_elems; ++i) {
|
||||
for (uint32_t j = 0; j < dl_result.rar[i].nof_grants; ++j) {
|
||||
auto& data = dl_result.rar[i].msg3_grant[j].data;
|
||||
if (data.prach_tti == (uint32_t)userinfo.prach_tti and data.preamble_idx == userinfo.preamble_idx) {
|
||||
CONDERROR(userinfo.rar_tti >= 0, "There was more than one RAR for the same user\n");
|
||||
userinfo.rar_tti = tti_params.tti_tx_dl;
|
||||
if (data.prach_tti == (uint32_t)userinfo.prach_tic.tti_rx() and data.preamble_idx == userinfo.preamble_idx) {
|
||||
CONDERROR(userinfo.rar_tic.is_valid(), "There was more than one RAR for the same user\n");
|
||||
userinfo.rar_tic = tic_tx_dl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether Msg3 was allocated in expected TTI
|
||||
if (userinfo.rar_tti >= 0) {
|
||||
uint32_t expected_msg3_tti = (uint32_t)(userinfo.rar_tti + FDD_HARQ_DELAY_MS + MSG3_DELAY_MS) % 10240;
|
||||
if (expected_msg3_tti == tti_params.tti_tx_ul) {
|
||||
if (userinfo.rar_tic.is_valid()) {
|
||||
tti_counter expected_msg3_tti = userinfo.rar_tic + FDD_HARQ_DELAY_MS + MSG3_DELAY_MS;
|
||||
if (expected_msg3_tti == tic.tic_tx_ul()) {
|
||||
for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) {
|
||||
if (ul_result.pusch[i].dci.rnti == rnti) {
|
||||
CONDERROR(userinfo.msg3_tti >= 0, "[TESTER] Only one Msg3 allowed per user\n");
|
||||
CONDERROR(userinfo.msg3_tic.is_valid(), "Only one Msg3 allowed per user\n");
|
||||
CONDERROR(ul_result.pusch[i].needs_pdcch, "[TESTER] Msg3 allocations do not require PDCCH\n");
|
||||
// CONDERROR(tti_data.ul_pending_msg3.rnti != rnti, "[TESTER] The UL pending msg3 RNTI did not
|
||||
// match\n"); CONDERROR(not tti_data.ul_pending_msg3_present, "[TESTER] The UL pending msg3
|
||||
// RNTI did not match\n");
|
||||
userinfo.msg3_tti = tti_params.tti_tx_ul;
|
||||
userinfo.msg3_tic = tic.tic_tx_ul();
|
||||
msg3_count++;
|
||||
}
|
||||
}
|
||||
} else if (expected_msg3_tti < tti_params.tti_tx_ul) {
|
||||
CONDERROR(userinfo.msg3_tti < 0, "[TESTER] No UL msg3 allocation was made\n");
|
||||
} else if (expected_msg3_tti < tic.tic_tx_ul()) {
|
||||
CONDERROR(not userinfo.msg3_tic.is_valid(), "[TESTER] No UL msg3 allocation was made\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Find any Msg4 Allocation
|
||||
if (userinfo.msg4_tti < 0) {
|
||||
for (uint32_t i = 0; i < dl_result.nof_data_elems; ++i) {
|
||||
if (dl_result.data[i].dci.rnti == rnti) {
|
||||
for (uint32_t j = 0; j < dl_result.data[i].nof_pdu_elems[0]; ++j) {
|
||||
if (dl_result.data[i].pdu[0][j].lcid == srslte::sch_subh::CON_RES_ID) {
|
||||
// ConRes found
|
||||
CONDERROR(dl_result.data[i].dci.format != SRSLTE_DCI_FORMAT1, "ConRes must be format1\n");
|
||||
CONDERROR(userinfo.msg4_tti >= 0, "ConRes CE cannot be retransmitted for the same rnti\n");
|
||||
userinfo.msg4_tti = tti_params.tti_tx_dl;
|
||||
}
|
||||
for (uint32_t i = 0; i < dl_result.nof_data_elems; ++i) {
|
||||
if (dl_result.data[i].dci.rnti == rnti) {
|
||||
for (uint32_t j = 0; j < dl_result.data[i].nof_pdu_elems[0]; ++j) {
|
||||
if (dl_result.data[i].pdu[0][j].lcid == srslte::sch_subh::CON_RES_ID) {
|
||||
// ConRes found
|
||||
CONDERROR(dl_result.data[i].dci.format != SRSLTE_DCI_FORMAT1, "ConRes must be format1\n");
|
||||
CONDERROR(userinfo.msg4_tic.is_valid(), "Duplicate ConRes CE for the same rnti\n");
|
||||
userinfo.msg4_tic = tic.tic_tx_dl();
|
||||
}
|
||||
CONDERROR(userinfo.msg4_tti < 0, "Data allocations are not allowed without first receiving ConRes\n");
|
||||
}
|
||||
CONDERROR(not userinfo.msg4_tic.is_valid(), "Data allocs are not allowed without first receiving ConRes\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) {
|
||||
auto& pusch_alloc = ul_result.pusch[i];
|
||||
if (not pusch_alloc.needs_pdcch) {
|
||||
// can be adaptive retx or msg3
|
||||
auto& ue = users[pusch_alloc.dci.rnti];
|
||||
if (tic.tic_tx_ul() == ue.msg3_tic) {
|
||||
msg3_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
CONDERROR(msg3_count > 0, "[TESTER] There are pending msg3 that do not belong to any active UE\n");
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Individual tests:
|
||||
* - All RARs belong to a user that just PRACHed
|
||||
* - All DL/UL data allocs have a valid RNTI
|
||||
*/
|
||||
int user_state_sched_tester::test_ctrl_info(uint32_t enb_cc_idx,
|
||||
const sched_interface::dl_sched_res_t& dl_result,
|
||||
const sched_interface::ul_sched_res_t& ul_result)
|
||||
|
@ -454,7 +500,7 @@ int user_state_sched_tester::test_ctrl_info(uint32_t
|
|||
uint32_t prach_tti = dl_result.rar[i].msg3_grant[j].data.prach_tti;
|
||||
uint32_t preamble_idx = dl_result.rar[i].msg3_grant[j].data.preamble_idx;
|
||||
auto it = std::find_if(users.begin(), users.end(), [&](const std::pair<uint16_t, ue_state>& u) {
|
||||
return u.second.preamble_idx == preamble_idx and ((uint32_t)u.second.prach_tti == prach_tti);
|
||||
return u.second.preamble_idx == preamble_idx and ((uint32_t)u.second.prach_tic.tti_rx() == prach_tti);
|
||||
});
|
||||
CONDERROR(it == users.end(), "There was a RAR allocation with no associated user");
|
||||
CONDERROR(it->second.user_cfg.supported_cc_list[0].enb_cc_idx != enb_cc_idx,
|
||||
|
@ -550,3 +596,234 @@ sched_result_stats::user_stats* sched_result_stats::get_user(uint16_t rnti)
|
|||
users[rnti].tot_ul_sched_data.resize(cell_params.size(), 0);
|
||||
return &users[rnti];
|
||||
}
|
||||
|
||||
/***********************
|
||||
* Common Sched Tester
|
||||
**********************/
|
||||
|
||||
int common_sched_tester::sim_cfg(sim_sched_args args)
|
||||
{
|
||||
sim_args0 = std::move(args);
|
||||
|
||||
sched::cell_cfg(sim_args0.cell_cfg); // call parent cfg
|
||||
|
||||
ue_tester.reset(new user_state_sched_tester{sim_args0.cell_cfg});
|
||||
output_tester.clear();
|
||||
output_tester.reserve(sim_args0.cell_cfg.size());
|
||||
for (uint32_t i = 0; i < sim_args0.cell_cfg.size(); ++i) {
|
||||
output_tester.emplace_back(sched_cell_params[i]);
|
||||
}
|
||||
sched_stats.reset(new sched_result_stats{sim_args0.cell_cfg});
|
||||
|
||||
tester_log = sim_args0.sim_log;
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int common_sched_tester::add_user(uint16_t rnti, const ue_cfg_t& ue_cfg_)
|
||||
{
|
||||
CONDERROR(ue_cfg(rnti, ue_cfg_) != SRSLTE_SUCCESS, "[TESTER] Configuring new user rnti=0x%x to sched\n", rnti);
|
||||
|
||||
dl_sched_rar_info_t rar_info = {};
|
||||
rar_info.prach_tti = tti_info.tti_params.tti_rx;
|
||||
rar_info.temp_crnti = rnti;
|
||||
rar_info.msg3_size = 7;
|
||||
rar_info.preamble_idx = tti_info.nof_prachs++;
|
||||
uint32_t pcell_idx = ue_cfg_.supported_cc_list[0].enb_cc_idx;
|
||||
dl_rach_info(pcell_idx, rar_info);
|
||||
|
||||
ue_tester->add_user(rnti, rar_info.preamble_idx, ue_cfg_);
|
||||
|
||||
tester_log->info("[TESTER] Adding user rnti=0x%x\n", rnti);
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void common_sched_tester::rem_user(uint16_t rnti)
|
||||
{
|
||||
ue_tester->rem_user(rnti);
|
||||
}
|
||||
|
||||
void common_sched_tester::new_test_tti()
|
||||
{
|
||||
if (not tic.is_valid()) {
|
||||
tic.set_start_tti(sim_args0.start_tti);
|
||||
} else {
|
||||
tic++;
|
||||
}
|
||||
|
||||
tti_info.tti_params = tti_params_t{tic.tti_rx()};
|
||||
tti_info.nof_prachs = 0;
|
||||
tti_info.dl_sched_result.clear();
|
||||
tti_info.ul_sched_result.clear();
|
||||
|
||||
tester_log->step(tti_info.tti_params.tti_rx);
|
||||
|
||||
ue_tester->new_tti(tti_info.tti_params.tti_rx);
|
||||
}
|
||||
|
||||
int common_sched_tester::process_ack_txs()
|
||||
{
|
||||
/* check if user was removed. If so, clean respective acks */
|
||||
erase_if(to_ack,
|
||||
[this](std::pair<const uint32_t, ack_info_t>& elem) { return this->ue_db.count(elem.second.rnti) == 0; });
|
||||
erase_if(to_ul_ack,
|
||||
[this](std::pair<const uint32_t, ul_ack_info_t>& elem) { return this->ue_db.count(elem.second.rnti) == 0; });
|
||||
|
||||
/* Ack DL HARQs */
|
||||
for (const auto& ack_it : to_ack) {
|
||||
if (ack_it.second.tti != tti_info.tti_params.tti_rx) {
|
||||
continue;
|
||||
}
|
||||
const ack_info_t& dl_ack = ack_it.second;
|
||||
|
||||
srsenb::dl_harq_proc* h = ue_db[dl_ack.rnti].get_dl_harq(ack_it.second.dl_harq.get_id(), dl_ack.ue_cc_idx);
|
||||
const srsenb::dl_harq_proc& hack = dl_ack.dl_harq;
|
||||
CONDERROR(hack.is_empty(), "[TESTER] The acked DL harq was not active\n");
|
||||
|
||||
bool ret = false;
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; ++tb) {
|
||||
if (dl_ack.dl_harq.is_empty(tb)) {
|
||||
continue;
|
||||
}
|
||||
ret |= dl_ack_info(tti_info.tti_params.tti_rx, dl_ack.rnti, dl_ack.ue_cc_idx, tb, dl_ack.ack) > 0;
|
||||
}
|
||||
CONDERROR(not ret, "[TESTER] The dl harq proc that was ACKed does not exist\n");
|
||||
|
||||
if (dl_ack.ack) {
|
||||
CONDERROR(!h->is_empty(), "[TESTER] ACKed dl harq was not emptied\n");
|
||||
CONDERROR(h->has_pending_retx(0, tti_info.tti_params.tti_tx_dl),
|
||||
"[TESTER] ACKed dl harq still has pending retx\n");
|
||||
tester_log->info("[TESTER] DL ACK tti=%u rnti=0x%x pid=%d\n",
|
||||
tti_info.tti_params.tti_rx,
|
||||
dl_ack.rnti,
|
||||
dl_ack.dl_harq.get_id());
|
||||
} else {
|
||||
CONDERROR(h->is_empty() and hack.nof_retx(0) + 1 < hack.max_nof_retx(), "[TESTER] NACKed DL harq got emptied\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Ack UL HARQs */
|
||||
for (const auto& ack_it : to_ul_ack) {
|
||||
if (ack_it.first != tti_info.tti_params.tti_rx) {
|
||||
continue;
|
||||
}
|
||||
const ul_ack_info_t& ul_ack = ack_it.second;
|
||||
|
||||
srsenb::ul_harq_proc* h = ue_db[ul_ack.rnti].get_ul_harq(tti_info.tti_params.tti_rx, ul_ack.ue_cc_idx);
|
||||
const srsenb::ul_harq_proc& hack = ul_ack.ul_harq;
|
||||
CONDERROR(h == nullptr or h->get_tti() != hack.get_tti(), "[TESTER] UL Harq TTI does not match the ACK TTI\n");
|
||||
CONDERROR(h->is_empty(0), "[TESTER] The acked UL harq is not active\n");
|
||||
CONDERROR(hack.is_empty(0), "[TESTER] The acked UL harq was not active\n");
|
||||
|
||||
ul_crc_info(tti_info.tti_params.tti_rx, ul_ack.rnti, ul_ack.ue_cc_idx, ul_ack.ack);
|
||||
|
||||
CONDERROR(!h->get_pending_data(), "[TESTER] UL harq lost its pending data\n");
|
||||
CONDERROR(!h->has_pending_ack(), "[TESTER] ACK/NACKed UL harq should have a pending ACK\n");
|
||||
|
||||
if (ul_ack.ack) {
|
||||
CONDERROR(!h->is_empty(), "[TESTER] ACKed UL harq did not get emptied\n");
|
||||
CONDERROR(h->has_pending_retx(), "[TESTER] ACKed UL harq still has pending retx\n");
|
||||
tester_log->info(
|
||||
"[TESTER] UL ACK tti=%u rnti=0x%x pid=%d\n", tti_info.tti_params.tti_rx, ul_ack.rnti, hack.get_id());
|
||||
} else {
|
||||
// NACK
|
||||
CONDERROR(!h->is_empty() and !h->has_pending_retx(), "[TESTER] If NACKed, UL harq has to have pending retx\n");
|
||||
CONDERROR(h->is_empty() and hack.nof_retx(0) + 1 < hack.max_nof_retx(),
|
||||
"[TESTER] Nacked UL harq did get emptied\n");
|
||||
}
|
||||
}
|
||||
|
||||
// erase processed acks
|
||||
to_ack.erase(tti_info.tti_params.tti_rx);
|
||||
to_ul_ack.erase(tti_info.tti_params.tti_rx);
|
||||
|
||||
// bool ack = true; //(tti_data.tti_rx % 3) == 0;
|
||||
// if (tti_data.tti_rx >= FDD_HARQ_DELAY_MS) {
|
||||
// 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 != nullptr and not h->is_empty()) {
|
||||
// ul_crc_info(tti_data.tti_rx, rnti, ack);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int common_sched_tester::schedule_acks()
|
||||
{
|
||||
for (uint32_t ccidx = 0; ccidx < sched_cell_params.size(); ++ccidx) {
|
||||
// schedule future acks
|
||||
for (uint32_t i = 0; i < tti_info.dl_sched_result[ccidx].nof_data_elems; ++i) {
|
||||
ack_info_t ack_data;
|
||||
ack_data.rnti = tti_info.dl_sched_result[ccidx].data[i].dci.rnti;
|
||||
ack_data.tti = FDD_HARQ_DELAY_MS + tti_info.tti_params.tti_tx_dl;
|
||||
ack_data.ue_cc_idx = ue_db[ack_data.rnti].get_cell_index(ccidx).second;
|
||||
const srsenb::dl_harq_proc* dl_h =
|
||||
ue_db[ack_data.rnti].get_dl_harq(tti_info.dl_sched_result[ccidx].data[i].dci.pid, ccidx);
|
||||
ack_data.dl_harq = *dl_h;
|
||||
if (ack_data.dl_harq.nof_retx(0) == 0) {
|
||||
ack_data.ack = randf() > sim_args0.P_retx;
|
||||
} else { // always ack after three retxs
|
||||
ack_data.ack = ack_data.dl_harq.nof_retx(0) == 3;
|
||||
}
|
||||
|
||||
// Remove harq from the ack list if there was a harq rewrite
|
||||
auto it = to_ack.begin();
|
||||
while (it != to_ack.end() and it->first < ack_data.tti) {
|
||||
if (it->second.rnti == ack_data.rnti and it->second.dl_harq.get_id() == ack_data.dl_harq.get_id() and
|
||||
it->second.ue_cc_idx == ack_data.ue_cc_idx) {
|
||||
CONDERROR(it->second.tti + 2 * FDD_HARQ_DELAY_MS > ack_data.tti,
|
||||
"[TESTER] The retx dl harq id=%d was transmitted too soon\n",
|
||||
ack_data.dl_harq.get_id());
|
||||
auto toerase_it = it++;
|
||||
to_ack.erase(toerase_it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
// add new ack to the list
|
||||
to_ack.insert(std::make_pair(ack_data.tti, ack_data));
|
||||
}
|
||||
|
||||
/* Schedule UL ACKs */
|
||||
for (uint32_t i = 0; i < tti_info.ul_sched_result[ccidx].nof_dci_elems; ++i) {
|
||||
const auto& pusch = tti_info.ul_sched_result[ccidx].pusch[i];
|
||||
ul_ack_info_t ack_data;
|
||||
ack_data.rnti = pusch.dci.rnti;
|
||||
ack_data.ul_harq = *ue_db[ack_data.rnti].get_ul_harq(tti_info.tti_params.tti_tx_ul, ccidx);
|
||||
ack_data.tti_tx_ul = tti_info.tti_params.tti_tx_ul;
|
||||
ack_data.tti_ack = tti_info.tti_params.tti_tx_ul + FDD_HARQ_DELAY_MS;
|
||||
ack_data.ue_cc_idx = ue_db[ack_data.rnti].get_cell_index(ccidx).second;
|
||||
if (ack_data.ul_harq.nof_retx(0) == 0) {
|
||||
ack_data.ack = randf() > sim_args0.P_retx;
|
||||
} else {
|
||||
ack_data.ack = ack_data.ul_harq.nof_retx(0) == 3;
|
||||
}
|
||||
to_ul_ack.insert(std::make_pair(ack_data.tti_tx_ul, ack_data));
|
||||
}
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int common_sched_tester::process_results()
|
||||
{
|
||||
for (uint32_t i = 0; i < sched_cell_params.size(); ++i) {
|
||||
TESTASSERT(ue_tester->test_all(i, tti_info.dl_sched_result[i], tti_info.ul_sched_result[i]) == SRSLTE_SUCCESS);
|
||||
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;
|
||||
}
|
||||
|
||||
int common_sched_tester::test_next_ttis(const std::vector<tti_ev>& tti_events)
|
||||
{
|
||||
uint32_t next_idx = tic.is_valid() ? tic.total_count() - sim_args0.start_tti + 1 : 0;
|
||||
|
||||
for (; next_idx < tti_events.size(); ++next_idx) {
|
||||
TESTASSERT(run_tti(tti_events[next_idx]) == SRSLTE_SUCCESS);
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -22,15 +22,29 @@
|
|||
#ifndef SRSLTE_SCHEDULER_TEST_COMMON_H
|
||||
#define SRSLTE_SCHEDULER_TEST_COMMON_H
|
||||
|
||||
#include "scheduler_test_utils.h"
|
||||
#include "srsenb/hdr/stack/mac/scheduler.h"
|
||||
#include <random>
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
// helpers
|
||||
/***************************
|
||||
* Random Utils
|
||||
**************************/
|
||||
|
||||
void set_randseed(uint64_t seed);
|
||||
float randf();
|
||||
std::default_random_engine& get_rand_gen();
|
||||
|
||||
// other helpers
|
||||
int extract_dl_prbmask(const srslte_cell_t& cell,
|
||||
const srslte_dci_dl_t& dci,
|
||||
srslte::bounded_bitset<100, true>* alloc_mask);
|
||||
|
||||
/**************************
|
||||
* Testers
|
||||
*************************/
|
||||
|
||||
class output_sched_tester
|
||||
{
|
||||
public:
|
||||
|
@ -70,7 +84,8 @@ class user_state_sched_tester
|
|||
{
|
||||
public:
|
||||
struct ue_state {
|
||||
int prach_tti = -1, rar_tti = -1, msg3_tti = -1, msg4_tti = -1;
|
||||
tti_counter prach_tic, rar_tic, msg3_tic, msg4_tic;
|
||||
// int prach_tic = -1, rar_tic = -1, msg3_tic = -1, msg4_tic = -1;
|
||||
bool drb_cfg_flag = false;
|
||||
srsenb::sched_interface::ue_cfg_t user_cfg;
|
||||
uint32_t dl_data = 0;
|
||||
|
@ -83,18 +98,17 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
void new_tti(uint32_t tti_rx) { tti_params = tti_params_t{tti_rx}; }
|
||||
void new_tti(uint32_t tti_rx);
|
||||
bool user_exists(uint16_t rnti) const { return users.find(rnti) != users.end(); }
|
||||
const ue_state* get_user_state(uint16_t rnti) const
|
||||
{
|
||||
return users.count(rnti) > 0 ? &users.find(rnti)->second : nullptr;
|
||||
}
|
||||
|
||||
/* Register new users */
|
||||
int add_user(uint16_t rnti, uint32_t preamble_idx, const srsenb::sched_interface::ue_cfg_t& ue_cfg);
|
||||
int user_reconf(uint16_t rnti, const srsenb::sched_interface::ue_cfg_t& ue_cfg);
|
||||
int bearer_cfg(uint16_t rnti, uint32_t lcid, const srsenb::sched_interface::ue_bearer_cfg_t& bearer_cfg);
|
||||
|
||||
/* Config users */
|
||||
int add_user(uint16_t rnti, uint32_t preamble_idx, const srsenb::sched_interface::ue_cfg_t& ue_cfg);
|
||||
int user_reconf(uint16_t rnti, const srsenb::sched_interface::ue_cfg_t& ue_cfg);
|
||||
int bearer_cfg(uint16_t rnti, uint32_t lcid, const srsenb::sched_interface::ue_bearer_cfg_t& bearer_cfg);
|
||||
void rem_user(uint16_t rnti);
|
||||
|
||||
/* Test the timing of RAR, Msg3, Msg4 */
|
||||
|
@ -117,10 +131,10 @@ public:
|
|||
const sched_interface::ul_sched_res_t& ul_result);
|
||||
|
||||
private:
|
||||
const std::vector<srsenb::sched::cell_cfg_t> cell_params;
|
||||
const std::vector<srsenb::sched::cell_cfg_t>& cell_params;
|
||||
|
||||
std::map<uint16_t, ue_state> users;
|
||||
tti_params_t tti_params{10241};
|
||||
tti_counter tic;
|
||||
};
|
||||
|
||||
class sched_result_stats
|
||||
|
@ -149,6 +163,64 @@ private:
|
|||
const std::vector<srsenb::sched::cell_cfg_t> cell_params;
|
||||
};
|
||||
|
||||
// Intrusive Scheduler Tester
|
||||
class common_sched_tester : public sched
|
||||
{
|
||||
public:
|
||||
struct tti_info_t {
|
||||
tti_params_t tti_params{10241};
|
||||
uint32_t nof_prachs = 0;
|
||||
std::vector<sched_interface::dl_sched_res_t> dl_sched_result;
|
||||
std::vector<sched_interface::ul_sched_res_t> ul_sched_result;
|
||||
};
|
||||
|
||||
int sim_cfg(sim_sched_args args);
|
||||
int add_user(uint16_t rnti, const ue_cfg_t& ue_cfg_);
|
||||
void rem_user(uint16_t rnti);
|
||||
int process_ack_txs();
|
||||
int schedule_acks();
|
||||
int process_results();
|
||||
|
||||
int test_next_ttis(const std::vector<tti_ev>& tti_events);
|
||||
virtual int run_tti(const tti_ev& tti_events) = 0;
|
||||
|
||||
// args
|
||||
sim_sched_args sim_args0; ///< arguments used to generate TTI events
|
||||
srslte::log* tester_log = nullptr;
|
||||
|
||||
// tti specific params
|
||||
tti_info_t tti_info;
|
||||
tti_counter tic;
|
||||
|
||||
// testers
|
||||
std::vector<output_sched_tester> output_tester;
|
||||
std::unique_ptr<user_state_sched_tester> ue_tester;
|
||||
std::unique_ptr<sched_result_stats> sched_stats;
|
||||
|
||||
protected:
|
||||
struct ack_info_t {
|
||||
uint16_t rnti;
|
||||
uint32_t tti;
|
||||
uint32_t ue_cc_idx;
|
||||
bool ack = false;
|
||||
uint32_t retx_delay = 0;
|
||||
srsenb::dl_harq_proc dl_harq;
|
||||
};
|
||||
struct ul_ack_info_t {
|
||||
uint16_t rnti;
|
||||
uint32_t tti_ack, tti_tx_ul;
|
||||
uint32_t ue_cc_idx;
|
||||
bool ack = false;
|
||||
srsenb::ul_harq_proc ul_harq;
|
||||
};
|
||||
|
||||
void new_test_tti();
|
||||
|
||||
// control params
|
||||
std::multimap<uint32_t, ack_info_t> to_ack;
|
||||
std::multimap<uint32_t, ul_ack_info_t> to_ul_ack;
|
||||
};
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSLTE_SCHEDULER_TEST_COMMON_H
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "srslte/radio/radio.h"
|
||||
|
||||
#include "scheduler_test_common.h"
|
||||
#include "scheduler_test_utils.h"
|
||||
#include "srslte/common/test_common.h"
|
||||
|
||||
/********************************************************
|
||||
|
@ -68,20 +69,10 @@
|
|||
* ...
|
||||
*******************************************************/
|
||||
|
||||
/***************************
|
||||
* 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<float> unif_dist(0, 1.0);
|
||||
bool check_old_pids = false;
|
||||
|
||||
float randf()
|
||||
{
|
||||
return unif_dist(rand_gen);
|
||||
}
|
||||
bool check_old_pids = false;
|
||||
|
||||
struct ue_stats_t {
|
||||
uint64_t nof_dl_rbs = 0;
|
||||
|
@ -89,18 +80,6 @@ struct ue_stats_t {
|
|||
};
|
||||
std::map<uint16_t, ue_stats_t> ue_stats;
|
||||
|
||||
template <class MapContainer, class Predicate>
|
||||
void erase_if(MapContainer& c, Predicate should_remove)
|
||||
{
|
||||
for (auto it = c.begin(); it != c.end();) {
|
||||
if (should_remove(*it)) {
|
||||
it = c.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************
|
||||
* Logging *
|
||||
*******************/
|
||||
|
@ -144,15 +123,13 @@ struct sched_sim_args {
|
|||
uint32_t rem_rnti;
|
||||
};
|
||||
|
||||
std::vector<tti_event_t> tti_events;
|
||||
uint32_t nof_ttis;
|
||||
float P_retx;
|
||||
srsenb::sched_interface::ue_cfg_t ue_cfg;
|
||||
srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg;
|
||||
std::vector<tti_event_t> tti_events2;
|
||||
sim_sched_args sim_args;
|
||||
// std::vector<tti_ev> sim_events;
|
||||
};
|
||||
|
||||
// Designed for testing purposes
|
||||
struct sched_tester : public srsenb::sched {
|
||||
struct sched_tester : public srsenb::common_sched_tester {
|
||||
struct tester_user_results {
|
||||
uint32_t dl_pending_data = 0;
|
||||
uint32_t ul_pending_data = 0; ///< data pending for UL
|
||||
|
@ -168,9 +145,6 @@ struct sched_tester : public srsenb::sched {
|
|||
srsenb::ul_harq_proc ul_harq;
|
||||
};
|
||||
struct sched_tti_data {
|
||||
uint32_t tti_rx;
|
||||
uint32_t tti_tx_dl;
|
||||
uint32_t tti_tx_ul;
|
||||
uint32_t current_cfi;
|
||||
uint32_t nof_prachs = 0;
|
||||
bool ul_pending_msg3_present = false;
|
||||
|
@ -182,111 +156,61 @@ struct sched_tester : public srsenb::sched {
|
|||
srsenb::sched_interface::dl_sched_res_t sched_result_dl;
|
||||
};
|
||||
struct ue_info {
|
||||
int prach_tti = -1, rar_tti = -1, msg3_tti = -1, msg4_tti = -1;
|
||||
bool drb_cfg_flag = false;
|
||||
srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg;
|
||||
srsenb::sched_interface::ue_cfg_t user_cfg;
|
||||
uint32_t dl_data = 0;
|
||||
uint32_t ul_data = 0;
|
||||
uint32_t preamble_idx = 0;
|
||||
};
|
||||
struct ack_info_t {
|
||||
uint16_t rnti;
|
||||
uint32_t tti;
|
||||
bool dl_ack = false;
|
||||
uint32_t retx_delay = 0;
|
||||
srsenb::dl_harq_proc dl_harq;
|
||||
};
|
||||
struct ul_ack_info_t {
|
||||
uint16_t rnti;
|
||||
uint32_t tti_ack, tti_tx_ul;
|
||||
bool ack = false;
|
||||
srsenb::ul_harq_proc ul_harq;
|
||||
};
|
||||
|
||||
sched_sim_args sim_args;
|
||||
sched_sim_args sim_events;
|
||||
|
||||
// tester control data
|
||||
std::map<uint16_t, ue_info> tester_ues;
|
||||
std::multimap<uint32_t, ack_info_t> to_ack;
|
||||
std::multimap<uint32_t, ul_ack_info_t> to_ul_ack;
|
||||
typedef std::multimap<uint32_t, ack_info_t>::iterator ack_it_t;
|
||||
std::map<uint16_t, ue_info> tester_ues;
|
||||
|
||||
// sched results
|
||||
sched_tti_data tti_data;
|
||||
srsenb::tti_params_t tti_params{10241};
|
||||
sched_tti_data tti_data;
|
||||
|
||||
int cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg) final;
|
||||
int add_user(uint16_t rnti,
|
||||
srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg,
|
||||
srsenb::sched_interface::ue_cfg_t ue_cfg_);
|
||||
void rem_user(uint16_t rnti);
|
||||
int test_ra();
|
||||
int test_tti_result();
|
||||
int assert_no_empty_allocs();
|
||||
int test_collisions();
|
||||
int test_harqs();
|
||||
int test_sibs();
|
||||
void run_tti(uint32_t tti_rx);
|
||||
int run_tti(const tti_ev& tti_events) final;
|
||||
|
||||
private:
|
||||
void new_test_tti(uint32_t tti_);
|
||||
void new_test_tti();
|
||||
int process_tti_args();
|
||||
void before_sched();
|
||||
int process_results();
|
||||
int ack_txs();
|
||||
|
||||
std::unique_ptr<srsenb::output_sched_tester> output_tester;
|
||||
};
|
||||
|
||||
int sched_tester::cell_cfg(const std::vector<sched_interface::cell_cfg_t>& cell_cfg)
|
||||
{
|
||||
sched::cell_cfg(cell_cfg);
|
||||
output_tester.reset(new srsenb::output_sched_tester{sched_cell_params[CARRIER_IDX]});
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int sched_tester::add_user(uint16_t rnti,
|
||||
srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg,
|
||||
srsenb::sched_interface::ue_cfg_t ue_cfg_)
|
||||
{
|
||||
TESTASSERT(common_sched_tester::add_user(rnti, ue_cfg_) == SRSLTE_SUCCESS);
|
||||
ue_info info;
|
||||
info.prach_tti = tti_data.tti_rx;
|
||||
info.bearer_cfg = bearer_cfg;
|
||||
info.user_cfg = ue_cfg_;
|
||||
info.preamble_idx = tti_data.nof_prachs++;
|
||||
tester_ues.insert(std::make_pair(rnti, info));
|
||||
|
||||
CONDERROR(ue_cfg(rnti, ue_cfg_) != SRSLTE_SUCCESS, "[TESTER] Configuring new user rnti=0x%x to sched\n", rnti);
|
||||
|
||||
dl_sched_rar_info_t rar_info = {};
|
||||
rar_info.prach_tti = tti_data.tti_rx;
|
||||
rar_info.temp_crnti = rnti;
|
||||
rar_info.msg3_size = 7;
|
||||
rar_info.preamble_idx = info.preamble_idx;
|
||||
dl_rach_info(CARRIER_IDX, rar_info);
|
||||
|
||||
// setup bearers
|
||||
bearer_ue_cfg(rnti, 0, &bearer_cfg);
|
||||
|
||||
log_global->info("[TESTER] Adding user rnti=0x%x\n", rnti);
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void sched_tester::rem_user(uint16_t rnti)
|
||||
{
|
||||
common_sched_tester::rem_user(rnti);
|
||||
tester_ues.erase(rnti);
|
||||
tti_data.ue_data.erase(rnti);
|
||||
}
|
||||
|
||||
void sched_tester::new_test_tti(uint32_t tti_)
|
||||
void sched_tester::new_test_tti()
|
||||
{
|
||||
common_sched_tester::new_test_tti();
|
||||
// NOTE: make a local copy, since some of these variables may be cleared during scheduling
|
||||
tti_params = srsenb::tti_params_t{tti_};
|
||||
tti_data.tti_rx = tti_;
|
||||
tti_data.tti_tx_dl = TTI_TX(tti_);
|
||||
tti_data.tti_tx_ul = TTI_RX_ACK(tti_);
|
||||
auto& pending_msg3s = carrier_schedulers[0]->get_sf_sched_ptr(tti_data.tti_rx)->get_pending_msg3();
|
||||
auto& pending_msg3s = carrier_schedulers[0]->get_sf_sched_ptr(tti_info.tti_params.tti_rx)->get_pending_msg3();
|
||||
tti_data.ul_pending_msg3_present = false;
|
||||
if (not pending_msg3s.empty()) {
|
||||
tti_data.ul_pending_msg3_present = true;
|
||||
|
@ -303,17 +227,17 @@ void sched_tester::new_test_tti(uint32_t tti_)
|
|||
int sched_tester::process_tti_args()
|
||||
{
|
||||
// may add a new user
|
||||
if (sim_args.tti_events[tti_data.tti_rx].new_user) {
|
||||
CONDERROR(
|
||||
!srslte_prach_tti_opportunity_config_fdd(sched_cell_params[CARRIER_IDX].cfg.prach_config, tti_data.tti_rx, -1),
|
||||
"[TESTER] New user added in a non-PRACH TTI\n");
|
||||
uint16_t rnti = sim_args.tti_events[tti_data.tti_rx].new_rnti;
|
||||
add_user(rnti, sim_args.bearer_cfg, sim_args.ue_cfg);
|
||||
if (sim_events.tti_events2[tti_info.tti_params.tti_rx].new_user) {
|
||||
CONDERROR(!srslte_prach_tti_opportunity_config_fdd(
|
||||
sched_cell_params[CARRIER_IDX].cfg.prach_config, tti_info.tti_params.tti_rx, -1),
|
||||
"[TESTER] New user added in a non-PRACH TTI\n");
|
||||
uint16_t rnti = sim_events.tti_events2[tti_info.tti_params.tti_rx].new_rnti;
|
||||
add_user(rnti, sim_events.sim_args.bearer_cfg, sim_events.sim_args.ue_cfg);
|
||||
}
|
||||
|
||||
// may remove an existing user
|
||||
if (sim_args.tti_events[tti_data.tti_rx].rem_user) {
|
||||
uint16_t rnti = sim_args.tti_events[tti_data.tti_rx].rem_rnti;
|
||||
if (sim_events.tti_events2[tti_info.tti_params.tti_rx].rem_user) {
|
||||
uint16_t rnti = sim_events.tti_events2[tti_info.tti_params.tti_rx].rem_rnti;
|
||||
bearer_ue_rem(rnti, 0);
|
||||
ue_rem(rnti);
|
||||
rem_user(rnti);
|
||||
|
@ -321,16 +245,16 @@ int sched_tester::process_tti_args()
|
|||
}
|
||||
|
||||
// push UL SRs and DL packets
|
||||
for (auto& e : sim_args.tti_events[tti_data.tti_rx].users) {
|
||||
for (auto& e : sim_events.tti_events2[tti_info.tti_params.tti_rx].users) {
|
||||
if (e.second.sr_data > 0 and tester_ues[e.first].drb_cfg_flag) {
|
||||
uint32_t tot_ul_data = ue_db[e.first].get_pending_ul_new_data(tti_data.tti_tx_ul) + e.second.sr_data;
|
||||
uint32_t tot_ul_data = ue_db[e.first].get_pending_ul_new_data(tti_info.tti_params.tti_tx_ul) + e.second.sr_data;
|
||||
uint32_t lcid = 0;
|
||||
ul_bsr(e.first, lcid, tot_ul_data, true);
|
||||
}
|
||||
if (e.second.dl_data > 0 and tester_ues[e.first].msg3_tti >= 0 and
|
||||
tester_ues[e.first].msg3_tti < (int)tti_data.tti_rx) {
|
||||
auto* user = ue_tester->get_user_state(e.first);
|
||||
if (e.second.dl_data > 0 and user->msg3_tic.is_valid() and user->msg3_tic.tti_rx() < tti_info.tti_params.tti_rx) {
|
||||
// If Msg4 not yet sent, allocate data in SRB0 buffer
|
||||
uint32_t lcid = (tester_ues[e.first].msg4_tti >= 0) ? 2 : 0;
|
||||
uint32_t lcid = (user->msg4_tic.is_valid()) ? 2 : 0;
|
||||
uint32_t pending_dl_new_data = ue_db[e.first].get_pending_dl_new_data();
|
||||
if (lcid == 2 and not tester_ues[e.first].drb_cfg_flag) {
|
||||
// If RRCSetup finished
|
||||
|
@ -359,14 +283,15 @@ void sched_tester::before_sched()
|
|||
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, CARRIER_IDX);
|
||||
srsenb::ul_harq_proc* hul = user->get_ul_harq(tti_info.tti_params.tti_tx_ul, CARRIER_IDX);
|
||||
d.ul_pending_data = get_ul_buffer(rnti);
|
||||
// user->get_pending_ul_new_data(tti_data.tti_tx_ul) or hul->has_pending_retx(); // get_ul_buffer(rnti);
|
||||
// user->get_pending_ul_new_data(tti_info.tti_params.tti_tx_ul) or hul->has_pending_retx(); //
|
||||
// get_ul_buffer(rnti);
|
||||
d.dl_pending_data = get_dl_buffer(rnti);
|
||||
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, CARRIER_IDX);
|
||||
d.has_dl_retx = (hdl != nullptr) and hdl->has_pending_retx(0, tti_data.tti_tx_dl);
|
||||
srsenb::dl_harq_proc* hdl = user->get_pending_dl_harq(tti_info.tti_params.tti_tx_dl, CARRIER_IDX);
|
||||
d.has_dl_retx = (hdl != nullptr) and hdl->has_pending_retx(0, tti_info.tti_params.tti_tx_dl);
|
||||
d.has_dl_tx = (hdl != nullptr) or (it.second.get_empty_dl_harq(CARRIER_IDX) != 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));
|
||||
|
@ -380,8 +305,8 @@ void sched_tester::before_sched()
|
|||
const srsenb::dl_harq_proc* h = user->get_dl_harq(i, CARRIER_IDX);
|
||||
tti_data.ue_data[rnti].dl_harqs[i] = *h;
|
||||
}
|
||||
// NOTE: ACK might have just cleared the harq for tti_data.tti_tx_ul
|
||||
tti_data.ue_data[rnti].ul_harq = *user->get_ul_harq(tti_data.tti_tx_ul, CARRIER_IDX);
|
||||
// NOTE: ACK might have just cleared the harq for tti_info.tti_params.tti_tx_ul
|
||||
tti_data.ue_data[rnti].ul_harq = *user->get_ul_harq(tti_info.tti_params.tti_tx_ul, CARRIER_IDX);
|
||||
}
|
||||
|
||||
// TODO: Check whether pending pending_rar.rar_tti correspond to a prach_tti
|
||||
|
@ -389,12 +314,16 @@ void sched_tester::before_sched()
|
|||
|
||||
int sched_tester::process_results()
|
||||
{
|
||||
tti_info.dl_sched_result.resize(1);
|
||||
tti_info.dl_sched_result[0] = tti_data.sched_result_dl;
|
||||
tti_info.ul_sched_result.resize(1);
|
||||
tti_info.ul_sched_result[0] = tti_data.sched_result_ul;
|
||||
for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) {
|
||||
uint16_t rnti = tti_data.sched_result_ul.pusch[i].dci.rnti;
|
||||
tti_data.ue_data[rnti].ul_sched = &tti_data.sched_result_ul.pusch[i];
|
||||
CONDERROR(tester_ues.count(rnti) == 0,
|
||||
"[TESTER] [%d] The user rnti=0x%x that no longer exists got allocated.\n",
|
||||
tti_data.tti_rx,
|
||||
tti_info.tti_params.tti_rx,
|
||||
rnti);
|
||||
}
|
||||
for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) {
|
||||
|
@ -402,116 +331,34 @@ int sched_tester::process_results()
|
|||
tti_data.ue_data[rnti].dl_sched = &tti_data.sched_result_dl.data[i];
|
||||
CONDERROR(tester_ues.count(rnti) == 0,
|
||||
"[TESTER] [%d] The user rnti=0x%x that no longer exists got allocated.\n",
|
||||
tti_data.tti_rx,
|
||||
tti_info.tti_params.tti_rx,
|
||||
rnti);
|
||||
}
|
||||
|
||||
test_tti_result();
|
||||
test_ra();
|
||||
ue_tester->test_ra(0, tti_info.dl_sched_result[CARRIER_IDX], tti_info.ul_sched_result[CARRIER_IDX]);
|
||||
test_collisions();
|
||||
assert_no_empty_allocs();
|
||||
test_harqs();
|
||||
test_sibs();
|
||||
output_tester[CARRIER_IDX].test_sib_scheduling(tti_info.tti_params, tti_data.sched_result_dl);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void sched_tester::run_tti(uint32_t tti_rx)
|
||||
int sched_tester::run_tti(const tti_ev& tti_events)
|
||||
{
|
||||
new_test_tti(tti_rx);
|
||||
log_global->info("[TESTER] ---- tti=%u | nof_ues=%zd ----\n", tti_rx, ue_db.size());
|
||||
new_test_tti();
|
||||
log_global->info("[TESTER] ---- tti=%u | nof_ues=%zd ----\n", tic.tti_rx(), ue_db.size());
|
||||
|
||||
process_tti_args();
|
||||
|
||||
ack_txs();
|
||||
process_ack_txs();
|
||||
before_sched();
|
||||
|
||||
dl_sched(tti_data.tti_tx_dl, CARRIER_IDX, tti_data.sched_result_dl);
|
||||
ul_sched(tti_data.tti_tx_ul, CARRIER_IDX, tti_data.sched_result_ul);
|
||||
dl_sched(tti_info.tti_params.tti_tx_dl, CARRIER_IDX, tti_data.sched_result_dl);
|
||||
ul_sched(tti_info.tti_params.tti_tx_ul, CARRIER_IDX, tti_data.sched_result_ul);
|
||||
|
||||
process_results();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the RAR and Msg3 were scheduled within the expected windows
|
||||
*/
|
||||
int sched_tester::test_ra()
|
||||
{
|
||||
uint32_t msg3_count = 0;
|
||||
|
||||
// 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;
|
||||
sched_tester::ue_info& userinfo = tester_ues[rnti];
|
||||
|
||||
// Check whether RA has completed correctly
|
||||
int prach_tti = userinfo.prach_tti;
|
||||
// if (userinfo.msg4_tti > prach_tti) { // Msg4 already scheduled
|
||||
// continue;
|
||||
// }
|
||||
|
||||
uint32_t window[2] = {(uint32_t)prach_tti + 3, prach_tti + 3 + sched_cell_params[CARRIER_IDX].cfg.prach_rar_window};
|
||||
if (prach_tti >= userinfo.rar_tti) { // RAR not yet sent
|
||||
CONDERROR(tti_data.tti_tx_dl > window[1], "[TESTER] There was no RAR scheduled within the RAR Window\n");
|
||||
if (tti_data.tti_tx_dl >= window[0]) {
|
||||
for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_rar_elems; ++i) {
|
||||
for (uint32_t j = 0; j < tti_data.sched_result_dl.rar[i].nof_grants; ++j) {
|
||||
auto& data = tti_data.sched_result_dl.rar[i].msg3_grant[j].data;
|
||||
if (data.prach_tti == (uint32_t)userinfo.prach_tti and data.preamble_idx == userinfo.preamble_idx) {
|
||||
userinfo.rar_tti = tti_data.tti_tx_dl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (userinfo.msg3_tti < prach_tti) { // Msg3 not yet sent
|
||||
uint32_t msg3_tti = (uint32_t)(userinfo.rar_tti + FDD_HARQ_DELAY_MS + MSG3_DELAY_MS) % 10240;
|
||||
if (msg3_tti == tti_data.tti_tx_ul) {
|
||||
for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) {
|
||||
if (tti_data.sched_result_ul.pusch[i].dci.rnti == rnti) {
|
||||
CONDERROR(tti_data.sched_result_ul.pusch[i].needs_pdcch,
|
||||
"[TESTER] Msg3 allocations do not require PDCCH\n");
|
||||
CONDERROR(tti_data.ul_pending_msg3.rnti != rnti, "[TESTER] The UL pending msg3 RNTI did not match\n");
|
||||
CONDERROR(not tti_data.ul_pending_msg3_present, "[TESTER] The UL pending msg3 RNTI did not match\n");
|
||||
userinfo.msg3_tti = tti_data.tti_tx_ul;
|
||||
msg3_count++;
|
||||
}
|
||||
}
|
||||
CONDERROR(msg3_count == 0, "[TESTER] No UL msg3 allocation was made\n");
|
||||
} else if (msg3_tti < tti_data.tti_tx_ul) {
|
||||
TESTERROR("[TESTER] No UL msg3 allocation was made\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Find any Msg4 allocation
|
||||
for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) {
|
||||
auto& ue_data = tti_data.sched_result_dl.data[i];
|
||||
if (ue_data.dci.rnti != rnti) {
|
||||
continue;
|
||||
}
|
||||
for (uint32_t j = 0; j < tti_data.sched_result_dl.data[i].nof_pdu_elems[0]; ++j) {
|
||||
if (ue_data.pdu[0][j].lcid == srslte::sch_subh::CON_RES_ID) {
|
||||
// ConRes found
|
||||
CONDERROR(ue_data.dci.format != SRSLTE_DCI_FORMAT1, "ConRes must be format1\n");
|
||||
CONDERROR(userinfo.msg3_tti > (int)tti_data.tti_rx, "Transmitting ConRes without receiving Msg3\n");
|
||||
CONDERROR(userinfo.msg4_tti >= 0, "ConRes CE cannot be retransmitted for the same rnti\n");
|
||||
userinfo.msg4_tti = tti_data.tti_tx_dl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) {
|
||||
auto& pusch_alloc = tti_data.sched_result_ul.pusch[i];
|
||||
if (not pusch_alloc.needs_pdcch) {
|
||||
// can be adaptive retx or msg3
|
||||
auto& ue = tester_ues[pusch_alloc.dci.rnti];
|
||||
if (tti_data.tti_tx_ul == (uint32_t)ue.msg3_tti) {
|
||||
msg3_count--;
|
||||
}
|
||||
}
|
||||
// msg3_count -= tti_data.sched_result_ul.pusch[i].needs_pdcch ? 0 : 1;
|
||||
}
|
||||
CONDERROR(msg3_count > 0, "[TESTER] There are pending msg3 that do not belong to any active UE\n");
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -527,7 +374,7 @@ int sched_tester::assert_no_empty_allocs()
|
|||
// TODO: 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_info.tti_params.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
|
||||
|
@ -536,12 +383,12 @@ int sched_tester::assert_no_empty_allocs()
|
|||
}
|
||||
|
||||
// There must be allocations if there is pending data/retxs.
|
||||
bool no_dl_allocs = true;
|
||||
for (auto& it : tti_data.ue_data) {
|
||||
if (it.second.dl_sched != nullptr) {
|
||||
no_dl_allocs = false;
|
||||
}
|
||||
}
|
||||
// bool no_dl_allocs = true;
|
||||
// for (auto& it : tti_data.ue_data) {
|
||||
// if (it.second.dl_sched != nullptr) {
|
||||
// no_dl_allocs = false;
|
||||
// }
|
||||
// }
|
||||
// CONDERROR(tti_data.total_ues.has_dl_tx and no_dl_allocs, "There was pending DL data but no user got allocated\n");
|
||||
// TODO: You have to verify if there is space for the retx since it is non-adaptive
|
||||
return SRSLTE_SUCCESS;
|
||||
|
@ -553,14 +400,14 @@ int sched_tester::assert_no_empty_allocs()
|
|||
int sched_tester::test_tti_result()
|
||||
{
|
||||
/* TEST: Check if there are collisions in the PDCCH */
|
||||
TESTASSERT(output_tester->test_pdcch_collisions(
|
||||
TESTASSERT(output_tester[CARRIER_IDX].test_pdcch_collisions(
|
||||
tti_data.sched_result_dl, tti_data.sched_result_ul, &tti_data.used_cce) == SRSLTE_SUCCESS);
|
||||
|
||||
/* TEST: Check whether dci values are correct */
|
||||
TESTASSERT(output_tester->test_dci_values_consistency(tti_data.sched_result_dl, tti_data.sched_result_ul) ==
|
||||
SRSLTE_SUCCESS);
|
||||
TESTASSERT(output_tester[CARRIER_IDX].test_dci_values_consistency(tti_data.sched_result_dl,
|
||||
tti_data.sched_result_ul) == SRSLTE_SUCCESS);
|
||||
|
||||
const srsenb::sf_sched* tti_sched = carrier_schedulers[0]->get_sf_sched_ptr(tti_data.tti_rx);
|
||||
const srsenb::sf_sched* tti_sched = carrier_schedulers[0]->get_sf_sched_ptr(tti_info.tti_params.tti_rx);
|
||||
|
||||
for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) {
|
||||
const auto& pusch = tti_data.sched_result_ul.pusch[i];
|
||||
|
@ -584,7 +431,7 @@ int sched_tester::test_tti_result()
|
|||
}
|
||||
|
||||
/* verify if sched_result "used_cce" coincide with sched "used_cce" */
|
||||
auto* tti_alloc = carrier_schedulers[0]->get_sf_sched_ptr(tti_data.tti_rx);
|
||||
auto* tti_alloc = carrier_schedulers[0]->get_sf_sched_ptr(tti_info.tti_params.tti_rx);
|
||||
if (tti_data.used_cce != tti_alloc->get_pdcch_mask()) {
|
||||
std::string mask_str = tti_alloc->get_pdcch_mask().to_string();
|
||||
TESTERROR(
|
||||
|
@ -599,7 +446,8 @@ int sched_tester::test_tti_result()
|
|||
// for (it_t it = ue_db.begin(); it != ue_db.end(); ++it) {
|
||||
// uint32_t aggr_level = it->second.get_aggr_level(srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, cfg.cell.nof_prb,
|
||||
// cfg.cell.nof_ports)); if (find_empty_dci(it->second.get_locations(current_cfi, sf_idx), aggr_level) > 0) {
|
||||
// TESTERROR("[%d] There was pending UL data and free CCEs, but no user got allocated\n", tti_data.tti_rx);
|
||||
// TESTERROR("[%d] There was pending UL data and free CCEs, but no user got allocated\n",
|
||||
// tti_info.tti_params.tti_rx);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
@ -616,19 +464,19 @@ int sched_tester::test_harqs()
|
|||
const srsenb::dl_harq_proc* h = ue_db[rnti].get_dl_harq(h_id, CARRIER_IDX);
|
||||
CONDERROR(h == nullptr, "[TESTER] scheduled DL harq pid=%d does not exist\n", h_id);
|
||||
CONDERROR(h->is_empty(), "[TESTER] Cannot schedule an empty harq proc\n");
|
||||
CONDERROR(h->get_tti() != tti_data.tti_tx_dl,
|
||||
CONDERROR(h->get_tti() != tti_info.tti_params.tti_tx_dl,
|
||||
"[TESTER] The scheduled DL harq pid=%d does not a valid tti=%u\n",
|
||||
h_id,
|
||||
tti_data.tti_tx_dl);
|
||||
tti_info.tti_params.tti_tx_dl);
|
||||
CONDERROR(h->get_n_cce() != data.dci.location.ncce, "[TESTER] Harq DCI location does not match with result\n");
|
||||
if (tti_data.ue_data[rnti].dl_harqs[h_id].has_pending_retx(0, tti_data.tti_tx_dl)) { // retx
|
||||
if (tti_data.ue_data[rnti].dl_harqs[h_id].has_pending_retx(0, tti_info.tti_params.tti_tx_dl)) { // retx
|
||||
CONDERROR(tti_data.ue_data[rnti].dl_harqs[h_id].nof_retx(0) + 1 != h->nof_retx(0),
|
||||
"[TESTER] A dl harq of user rnti=0x%x was likely overwritten.\n",
|
||||
rnti);
|
||||
CONDERROR(h->nof_retx(0) >= sim_args.ue_cfg.maxharq_tx,
|
||||
CONDERROR(h->nof_retx(0) >= sim_events.sim_args.ue_cfg.maxharq_tx,
|
||||
"[TESTER] The number of retx=%d exceeded its max=%d\n",
|
||||
h->nof_retx(0),
|
||||
sim_args.ue_cfg.maxharq_tx);
|
||||
sim_events.sim_args.ue_cfg.maxharq_tx);
|
||||
} else { // newtx
|
||||
CONDERROR(h->nof_retx(0) != 0, "[TESTER] A new harq was scheduled but with invalid number of retxs\n");
|
||||
}
|
||||
|
@ -638,11 +486,11 @@ int sched_tester::test_harqs()
|
|||
const auto& pusch = tti_data.sched_result_ul.pusch[i];
|
||||
uint16_t rnti = pusch.dci.rnti;
|
||||
const auto& ue_data = tti_data.ue_data[rnti];
|
||||
const srsenb::ul_harq_proc* h = ue_db[rnti].get_ul_harq(tti_data.tti_tx_ul, CARRIER_IDX);
|
||||
const srsenb::ul_harq_proc* h = ue_db[rnti].get_ul_harq(tti_info.tti_params.tti_tx_ul, CARRIER_IDX);
|
||||
CONDERROR(h == nullptr or h->is_empty(), "[TESTER] scheduled UL harq does not exist or is empty\n");
|
||||
CONDERROR(h->get_tti() != tti_data.tti_tx_ul,
|
||||
CONDERROR(h->get_tti() != tti_info.tti_params.tti_tx_ul,
|
||||
"[TESTER] The scheduled UL harq does not a valid tti=%u\n",
|
||||
tti_data.tti_tx_ul);
|
||||
tti_info.tti_params.tti_tx_ul);
|
||||
CONDERROR(h->has_pending_ack(), "[TESTER] At the end of the TTI, there shouldnt be any pending ACKs\n");
|
||||
|
||||
if (h->has_pending_retx()) {
|
||||
|
@ -662,7 +510,7 @@ int sched_tester::test_harqs()
|
|||
const auto& phich = tti_data.sched_result_ul.phich[i];
|
||||
CONDERROR(tti_data.ue_data.count(phich.rnti) == 0, "[TESTER] Allocated PHICH rnti no longer exists\n");
|
||||
const auto& hprev = tti_data.ue_data[phich.rnti].ul_harq;
|
||||
const auto* h = ue_db[phich.rnti].get_ul_harq(tti_data.tti_tx_ul, CARRIER_IDX);
|
||||
const auto* h = ue_db[phich.rnti].get_ul_harq(tti_info.tti_params.tti_tx_ul, CARRIER_IDX);
|
||||
CONDERROR(not hprev.has_pending_ack(), "[TESTER] Alloc PHICH did not have any pending ack\n");
|
||||
bool maxretx_flag = hprev.nof_retx(0) + 1 >= hprev.max_nof_retx();
|
||||
if (phich.phich == sched_interface::ul_sched_phich_t::ACK) {
|
||||
|
@ -688,59 +536,15 @@ int sched_tester::test_harqs()
|
|||
}
|
||||
|
||||
// schedule future acks
|
||||
for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) {
|
||||
ack_info_t ack_data;
|
||||
ack_data.rnti = tti_data.sched_result_dl.data[i].dci.rnti;
|
||||
ack_data.tti = FDD_HARQ_DELAY_MS + tti_data.tti_tx_dl;
|
||||
const srsenb::dl_harq_proc* dl_h =
|
||||
ue_db[ack_data.rnti].get_dl_harq(tti_data.sched_result_dl.data[i].dci.pid, CARRIER_IDX);
|
||||
ack_data.dl_harq = *dl_h;
|
||||
if (ack_data.dl_harq.nof_retx(0) == 0) {
|
||||
ack_data.dl_ack = randf() > sim_args.P_retx;
|
||||
} else { // always ack after three retxs
|
||||
ack_data.dl_ack = ack_data.dl_harq.nof_retx(0) == 3;
|
||||
}
|
||||
|
||||
// Remove harq from the ack list if there was a harq rewrite
|
||||
ack_it_t it = to_ack.begin();
|
||||
while (it != to_ack.end() and it->first < ack_data.tti) {
|
||||
if (it->second.rnti == ack_data.rnti and it->second.dl_harq.get_id() == ack_data.dl_harq.get_id()) {
|
||||
CONDERROR(it->second.tti + 2 * FDD_HARQ_DELAY_MS > ack_data.tti,
|
||||
"[TESTER] The retx dl harq id=%d was transmitted too soon\n",
|
||||
ack_data.dl_harq.get_id());
|
||||
ack_it_t toerase_it = it++;
|
||||
to_ack.erase(toerase_it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
// add new ack to the list
|
||||
to_ack.insert(std::make_pair(ack_data.tti, ack_data));
|
||||
}
|
||||
|
||||
/* Schedule UL ACKs */
|
||||
for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) {
|
||||
const auto& pusch = tti_data.sched_result_ul.pusch[i];
|
||||
ul_ack_info_t ack_data;
|
||||
ack_data.rnti = pusch.dci.rnti;
|
||||
ack_data.ul_harq = *ue_db[ack_data.rnti].get_ul_harq(tti_data.tti_tx_ul, CARRIER_IDX);
|
||||
ack_data.tti_tx_ul = tti_data.tti_tx_ul;
|
||||
ack_data.tti_ack = tti_data.tti_tx_ul + FDD_HARQ_DELAY_MS;
|
||||
if (ack_data.ul_harq.nof_retx(0) == 0) {
|
||||
ack_data.ack = randf() > sim_args.P_retx;
|
||||
} else {
|
||||
ack_data.ack = ack_data.ul_harq.nof_retx(0) == 3;
|
||||
}
|
||||
to_ul_ack.insert(std::make_pair(ack_data.tti_tx_ul, ack_data));
|
||||
}
|
||||
TESTASSERT(schedule_acks() == SRSLTE_SUCCESS);
|
||||
|
||||
// Check whether some pids got old
|
||||
if (check_old_pids) {
|
||||
for (auto& user : ue_db) {
|
||||
for (int i = 0; i < 2 * FDD_HARQ_DELAY_MS; i++) {
|
||||
if (not(user.second.get_dl_harq(i, CARRIER_IDX)->is_empty(0) and user.second.get_dl_harq(1, CARRIER_IDX))) {
|
||||
if (srslte_tti_interval(tti_data.tti_tx_dl, user.second.get_dl_harq(i, CARRIER_IDX)->get_tti()) > 49) {
|
||||
if (srslte_tti_interval(tti_info.tti_params.tti_tx_dl, user.second.get_dl_harq(i, CARRIER_IDX)->get_tti()) >
|
||||
49) {
|
||||
TESTERROR("[TESTER] The pid=%d for rnti=0x%x got old.\n",
|
||||
user.second.get_dl_harq(i, CARRIER_IDX)->get_id(),
|
||||
user.first);
|
||||
|
@ -753,18 +557,14 @@ int sched_tester::test_harqs()
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int sched_tester::test_sibs()
|
||||
{
|
||||
return output_tester->test_sib_scheduling(tti_params, tti_data.sched_result_dl);
|
||||
}
|
||||
|
||||
int sched_tester::test_collisions()
|
||||
{
|
||||
const srsenb::sf_sched* tti_sched = carrier_schedulers[0]->get_sf_sched_ptr(tti_data.tti_rx);
|
||||
const srsenb::sf_sched* tti_sched = carrier_schedulers[0]->get_sf_sched_ptr(tti_info.tti_params.tti_rx);
|
||||
srsenb::prbmask_t ul_allocs(sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb);
|
||||
|
||||
/* TEST: any collision in PUCCH and PUSCH */
|
||||
TESTASSERT(output_tester->test_pusch_collisions(tti_params, tti_data.sched_result_ul, ul_allocs) == SRSLTE_SUCCESS);
|
||||
TESTASSERT(output_tester[CARRIER_IDX].test_pusch_collisions(
|
||||
tti_info.tti_params, tti_data.sched_result_ul, ul_allocs) == SRSLTE_SUCCESS);
|
||||
|
||||
/* TEST: check whether cumulative UL PRB masks coincide */
|
||||
if (ul_allocs != tti_sched->get_ul_mask()) {
|
||||
|
@ -806,7 +606,8 @@ int sched_tester::test_collisions()
|
|||
|
||||
/* TEST: check any collision in PDSCH */
|
||||
srsenb::rbgmask_t rbgmask(sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb);
|
||||
TESTASSERT(output_tester->test_pdsch_collisions(tti_params, tti_data.sched_result_dl, rbgmask) == SRSLTE_SUCCESS);
|
||||
TESTASSERT(output_tester[CARRIER_IDX].test_pdsch_collisions(tti_info.tti_params, tti_data.sched_result_dl, rbgmask) ==
|
||||
SRSLTE_SUCCESS);
|
||||
|
||||
// update ue stats with number of DL RB allocations
|
||||
srslte::bounded_bitset<100, true> alloc_mask(sched_cell_params[CARRIER_IDX].cfg.cell.nof_prb);
|
||||
|
@ -818,104 +619,25 @@ int sched_tester::test_collisions()
|
|||
}
|
||||
|
||||
// TEST: check if resulting DL mask is equal to scheduler internal DL mask
|
||||
if (rbgmask != carrier_schedulers[0]->get_sf_sched_ptr(tti_data.tti_rx)->get_dl_mask()) {
|
||||
if (rbgmask != carrier_schedulers[0]->get_sf_sched_ptr(tti_info.tti_params.tti_rx)->get_dl_mask()) {
|
||||
TESTERROR("[TESTER] The UL PRB mask and the scheduler result UL mask are not consistent (%s!=%s)\n",
|
||||
rbgmask.to_string().c_str(),
|
||||
carrier_schedulers[CARRIER_IDX]->get_sf_sched_ptr(tti_data.tti_rx)->get_dl_mask().to_string().c_str());
|
||||
carrier_schedulers[CARRIER_IDX]
|
||||
->get_sf_sched_ptr(tti_info.tti_params.tti_rx)
|
||||
->get_dl_mask()
|
||||
.to_string()
|
||||
.c_str());
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int sched_tester::ack_txs()
|
||||
{
|
||||
/* check if user was removed. If so, clean respective acks */
|
||||
erase_if(to_ack,
|
||||
[this](std::pair<const uint32_t, ack_info_t>& elem) { return this->ue_db.count(elem.second.rnti) == 0; });
|
||||
erase_if(to_ul_ack,
|
||||
[this](std::pair<const uint32_t, ul_ack_info_t>& elem) { return this->ue_db.count(elem.second.rnti) == 0; });
|
||||
|
||||
/* Ack DL HARQs */
|
||||
for (const auto& ack_it : to_ack) {
|
||||
if (ack_it.second.tti != tti_data.tti_rx) {
|
||||
continue;
|
||||
}
|
||||
srsenb::dl_harq_proc* h = ue_db[ack_it.second.rnti].get_dl_harq(ack_it.second.dl_harq.get_id(), CARRIER_IDX);
|
||||
const srsenb::dl_harq_proc& hack = ack_it.second.dl_harq;
|
||||
CONDERROR(hack.is_empty(), "[TESTER] The acked DL harq was not active\n");
|
||||
|
||||
bool ret = false;
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; ++tb) {
|
||||
if (ack_it.second.dl_harq.is_empty(tb)) {
|
||||
continue;
|
||||
}
|
||||
ret |= dl_ack_info(tti_data.tti_rx, ack_it.second.rnti, CARRIER_IDX, tb, ack_it.second.dl_ack) > 0;
|
||||
}
|
||||
CONDERROR(not ret, "[TESTER] The dl harq proc that was acked does not exist\n");
|
||||
|
||||
if (ack_it.second.dl_ack) {
|
||||
CONDERROR(!h->is_empty(), "[TESTER] ACKed dl harq was not emptied\n");
|
||||
CONDERROR(h->has_pending_retx(0, tti_data.tti_tx_dl), "[TESTER] ACKed dl harq still has pending retx\n");
|
||||
log_global->info("[TESTER] DL ACK tti=%u rnti=0x%x pid=%d\n",
|
||||
tti_data.tti_rx,
|
||||
ack_it.second.rnti,
|
||||
ack_it.second.dl_harq.get_id());
|
||||
} else {
|
||||
CONDERROR(h->is_empty() and hack.nof_retx(0) + 1 < hack.max_nof_retx(), "[TESTER] NACKed DL harq got emptied\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Ack UL HARQs */
|
||||
for (const auto& ack_it : to_ul_ack) {
|
||||
if (ack_it.first != tti_data.tti_rx) {
|
||||
continue;
|
||||
}
|
||||
srsenb::ul_harq_proc* h = ue_db[ack_it.second.rnti].get_ul_harq(tti_data.tti_rx, CARRIER_IDX);
|
||||
const srsenb::ul_harq_proc& hack = ack_it.second.ul_harq;
|
||||
CONDERROR(h == nullptr or h->get_tti() != hack.get_tti(), "[TESTER] UL Harq TTI does not match the ACK TTI\n");
|
||||
CONDERROR(h->is_empty(0), "[TESTER] The acked UL harq is not active\n");
|
||||
CONDERROR(hack.is_empty(0), "[TESTER] The acked UL harq was not active\n");
|
||||
|
||||
ul_crc_info(tti_data.tti_rx, ack_it.second.rnti, CARRIER_IDX, ack_it.second.ack);
|
||||
|
||||
CONDERROR(!h->get_pending_data(), "[TESTER] UL harq lost its pending data\n");
|
||||
CONDERROR(!h->has_pending_ack(), "[TESTER] ACK/NACKed UL harq should have a pending ACK\n");
|
||||
|
||||
if (ack_it.second.ack) {
|
||||
CONDERROR(!h->is_empty(), "[TESTER] ACKed UL harq did not get emptied\n");
|
||||
CONDERROR(h->has_pending_retx(), "[TESTER] ACKed UL harq still has pending retx\n");
|
||||
log_global->info("[TESTER] UL ACK tti=%u rnti=0x%x pid=%d\n", tti_data.tti_rx, ack_it.second.rnti, hack.get_id());
|
||||
} else {
|
||||
// NACK
|
||||
CONDERROR(!h->is_empty() and !h->has_pending_retx(), "[TESTER] If NACKed, UL harq has to have pending retx\n");
|
||||
CONDERROR(h->is_empty() and hack.nof_retx(0) + 1 < hack.max_nof_retx(),
|
||||
"[TESTER] Nacked UL harq did get emptied\n");
|
||||
}
|
||||
}
|
||||
|
||||
// erase processed acks
|
||||
to_ack.erase(tti_data.tti_rx);
|
||||
to_ul_ack.erase(tti_data.tti_rx);
|
||||
|
||||
// bool ack = true; //(tti_data.tti_rx % 3) == 0;
|
||||
// if (tti_data.tti_rx >= FDD_HARQ_DELAY_MS) {
|
||||
// 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 != nullptr and not h->is_empty()) {
|
||||
// ul_crc_info(tti_data.tti_rx, rnti, ack);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
srsenb::sched_interface::cell_cfg_t generate_cell_cfg()
|
||||
{
|
||||
srsenb::sched_interface::cell_cfg_t cell_cfg = {};
|
||||
srslte_cell_t& cell_cfg_phy = cell_cfg.cell;
|
||||
|
||||
std::uniform_int_distribution<uint32_t> dist_prb_idx(0, 5);
|
||||
uint32_t prb_idx = dist_prb_idx(rand_gen);
|
||||
uint32_t prb_idx = dist_prb_idx(srsenb::get_rand_gen());
|
||||
|
||||
/* Set PHY cell configuration */
|
||||
cell_cfg_phy.id = 1;
|
||||
|
@ -938,7 +660,7 @@ srsenb::sched_interface::cell_cfg_t generate_cell_cfg()
|
|||
return cell_cfg;
|
||||
}
|
||||
|
||||
void test_scheduler_rand(std::vector<srsenb::sched_interface::cell_cfg_t> cell_cfg, const sched_sim_args& args)
|
||||
void test_scheduler_rand(const sched_sim_args& args)
|
||||
{
|
||||
// Create classes
|
||||
sched_tester tester;
|
||||
|
@ -946,101 +668,100 @@ void test_scheduler_rand(std::vector<srsenb::sched_interface::cell_cfg_t> cell_c
|
|||
|
||||
log_global->set_level(srslte::LOG_LEVEL_INFO);
|
||||
|
||||
tester.sim_args = args;
|
||||
// srslte_cell_t& cell_cfg_phy = cell_cfg.cell;
|
||||
// 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.sim_events = args;
|
||||
sim_sched_args sim_args = args.sim_args;
|
||||
sim_args.ue_cfg = args.sim_args.ue_cfg;
|
||||
sim_args.bearer_cfg = args.sim_args.bearer_cfg;
|
||||
sim_args.start_tti = 0;
|
||||
sim_args.sim_log = log_global.get();
|
||||
|
||||
tester.init(nullptr);
|
||||
tester.cell_cfg(cell_cfg);
|
||||
tester.sim_cfg(sim_args);
|
||||
|
||||
bool running = true;
|
||||
uint32_t tti = 0;
|
||||
uint32_t nof_ttis = 0;
|
||||
while (running) {
|
||||
if (nof_ttis > args.nof_ttis) {
|
||||
running = false;
|
||||
}
|
||||
while (nof_ttis <= args.tti_events2.size()) {
|
||||
log_global->step(tti);
|
||||
|
||||
tester.run_tti(tti);
|
||||
tester.run_tti({});
|
||||
|
||||
nof_ttis++;
|
||||
tti = (tti + 1) % 10240;
|
||||
}
|
||||
}
|
||||
|
||||
sched_sim_args rand_sim_params(const srsenb::sched_interface::cell_cfg_t& cell_cfg, uint32_t nof_ttis)
|
||||
sched_sim_args rand_sim_params(uint32_t nof_ttis)
|
||||
{
|
||||
sched_sim_args sim_args;
|
||||
sched_sim_args sim_gen;
|
||||
std::vector<std::vector<uint32_t> > current_rntis;
|
||||
uint16_t rnti_start = 70;
|
||||
uint32_t max_conn_dur = 10000, min_conn_dur = 5000;
|
||||
float P_ul_sr = randf() * 0.5, P_dl = randf() * 0.5;
|
||||
float P_ul_sr = srsenb::randf() * 0.5, P_dl = srsenb::randf() * 0.5;
|
||||
float P_prach = 0.99f; // 0.1f + randf()*0.3f;
|
||||
float ul_sr_exps[] = {1, 4}; // log rand
|
||||
float dl_data_exps[] = {1, 4}; // log rand
|
||||
uint32_t max_nof_users = 5;
|
||||
std::uniform_int_distribution<> connection_dur_dist(min_conn_dur, max_conn_dur);
|
||||
|
||||
sim_args.ue_cfg = {};
|
||||
sim_args.ue_cfg.aperiodic_cqi_period = 40;
|
||||
sim_args.ue_cfg.maxharq_tx = 5;
|
||||
sim_args.ue_cfg.dl_cfg.tm = SRSLTE_TM1;
|
||||
sim_args.ue_cfg.supported_cc_list.emplace_back();
|
||||
sim_args.ue_cfg.supported_cc_list.back().enb_cc_idx = 0;
|
||||
sim_args.ue_cfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
|
||||
sim_gen.sim_args.cell_cfg = {generate_cell_cfg()};
|
||||
|
||||
bzero(&sim_args.bearer_cfg, sizeof(srsenb::sched_interface::ue_bearer_cfg_t));
|
||||
sim_args.bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
|
||||
sim_gen.sim_args.ue_cfg = generate_default_ue_cfg();
|
||||
|
||||
sim_args.nof_ttis = nof_ttis;
|
||||
sim_args.P_retx = 0.1;
|
||||
sim_args.tti_events.resize(sim_args.nof_ttis);
|
||||
bzero(&sim_gen.sim_args.bearer_cfg, sizeof(srsenb::sched_interface::ue_bearer_cfg_t));
|
||||
sim_gen.sim_args.bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH;
|
||||
|
||||
for (uint32_t tti = 0; tti < sim_args.tti_events.size(); ++tti) {
|
||||
sim_gen.sim_args.P_retx = 0.1;
|
||||
sim_gen.tti_events2.resize(nof_ttis);
|
||||
// sim_gen.sim_events.resize(nof_ttis);
|
||||
|
||||
for (uint32_t tti = 0; tti < sim_gen.tti_events2.size(); ++tti) {
|
||||
if (not current_rntis.empty()) {
|
||||
// may rem user
|
||||
for (uint32_t i = 0; i < current_rntis.size(); ++i) {
|
||||
if (current_rntis[i][2] + current_rntis[i][1] <= tti) {
|
||||
std::vector<std::vector<uint32_t> >::iterator it_to_rem = current_rntis.begin() + i;
|
||||
sim_args.tti_events[tti].rem_user = true;
|
||||
sim_args.tti_events[tti].rem_rnti = (*it_to_rem)[0];
|
||||
auto it_to_rem = current_rntis.begin() + i;
|
||||
sim_gen.tti_events2[tti].rem_user = true;
|
||||
sim_gen.tti_events2[tti].rem_rnti = (*it_to_rem)[0];
|
||||
current_rntis.erase(it_to_rem);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (srsenb::randf() < P_ul_sr) {
|
||||
float exp = ul_sr_exps[0] + srsenb::randf() * (ul_sr_exps[1] - ul_sr_exps[0]);
|
||||
sim_gen.tti_events2[tti].users[rnti].sr_data = (uint32_t)pow(10, exp);
|
||||
}
|
||||
if (randf() < P_dl) {
|
||||
float exp = dl_data_exps[0] + randf() * (dl_data_exps[1] - dl_data_exps[0]);
|
||||
sim_args.tti_events[tti].users[rnti].dl_data = (uint32_t)pow(10, exp);
|
||||
if (srsenb::randf() < P_dl) {
|
||||
float exp = dl_data_exps[0] + srsenb::randf() * (dl_data_exps[1] - dl_data_exps[0]);
|
||||
sim_gen.tti_events2[tti].users[rnti].dl_data = (uint32_t)pow(10, exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// may add new user (For now, we only support one UE per PRACH)
|
||||
bool is_prach_tti = srslte_prach_tti_opportunity_config_fdd(cell_cfg.prach_config, tti, -1);
|
||||
if (is_prach_tti and current_rntis.size() < max_nof_users and randf() < P_prach) {
|
||||
bool is_prach_tti =
|
||||
srslte_prach_tti_opportunity_config_fdd(sim_gen.sim_args.cell_cfg[CARRIER_IDX].prach_config, tti, -1);
|
||||
if (is_prach_tti and current_rntis.size() < max_nof_users and srsenb::randf() < P_prach) {
|
||||
std::vector<uint32_t> elem(3);
|
||||
elem[0] = rnti_start;
|
||||
elem[1] = tti;
|
||||
elem[2] = connection_dur_dist(rand_gen);
|
||||
elem[2] = connection_dur_dist(srsenb::get_rand_gen());
|
||||
current_rntis.push_back(elem);
|
||||
sim_args.tti_events[tti].new_user = true;
|
||||
sim_args.tti_events[tti].new_rnti = rnti_start++;
|
||||
sim_gen.tti_events2[tti].new_user = true;
|
||||
sim_gen.tti_events2[tti].new_rnti = rnti_start;
|
||||
rnti_start++;
|
||||
}
|
||||
}
|
||||
|
||||
return sim_args;
|
||||
return sim_gen;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Setup seed
|
||||
srsenb::set_randseed(seed);
|
||||
|
||||
srslte::logmap::set_default_log_level(srslte::LOG_LEVEL_INFO);
|
||||
printf("[TESTER] This is the chosen seed: %u\n", seed);
|
||||
/* initialize random seed: */
|
||||
|
@ -1048,10 +769,8 @@ int main()
|
|||
|
||||
for (uint32_t n = 0; n < N_runs; ++n) {
|
||||
printf("Sim run number: %u\n", n + 1);
|
||||
std::vector<srsenb::sched_interface::cell_cfg_t> cell_cfg = {generate_cell_cfg()};
|
||||
sched_sim_args sim_args = rand_sim_params(cell_cfg[0], nof_ttis);
|
||||
|
||||
test_scheduler_rand(cell_cfg, sim_args);
|
||||
sched_sim_args sim_args = rand_sim_params(nof_ttis);
|
||||
test_scheduler_rand(sim_args);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -27,36 +27,67 @@
|
|||
#include "srslte/interfaces/sched_interface.h"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
|
||||
struct tti_counter {
|
||||
tti_counter() = default;
|
||||
void set_start_tti(uint32_t tti_) { counter = tti_; }
|
||||
uint32_t tti_rx() const { return counter % 10240u; }
|
||||
tti_counter tic_tx_dl() const { return tti_counter{counter + TX_DELAY}; }
|
||||
tti_counter tic_tx_ul() const { return tti_counter{counter + TX_DELAY + FDD_HARQ_DELAY_MS}; }
|
||||
bool operator==(const tti_counter& other) const { return counter == other.counter; }
|
||||
bool operator!=(const tti_counter& other) const { return counter != other.counter; }
|
||||
bool operator<(const tti_counter& other) const { return counter < other.counter; }
|
||||
bool operator<=(const tti_counter& other) const { return counter <= other.counter; }
|
||||
bool operator>=(const tti_counter& other) const { return counter >= other.counter; }
|
||||
bool operator>(const tti_counter& other) const { return counter > other.counter; }
|
||||
uint32_t operator-(const tti_counter& other) const { return counter - other.counter; }
|
||||
tti_counter& operator-=(uint32_t jump)
|
||||
{
|
||||
counter -= jump;
|
||||
return *this;
|
||||
}
|
||||
tti_counter& operator+=(uint32_t jump)
|
||||
{
|
||||
counter += jump;
|
||||
return *this;
|
||||
}
|
||||
tti_counter& operator+=(int32_t jump)
|
||||
{
|
||||
counter += jump;
|
||||
return *this;
|
||||
}
|
||||
tti_counter& operator++() { return this->operator+=(1); }
|
||||
tti_counter operator+(int32_t jump) { return tti_counter{counter + jump}; }
|
||||
tti_counter operator++(int) { return tti_counter{++counter}; }
|
||||
bool is_valid() const { return counter != std::numeric_limits<uint32_t>::max(); }
|
||||
uint32_t total_count() const { return counter; }
|
||||
|
||||
private:
|
||||
explicit tti_counter(uint32_t c_) : counter(c_) {}
|
||||
uint32_t counter = std::numeric_limits<uint32_t>::max();
|
||||
};
|
||||
|
||||
/***************************
|
||||
* Setup Random generators
|
||||
* Function helpers
|
||||
**************************/
|
||||
|
||||
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<float> unif_dist(0, 1.0);
|
||||
bool check_old_pids = false;
|
||||
|
||||
float randf()
|
||||
template <class MapContainer, class Predicate>
|
||||
void erase_if(MapContainer& c, Predicate should_remove)
|
||||
{
|
||||
return unif_dist(rand_gen);
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
Integer rand_int(Integer lb, Integer ub)
|
||||
{
|
||||
std::uniform_int_distribution<Integer> dist(lb, ub);
|
||||
return dist(rand_gen);
|
||||
for (auto it = c.begin(); it != c.end();) {
|
||||
if (should_remove(*it)) {
|
||||
it = c.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************
|
||||
* Setup Sched Configuration
|
||||
****************************/
|
||||
|
||||
srsenb::sched_interface::cell_cfg_t generate_default_cell_cfg(uint32_t nof_prb)
|
||||
inline srsenb::sched_interface::cell_cfg_t generate_default_cell_cfg(uint32_t nof_prb)
|
||||
{
|
||||
srsenb::sched_interface::cell_cfg_t cell_cfg = {};
|
||||
srslte_cell_t& cell_cfg_phy = cell_cfg.cell;
|
||||
|
@ -82,7 +113,7 @@ srsenb::sched_interface::cell_cfg_t generate_default_cell_cfg(uint32_t nof_prb)
|
|||
return cell_cfg;
|
||||
}
|
||||
|
||||
srsenb::sched_interface::ue_cfg_t generate_default_ue_cfg()
|
||||
inline srsenb::sched_interface::ue_cfg_t generate_default_ue_cfg()
|
||||
{
|
||||
srsenb::sched_interface::ue_cfg_t ue_cfg = {};
|
||||
|
||||
|
@ -98,7 +129,7 @@ srsenb::sched_interface::ue_cfg_t generate_default_ue_cfg()
|
|||
}
|
||||
|
||||
/*****************************
|
||||
* Event Setup Helpers
|
||||
* Event Types
|
||||
****************************/
|
||||
|
||||
// Struct that represents all the events that take place in a TTI
|
||||
|
@ -119,11 +150,12 @@ struct tti_ev {
|
|||
};
|
||||
|
||||
struct sim_sched_args {
|
||||
uint32_t nof_ttis;
|
||||
uint32_t start_tti = 0;
|
||||
float P_retx;
|
||||
srsenb::sched_interface::ue_cfg_t ue_cfg;
|
||||
srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg;
|
||||
std::vector<srsenb::sched_interface::cell_cfg_t> cell_cfg;
|
||||
srslte::log* sim_log = nullptr;
|
||||
};
|
||||
|
||||
// generate all events up front
|
||||
|
|
Loading…
Reference in New Issue