nr,gnb,sched: implement ConRes CE scheduling command in NR sched

master
Francisco 3 years ago committed by Francisco Paisana
parent 64d65b1afa
commit ed1514cf68

@ -10,8 +10,8 @@
*
*/
#ifndef SRSRAN_UE_BUFFER_MANAGER_H
#define SRSRAN_UE_BUFFER_MANAGER_H
#ifndef SRSRAN_BASE_UE_BUFFER_MANAGER_H
#define SRSRAN_BASE_UE_BUFFER_MANAGER_H
#include "sched_config.h"
#include "srsran/adt/span.h"
@ -26,7 +26,7 @@ namespace srsenb {
* Class to handle UE DL+UL RLC and MAC buffers state
*/
template <bool isNR>
class ue_buffer_manager
class base_ue_buffer_manager
{
protected:
const static uint32_t MAX_LC_ID = isNR ? (srsran::MAX_NR_NOF_BEARERS - 1) : srsran::MAX_LTE_LCID;
@ -37,7 +37,7 @@ protected:
constexpr static uint32_t pbr_infinity = -1;
public:
explicit ue_buffer_manager(uint16_t rnti, srslog::basic_logger& logger_);
explicit base_ue_buffer_manager(uint16_t rnti, srslog::basic_logger& logger_);
// Bearer configuration
void config_lcids(srsran::const_span<mac_lc_ch_cfg_t> bearer_cfg_list);
@ -80,6 +80,8 @@ public:
static bool is_lcg_valid(uint32_t lcg) { return lcg <= MAX_LCG_ID; }
protected:
~base_ue_buffer_manager() = default;
bool config_lcid_internal(uint32_t lcid, const mac_lc_ch_cfg_t& bearer_cfg);
srslog::basic_logger& logger;
@ -99,4 +101,4 @@ protected:
} // namespace srsenb
#endif // SRSRAN_UE_BUFFER_MANAGER_H
#endif // SRSRAN_BASE_UE_BUFFER_MANAGER_H

@ -13,7 +13,7 @@
#ifndef SRSRAN_SCHED_LCH_H
#define SRSRAN_SCHED_LCH_H
#include "srsenb/hdr/stack/mac/common/ue_buffer_manager.h"
#include "srsenb/hdr/stack/mac/common/base_ue_buffer_manager.h"
#include "srsenb/hdr/stack/mac/sched_interface.h"
#include "srsran/adt/pool/cached_alloc.h"
#include "srsran/mac/pdu.h"
@ -21,12 +21,12 @@
namespace srsenb {
class lch_ue_manager : private ue_buffer_manager<false>
class lch_ue_manager : private base_ue_buffer_manager<false>
{
using base_type = ue_buffer_manager<false>;
using base_type = base_ue_buffer_manager<false>;
public:
explicit lch_ue_manager(uint16_t rnti) : ue_buffer_manager(rnti, srslog::fetch_basic_logger("MAC")) {}
explicit lch_ue_manager(uint16_t rnti) : base_ue_buffer_manager(rnti, srslog::fetch_basic_logger("MAC")) {}
void set_cfg(const sched_interface::ue_cfg_t& cfg_);
void new_tti();

@ -6,5 +6,5 @@
# the distribution.
#
set(SOURCES ue_buffer_manager.cc)
set(SOURCES base_ue_buffer_manager.cc)
add_library(srsenb_mac_common STATIC ${SOURCES})

@ -10,7 +10,7 @@
*
*/
#include "srsenb/hdr/stack/mac/common/ue_buffer_manager.h"
#include "srsenb/hdr/stack/mac/common/base_ue_buffer_manager.h"
#include "srsran/adt/bounded_vector.h"
#include "srsran/common/string_helpers.h"
#include "srsran/srslog/bundled/fmt/format.h"
@ -22,13 +22,14 @@ extern "C" {
namespace srsenb {
template <bool isNR>
ue_buffer_manager<isNR>::ue_buffer_manager(uint16_t rnti_, srslog::basic_logger& logger_) : logger(logger_), rnti(rnti_)
base_ue_buffer_manager<isNR>::base_ue_buffer_manager(uint16_t rnti_, srslog::basic_logger& logger_) :
logger(logger_), rnti(rnti_)
{
std::fill(lcg_bsr.begin(), lcg_bsr.end(), 0);
}
template <bool isNR>
void ue_buffer_manager<isNR>::config_lcids(srsran::const_span<mac_lc_ch_cfg_t> bearer_cfg_list)
void base_ue_buffer_manager<isNR>::config_lcids(srsran::const_span<mac_lc_ch_cfg_t> bearer_cfg_list)
{
bool log_enabled = logger.info.enabled();
srsran::bounded_vector<uint32_t, MAX_NOF_LCIDS> changed_list;
@ -58,7 +59,7 @@ void ue_buffer_manager<isNR>::config_lcids(srsran::const_span<mac_lc_ch_cfg_t> b
}
template <bool isNR>
void ue_buffer_manager<isNR>::config_lcid(uint32_t lcid, const mac_lc_ch_cfg_t& bearer_cfg)
void base_ue_buffer_manager<isNR>::config_lcid(uint32_t lcid, const mac_lc_ch_cfg_t& bearer_cfg)
{
bool cfg_changed = config_lcid_internal(lcid, bearer_cfg);
if (cfg_changed) {
@ -77,7 +78,7 @@ void ue_buffer_manager<isNR>::config_lcid(uint32_t lcid, const mac_lc_ch_cfg_t&
* @return true if the lcid was updated with new parameters. False in case of case of error or no update.
*/
template <bool isNR>
bool ue_buffer_manager<isNR>::config_lcid_internal(uint32_t lcid, const mac_lc_ch_cfg_t& bearer_cfg)
bool base_ue_buffer_manager<isNR>::config_lcid_internal(uint32_t lcid, const mac_lc_ch_cfg_t& bearer_cfg)
{
if (not is_lcid_valid(lcid)) {
logger.warning("SCHED: Configuring rnti=0x%x bearer with invalid lcid=%d", rnti, lcid);
@ -105,7 +106,7 @@ bool ue_buffer_manager<isNR>::config_lcid_internal(uint32_t lcid, const mac_lc_c
}
template <bool isNR>
int ue_buffer_manager<isNR>::get_dl_tx_total() const
int base_ue_buffer_manager<isNR>::get_dl_tx_total() const
{
int sum = 0;
for (size_t lcid = 0; is_lcid_valid(lcid); ++lcid) {
@ -115,7 +116,7 @@ int ue_buffer_manager<isNR>::get_dl_tx_total() const
}
template <bool isNR>
bool ue_buffer_manager<isNR>::is_lcg_active(uint32_t lcg) const
bool base_ue_buffer_manager<isNR>::is_lcg_active(uint32_t lcg) const
{
if (lcg == 0) {
return true;
@ -129,13 +130,13 @@ bool ue_buffer_manager<isNR>::is_lcg_active(uint32_t lcg) const
}
template <bool isNR>
int ue_buffer_manager<isNR>::get_bsr(uint32_t lcg) const
int base_ue_buffer_manager<isNR>::get_bsr(uint32_t lcg) const
{
return is_lcg_active(lcg) ? lcg_bsr[lcg] : 0;
}
template <bool isNR>
int ue_buffer_manager<isNR>::get_bsr() const
int base_ue_buffer_manager<isNR>::get_bsr() const
{
uint32_t count = 0;
for (uint32_t lcg = 0; is_lcg_valid(lcg); ++lcg) {
@ -147,7 +148,7 @@ int ue_buffer_manager<isNR>::get_bsr() const
}
template <bool isNR>
int ue_buffer_manager<isNR>::ul_bsr(uint32_t lcg_id, uint32_t val)
int base_ue_buffer_manager<isNR>::ul_bsr(uint32_t lcg_id, uint32_t val)
{
if (not is_lcg_valid(lcg_id)) {
logger.warning("SCHED: The provided lcg_id=%d for rnti=0x%x is not valid", lcg_id, rnti);
@ -158,7 +159,7 @@ int ue_buffer_manager<isNR>::ul_bsr(uint32_t lcg_id, uint32_t val)
}
template <bool isNR>
int ue_buffer_manager<isNR>::dl_buffer_state(uint8_t lcid, uint32_t tx_queue, uint32_t prio_tx_queue)
int base_ue_buffer_manager<isNR>::dl_buffer_state(uint8_t lcid, uint32_t tx_queue, uint32_t prio_tx_queue)
{
if (not is_lcid_valid(lcid)) {
logger.warning("The provided lcid=%d is not valid", lcid);
@ -170,7 +171,7 @@ int ue_buffer_manager<isNR>::dl_buffer_state(uint8_t lcid, uint32_t tx_queue, ui
}
// Explicit instantiation
template class ue_buffer_manager<true>;
template class ue_buffer_manager<false>;
template class base_ue_buffer_manager<true>;
template class base_ue_buffer_manager<false>;
} // namespace srsenb

@ -40,7 +40,8 @@ struct sched_nr_ue_cc_cfg_t {
};
struct sched_nr_ue_cfg_t {
uint32_t maxharq_tx = 4;
bool is_temp_crnti = false;
uint32_t maxharq_tx = 4;
srsran::bounded_vector<sched_nr_ue_cc_cfg_t, SCHED_NR_MAX_CARRIERS> carriers;
std::array<mac_lc_ch_cfg_t, SCHED_NR_MAX_LCID> ue_bearers = {};
srsran::phy_cfg_nr_t phy_cfg = {};

@ -16,8 +16,8 @@
#include "sched_nr_cfg.h"
#include "sched_nr_harq.h"
#include "sched_nr_interface.h"
#include "srsenb/hdr/stack/mac/common/base_ue_buffer_manager.h"
#include "srsenb/hdr/stack/mac/common/mac_metrics.h"
#include "srsenb/hdr/stack/mac/common/ue_buffer_manager.h"
#include "srsran/adt/circular_map.h"
#include "srsran/adt/move_callback.h"
#include "srsran/adt/pool/cached_alloc.h"
@ -26,6 +26,31 @@ namespace srsenb {
namespace sched_nr_impl {
class ue_buffer_manager : public base_ue_buffer_manager<true>
{
using base_type = base_ue_buffer_manager<true>;
public:
// Inherited methods from base_ue_buffer_manager base class
using base_type::base_type;
using base_type::config_lcid;
using base_type::dl_buffer_state;
using base_type::get_bsr;
using base_type::get_bsr_state;
using base_type::get_dl_prio_tx;
using base_type::get_dl_tx;
using base_type::is_bearer_active;
using base_type::is_bearer_dl;
using base_type::is_bearer_ul;
using base_type::is_lcg_active;
using base_type::ul_bsr;
int get_dl_tx_total() const;
// Control Element Command queue
srsran::deque<uint32_t> pending_ces;
};
class slot_ue;
class ue_carrier
@ -71,8 +96,10 @@ public:
void set_cfg(const ue_cfg_t& cfg);
const ue_cfg_t& cfg() const { return ue_cfg; }
/// UE state feedback
void mac_buffer_state(uint32_t ce_lcid, uint32_t nof_cmds = 1);
void rlc_buffer_state(uint32_t lcid, uint32_t newtx, uint32_t retx) { buffers.dl_buffer_state(lcid, newtx, retx); }
/// UE state feedback
void ul_bsr(uint32_t lcg, uint32_t bsr_val) { buffers.ul_bsr(lcg, bsr_val); }
void ul_sr_info() { last_sr_slot = last_pdcch_slot - TX_ENB_DELAY; }
@ -84,7 +111,7 @@ public:
}
uint32_t pcell_cc() const { return ue_cfg.carriers[0].cc; }
ue_buffer_manager<true> buffers;
ue_buffer_manager buffers;
std::array<std::unique_ptr<ue_carrier>, SCHED_NR_MAX_CARRIERS> carriers;
const uint16_t rnti;

@ -23,7 +23,7 @@ set(SOURCES mac_nr.cc
sched_nr_signalling.cc)
add_library(srsgnb_mac STATIC ${SOURCES})
target_link_libraries(srsgnb_mac srsenb_mac_common)
target_link_libraries(srsgnb_mac srsenb_mac_common srsran_mac)
include_directories(${PROJECT_SOURCE_DIR})
add_subdirectory(test)

@ -330,6 +330,7 @@ void mac_nr::rach_detected(const rach_info_t& rach_info)
// Add new user to the scheduler so that it can RX/TX SRB0
sched_nr_ue_cfg_t uecfg = {};
uecfg.is_temp_crnti = true;
uecfg.carriers.resize(1);
uecfg.carriers[0].active = true;
uecfg.carriers[0].cc = enb_cc_idx;

@ -13,10 +13,22 @@
#include "srsgnb/hdr/stack/mac/sched_nr_ue.h"
#include "srsgnb/hdr/stack/mac/sched_nr_pdcch.h"
#include "srsran/common/string_helpers.h"
#include "srsran/mac/mac_sch_pdu_nr.h"
namespace srsenb {
namespace sched_nr_impl {
int ue_buffer_manager::get_dl_tx_total() const
{
int total_bytes = base_type::get_dl_tx_total();
for (uint32_t lcid : pending_ces) {
total_bytes += srsran::mac_sch_subpdu_nr::sizeof_ce(lcid, false);
}
return total_bytes;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
slot_ue::slot_ue(ue_carrier& ue_, slot_point slot_tx_, uint32_t dl_pending_bytes, uint32_t ul_pending_bytes) :
ue(&ue_), pdcch_slot(slot_tx_)
{
@ -98,6 +110,8 @@ ue::ue(uint16_t rnti_, const ue_cfg_t& cfg, const sched_params_t& sched_cfg_) :
void ue::set_cfg(const ue_cfg_t& cfg)
{
bool conres_needed = cfg.is_temp_crnti != ue_cfg.is_temp_crnti;
ue_cfg = cfg;
for (auto& ue_cc_cfg : cfg.carriers) {
if (ue_cc_cfg.active) {
@ -110,6 +124,17 @@ void ue::set_cfg(const ue_cfg_t& cfg)
}
buffers.config_lcids(cfg.ue_bearers);
if (conres_needed) {
mac_buffer_state(62, 1);
}
}
void ue::mac_buffer_state(uint32_t ce_lcid, uint32_t nof_cmds)
{
for (uint32_t i = 0; i < nof_cmds; ++i) {
buffers.pending_ces.push_back(ce_lcid);
}
}
void ue::new_slot(slot_point pdcch_slot)

@ -0,0 +1,120 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "sched_nr_cfg_generators.h"
#include "sched_nr_sim_ue.h"
#include "srsran/common/phy_cfg_nr_default.h"
#include "srsran/common/test_common.h"
#include <chrono>
namespace srsenb {
using dl_sched_t = sched_nr_interface::dl_sched_t;
static const srsran::phy_cfg_nr_t default_phy_cfg =
srsran::phy_cfg_nr_default_t{srsran::phy_cfg_nr_default_t::reference_cfg_t{}};
class sched_nr_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& slot_ctxt, srsran::const_span<cc_result_t> cc_list) override
{
tot_latency_sched_ns +=
std::max_element(cc_list.begin(), cc_list.end(), [](const cc_result_t& lhs, const cc_result_t& rhs) {
return lhs.cc_latency_ns < rhs.cc_latency_ns;
})->cc_latency_ns.count();
for (auto& cc_out : cc_list) {
pdsch_count += cc_out.res.dl->phy.pdcch_dl.size();
cc_res_count++;
bool is_dl_slot = srsran_duplex_nr_is_dl(&cell_params[cc_out.res.cc].cfg.duplex, 0, current_slot_tx.slot_idx());
if (is_dl_slot) {
if (cc_out.res.dl->phy.ssb.empty()) {
TESTASSERT(slot_ctxt.ue_db.empty() or cc_out.res.dl->phy.pdcch_dl.size() == 1);
} else {
TESTASSERT(cc_out.res.dl->phy.pdcch_dl.size() == 0);
}
}
}
}
void print_results() const
{
test_logger.info("TESTER: %f PDSCH/{slot,cc} were allocated", pdsch_count / (double)cc_res_count);
srslog::flush();
}
srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST");
uint64_t tot_latency_sched_ns = 0;
uint32_t cc_res_count = 0;
uint32_t pdsch_count = 0;
};
void run_sched_nr_test(uint32_t nof_workers)
{
srsran_assert(nof_workers > 0, "There must be at least one worker");
uint32_t max_nof_ttis = 1000, nof_sectors = 4;
uint16_t rnti = 0x4601;
sched_nr_interface::sched_args_t cfg;
cfg.auto_refill_buffer = true;
std::vector<sched_nr_interface::cell_cfg_t> cells_cfg = get_default_cells_cfg(nof_sectors);
std::string test_name = "Serialized Test";
if (nof_workers > 1) {
test_name = fmt::format("Parallel Test with {} workers", nof_workers);
}
sched_nr_tester tester(cfg, cells_cfg, test_name, nof_workers);
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;
if (slot_rx.to_uint() == 9) {
sched_nr_interface::ue_cfg_t uecfg = get_default_ue_cfg(nof_sectors);
tester.add_user(rnti, uecfg, slot_rx, 0);
}
tester.run_slot(slot_tx);
}
tester.stop();
tester.print_results();
// TESTASSERT(tasks.pdsch_count == (int)(max_nof_ttis * nof_sectors * 0.6));
double final_avg_usec = tester.tot_latency_sched_ns;
final_avg_usec = final_avg_usec / 1000.0 / max_nof_ttis;
printf("Total time taken per slot: %f usec\n", final_avg_usec);
}
} // namespace srsenb
int main()
{
auto& test_logger = srslog::fetch_basic_logger("TEST");
test_logger.set_level(srslog::basic_levels::warning);
auto& mac_nr_logger = srslog::fetch_basic_logger("MAC-NR");
mac_nr_logger.set_level(srslog::basic_levels::warning);
auto& pool_logger = srslog::fetch_basic_logger("POOL");
pool_logger.set_level(srslog::basic_levels::debug);
// Start the log backend.
srslog::init();
srsenb::run_sched_nr_test(1);
srsenb::run_sched_nr_test(2);
srsenb::run_sched_nr_test(4);
}

@ -14,90 +14,59 @@
#include "sched_nr_sim_ue.h"
#include "srsran/common/phy_cfg_nr_default.h"
#include "srsran/common/test_common.h"
#include <chrono>
namespace srsenb {
using dl_sched_t = sched_nr_interface::dl_sched_t;
static const srsran::phy_cfg_nr_t default_phy_cfg =
srsran::phy_cfg_nr_default_t{srsran::phy_cfg_nr_default_t::reference_cfg_t{}};
struct sched_event_t {
uint32_t slot_count;
std::function<void(sched_nr_base_tester&)> run;
};
class sched_nr_tester : public sched_nr_base_tester
sched_event_t add_user(uint32_t slot_count, uint16_t rnti, uint32_t preamble_idx)
{
public:
using sched_nr_base_tester::sched_nr_base_tester;
void process_slot_result(const sim_nr_enb_ctxt_t& slot_ctxt, srsran::const_span<cc_result_t> cc_list) override
{
tot_latency_sched_ns +=
std::max_element(cc_list.begin(), cc_list.end(), [](const cc_result_t& lhs, const cc_result_t& rhs) {
return lhs.cc_latency_ns < rhs.cc_latency_ns;
})->cc_latency_ns.count();
for (auto& cc_out : cc_list) {
pdsch_count += cc_out.res.dl->phy.pdcch_dl.size();
cc_res_count++;
bool is_dl_slot = srsran_duplex_nr_is_dl(&cell_params[cc_out.res.cc].cfg.duplex, 0, current_slot_tx.slot_idx());
if (is_dl_slot) {
if (cc_out.res.dl->phy.ssb.empty()) {
TESTASSERT(slot_ctxt.ue_db.empty() or cc_out.res.dl->phy.pdcch_dl.size() == 1);
} else {
TESTASSERT(cc_out.res.dl->phy.pdcch_dl.size() == 0);
}
}
}
}
void print_results() const
{
test_logger.info("TESTER: %f PDSCH/{slot,cc} were allocated", pdsch_count / (double)cc_res_count);
srslog::flush();
}
srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST");
auto task = [rnti, preamble_idx](sched_nr_base_tester& tester) {
tester.add_user(rnti, get_rach_ue_cfg(1), tester.get_slot_tx() - TX_ENB_DELAY, preamble_idx);
};
return sched_event_t{slot_count, task};
}
uint64_t tot_latency_sched_ns = 0;
uint32_t cc_res_count = 0;
uint32_t pdsch_count = 0;
};
sched_event_t ue_cfg(uint32_t slot_count, uint16_t rnti, const sched_nr_ue_cfg_t& ue_cfg)
{
auto task = [rnti, ue_cfg](sched_nr_base_tester& tester) { tester.user_cfg(rnti, ue_cfg); };
return sched_event_t{slot_count, task};
}
void run_sched_nr_test(uint32_t nof_workers)
void run_sched_nr_test()
{
srsran_assert(nof_workers > 0, "There must be at least one worker");
uint32_t max_nof_ttis = 1000, nof_sectors = 4;
uint32_t max_nof_ttis = 1000, nof_sectors = 1;
uint16_t rnti = 0x4601;
sched_nr_interface::sched_args_t cfg;
cfg.auto_refill_buffer = true;
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";
if (nof_workers > 1) {
test_name = fmt::format("Parallel Test with {} workers", nof_workers);
}
sched_nr_tester tester(cfg, cells_cfg, test_name, nof_workers);
std::string test_name = "Serialized Test";
sched_nr_base_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)));
/* 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;
if (slot_rx.to_uint() == 9) {
sched_nr_interface::ue_cfg_t uecfg = get_default_ue_cfg(nof_sectors);
tester.add_user(rnti, uecfg, slot_rx, 0);
// 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.stop();
tester.print_results();
// TESTASSERT(tasks.pdsch_count == (int)(max_nof_ttis * nof_sectors * 0.6));
double final_avg_usec = tester.tot_latency_sched_ns;
final_avg_usec = final_avg_usec / 1000.0 / max_nof_ttis;
printf("Total time taken per slot: %f usec\n", final_avg_usec);
}
} // namespace srsenb
@ -114,7 +83,5 @@ int main()
// Start the log backend.
srslog::init();
srsenb::run_sched_nr_test(1);
srsenb::run_sched_nr_test(2);
srsenb::run_sched_nr_test(4);
srsenb::run_sched_nr_test();
}

@ -1213,6 +1213,7 @@ int rrc_nr::ue::update_rlc_bearers(const asn1::rrc_nr::cell_group_cfg_s& cell_gr
int rrc_nr::ue::update_mac(const cell_group_cfg_s& cell_group_diff, bool is_config_complete)
{
if (not is_config_complete) {
uecfg.is_temp_crnti = false;
// Release bearers
for (uint8_t lcid : cell_group_diff.rlc_bearer_to_release_list) {
uecfg.ue_bearers[lcid].direction = mac_lc_ch_cfg_t::IDLE;

Loading…
Cancel
Save