nr,gnb,sched: fix and extend sched_nr_test to verify that the DL allocated bytes match the bytes passed as DL buffer state to the scheduler

This commit is contained in:
Francisco 2021-12-08 14:55:08 +00:00 committed by Francisco Paisana
parent 107e2aa938
commit 5cc7863379
3 changed files with 218 additions and 8 deletions

View File

@ -78,7 +78,11 @@ void sched_nr_ue_sim::update_dl_harqs(const sched_nr_cc_result_view& cc_out)
h.ndi = data.dci.ndi;
h.first_slot_tx = cc_out.slot;
h.dci_loc = data.dci.ctx.location;
h.tbs = 100; // TODO
for (const sched_nr_impl::pdsch_t& pdsch : cc_out.dl->phy.pdsch) {
if (pdsch.sch.grant.rnti == data.dci.ctx.rnti) {
h.tbs = pdsch.sch.grant.tb[0].tbs / 8u;
}
}
} else {
// it is retx
h.nof_retxs++;
@ -229,6 +233,12 @@ void sched_nr_base_tester::user_cfg(uint16_t rnti, const sched_nr_interface::ue_
sched_ptr->ue_cfg(rnti, ue_cfg_);
}
void sched_nr_base_tester::add_rlc_dl_bytes(uint16_t rnti, uint32_t lcid, uint32_t pdu_size_bytes)
{
TESTASSERT(ue_db.count(rnti) > 0);
dl_buffer_state_diff(rnti, lcid, pdu_size_bytes);
}
void sched_nr_base_tester::run_slot(slot_point slot_tx)
{
srsran_assert(not stopped.load(std::memory_order_relaxed), "Running scheduler when it has already been stopped");
@ -313,6 +323,83 @@ void sched_nr_base_tester::process_results()
for (auto& u : ue_db) {
u.second.update(cc_out);
}
// Update scheduler buffers
update_sched_buffer_state(cc_out);
}
}
void sched_nr_base_tester::dl_buffer_state_diff(uint16_t rnti, uint32_t lcid, int newtx)
{
auto& lch = gnb_ue_db[rnti].logical_channels[lcid];
lch.rlc_unacked = std::max(0, (int)lch.rlc_unacked + newtx);
update_sched_buffer_state(rnti);
logger.debug("STATUS: rnti=0x%x, lcid=%d DL buffer state is (unacked=%d, newtx=%d)",
rnti,
lcid,
lch.rlc_unacked,
lch.rlc_newtx);
}
void sched_nr_base_tester::dl_buffer_state_diff(uint16_t rnti, int diff_bs)
{
if (diff_bs == 0) {
return;
}
if (diff_bs > 0) {
const auto& ue_bearers = ue_db.at(rnti).get_ctxt().ue_cfg.ue_bearers;
for (int i = ue_bearers.size() - 1; i >= 0; --i) {
if (ue_bearers[i].is_dl()) {
dl_buffer_state_diff(rnti, i, diff_bs);
return;
}
}
srsran_terminate("Updating UE RLC buffer state but no bearers are active");
}
for (auto& lch : gnb_ue_db[rnti].logical_channels) {
if (not ue_db.at(rnti).get_ctxt().ue_cfg.ue_bearers[lch.first].is_dl()) {
continue;
}
int max_diff = -std::min((int)lch.second.rlc_unacked, -diff_bs);
if (max_diff != 0) {
dl_buffer_state_diff(rnti, lch.first, max_diff);
diff_bs -= max_diff;
}
}
}
void sched_nr_base_tester::update_sched_buffer_state(uint16_t rnti)
{
auto& u = ue_db.at(rnti);
for (auto& lch : gnb_ue_db[rnti].logical_channels) {
int newtx = lch.second.rlc_unacked;
for (auto& cc : u.get_ctxt().cc_list) {
if (newtx <= 0) {
break;
}
for (auto& dl_h : cc.dl_harqs) {
int tbs = dl_h.active ? dl_h.tbs : 0;
newtx = std::max(0, newtx - tbs);
}
}
if (newtx != (int)lch.second.rlc_newtx) {
sched_ptr->dl_buffer_state(rnti, lch.first, newtx, 0);
lch.second.rlc_newtx = newtx;
logger.debug("STATUS: rnti=0x%x, lcid=%d DL buffer state is (unacked=%d, newtx=%d)",
rnti,
lch.first,
lch.second.rlc_unacked,
lch.second.rlc_newtx);
}
}
}
void sched_nr_base_tester::update_sched_buffer_state(const sched_nr_cc_result_view& cc_out)
{
for (auto& dl : cc_out.dl->phy.pdcch_dl) {
if (dl.dci.ctx.rnti_type == srsran_rnti_type_c or dl.dci.ctx.rnti_type == srsran_rnti_type_tc) {
update_sched_buffer_state(dl.dci.ctx.rnti);
}
}
}
@ -359,8 +446,13 @@ int sched_nr_base_tester::apply_slot_events(sim_nr_ue_ctxt_t& ue_ctxt, const ue_
auto& h = ue_ctxt.cc_list[enb_cc_idx].dl_harqs[ack.pid];
if (ack.ack) {
logger.info(
"DL ACK rnti=0x%x slot_dl_tx=%u cc=%d pid=%d", ue_ctxt.rnti, h.last_slot_tx.to_uint(), enb_cc_idx, ack.pid);
logger.info("EVENT: DL ACK rnti=0x%x slot_dl_tx=%u cc=%d pid=%d, tbs=%d",
ue_ctxt.rnti,
h.last_slot_tx.to_uint(),
enb_cc_idx,
ack.pid,
h.tbs);
dl_buffer_state_diff(ue_ctxt.rnti, -(int)h.tbs);
}
// update scheduler
@ -385,7 +477,7 @@ int sched_nr_base_tester::apply_slot_events(sim_nr_ue_ctxt_t& ue_ctxt, const ue_
if (h.is_msg3) {
logger.info("STATUS: rnti=0x%x received Msg3", ue_ctxt.rnti);
sched_ptr->dl_buffer_state(ue_ctxt.rnti, 0, 150, 0); // Schedule RRC setup
dl_buffer_state_diff(ue_ctxt.rnti, 0, 150); // Schedule RRC setup
}
}
}

View File

@ -129,6 +129,8 @@ public:
void user_cfg(uint16_t rnti, const sched_nr_interface::ue_cfg_t& ue_cfg_);
void add_rlc_dl_bytes(uint16_t rnti, uint32_t lcid, uint32_t pdu_size_bytes);
srsran::const_span<sched_nr_impl::cell_params_t> get_cell_params() { return cell_params; }
// configurable by simulator concrete implementation
@ -141,6 +143,11 @@ protected:
void generate_cc_result(uint32_t cc);
sim_nr_enb_ctxt_t get_enb_ctxt() const;
void dl_buffer_state_diff(uint16_t rnti, uint32_t lcid, int newtx);
void dl_buffer_state_diff(uint16_t rnti, int newtx);
void update_sched_buffer_state(uint16_t rnti);
void update_sched_buffer_state(const sched_nr_cc_result_view& cc_out);
int set_default_slot_events(const sim_nr_ue_ctxt_t& ue_ctxt, ue_nr_slot_events& pending_events);
int apply_slot_events(sim_nr_ue_ctxt_t& ue_ctxt, const ue_nr_slot_events& events);
@ -155,8 +162,19 @@ protected:
std::vector<std::unique_ptr<srsran::task_worker> > cc_workers;
// UE context from the UE's point-of-view
std::map<uint16_t, sched_nr_ue_sim> ue_db;
// gNB point-of-view of UE state
struct gnb_ue_ctxt {
struct channel_ctxt {
uint32_t rlc_unacked = 0;
uint32_t rlc_newtx = 0;
};
std::map<uint32_t, channel_ctxt> logical_channels;
};
std::map<uint16_t, gnb_ue_ctxt> gnb_ue_db;
// slot-specific
slot_point current_slot_tx;
std::chrono::steady_clock::time_point slot_start_tp;

View File

@ -17,6 +17,50 @@
namespace srsenb {
class sched_tester : public sched_nr_base_tester
{
public:
using sched_nr_base_tester::sched_nr_base_tester;
void process_slot_result(const sim_nr_enb_ctxt_t& enb_ctxt, srsran::const_span<cc_result_t> cc_out) override
{
for (auto& cc : cc_out) {
for (auto& pdsch : cc.res.dl->phy.pdsch) {
if (pdsch.sch.grant.rnti_type == srsran_rnti_type_c or pdsch.sch.grant.rnti_type == srsran_rnti_type_tc) {
ue_metrics[pdsch.sch.grant.rnti].nof_dl_txs++;
ue_metrics[pdsch.sch.grant.rnti].nof_dl_bytes += pdsch.sch.grant.tb[0].tbs / 8u;
}
}
for (auto& pusch : cc.res.ul->pusch) {
if (pusch.sch.grant.rnti_type == srsran_rnti_type_c or pusch.sch.grant.rnti_type == srsran_rnti_type_tc) {
ue_metrics[pusch.sch.grant.rnti].nof_ul_txs++;
ue_metrics[pusch.sch.grant.rnti].nof_ul_bytes += pusch.sch.grant.tb[0].tbs / 8u;
}
}
}
}
void print_results()
{
srslog::flush();
fmt::print("SCHED UE metrics:\n");
for (auto& u : ue_metrics) {
fmt::print(" 0x{:x}: nof_txs=({}, {}), nof_bytes=({}, {})\n",
u.first,
u.second.nof_dl_txs,
u.second.nof_ul_txs,
u.second.nof_dl_bytes,
u.second.nof_ul_bytes);
}
}
struct sched_ue_metrics {
uint32_t nof_dl_txs = 0, nof_ul_txs = 0;
uint64_t nof_dl_bytes = 0, nof_ul_bytes = 0;
};
std::map<uint16_t, sched_ue_metrics> ue_metrics;
};
struct sched_event_t {
uint32_t slot_count;
std::function<void(sched_nr_base_tester&)> run;
@ -36,7 +80,13 @@ sched_event_t ue_cfg(uint32_t slot_count, uint16_t rnti, const sched_nr_ue_cfg_t
return sched_event_t{slot_count, task};
}
void run_sched_nr_test()
sched_event_t add_rlc_dl_bytes(uint32_t slot_count, uint16_t rnti, uint32_t lcid, uint32_t pdu_size)
{
auto task = [rnti, pdu_size, lcid](sched_nr_base_tester& tester) { tester.add_rlc_dl_bytes(rnti, lcid, pdu_size); };
return sched_event_t{slot_count, task};
}
void test_sched_nr_no_data()
{
uint32_t max_nof_ttis = 1000, nof_sectors = 1;
uint16_t rnti = 0x4601;
@ -45,8 +95,8 @@ void run_sched_nr_test()
cfg.auto_refill_buffer = false;
std::vector<sched_nr_interface::cell_cfg_t> cells_cfg = get_default_cells_cfg(nof_sectors);
std::string test_name = "Serialized Test";
sched_nr_base_tester tester(cfg, cells_cfg, test_name);
std::string test_name = "Test with no data";
sched_tester tester(cfg, cells_cfg, test_name);
/* Set events */
std::deque<sched_event_t> events;
@ -67,6 +117,55 @@ void run_sched_nr_test()
// call sched
tester.run_slot(slot_tx);
}
tester.print_results();
// Since DL buffers were not externally updated, we should only see Msg4 as DL tx
TESTASSERT_EQ(1, tester.ue_metrics[rnti].nof_dl_txs);
// Since UL buffers were not externally updated, we should only see Msg3 as UL tx
TESTASSERT_EQ(1, tester.ue_metrics[rnti].nof_ul_txs);
}
void test_sched_nr_data()
{
uint32_t max_nof_ttis = 1000, nof_sectors = 1;
uint16_t rnti = 0x4601;
uint32_t nof_dl_bytes_to_tx = 1e6;
sched_nr_interface::sched_args_t cfg;
cfg.auto_refill_buffer = false;
std::vector<sched_nr_interface::cell_cfg_t> cells_cfg = get_default_cells_cfg(nof_sectors);
std::string test_name = "Test with data";
sched_tester tester(cfg, cells_cfg, test_name);
/* Set events */
std::deque<sched_event_t> events;
events.push_back(add_user(9, rnti, 0));
events.push_back(ue_cfg(20, rnti, get_default_ue_cfg(1)));
events.push_back(add_rlc_dl_bytes(50, rnti, 0, nof_dl_bytes_to_tx));
/* Run Test */
for (uint32_t nof_slots = 0; nof_slots < max_nof_ttis; ++nof_slots) {
slot_point slot_rx(0, nof_slots % 10240);
slot_point slot_tx = slot_rx + TX_ENB_DELAY;
// run events
while (not events.empty() and events.front().slot_count <= nof_slots) {
events.front().run(tester);
events.pop_front();
}
// call sched
tester.run_slot(slot_tx);
}
tester.print_results();
TESTASSERT(tester.ue_metrics[rnti].nof_dl_txs > 1);
TESTASSERT(tester.ue_metrics[rnti].nof_dl_bytes >= nof_dl_bytes_to_tx);
// Since UL buffers were not externally updated, we should only see Msg3 as UL tx
TESTASSERT_EQ(1, tester.ue_metrics[rnti].nof_ul_txs);
}
} // namespace srsenb
@ -83,5 +182,6 @@ int main()
// Start the log backend.
srslog::init();
srsenb::run_sched_nr_test();
srsenb::test_sched_nr_no_data();
srsenb::test_sched_nr_data();
}