diff --git a/srsenb/hdr/stack/mac/sched_pf.h b/srsenb/hdr/stack/mac/sched_pf.h new file mode 100644 index 000000000..12af4ab52 --- /dev/null +++ b/srsenb/hdr/stack/mac/sched_pf.h @@ -0,0 +1,99 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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. + * + */ + +#ifndef SRSLTE_SCHED_PF_H +#define SRSLTE_SCHED_PF_H + +#include "sched.h" +#include + +namespace srsenb { + +class sched_dl_pf : public sched::metric_dl +{ + using ue_cit_t = std::map::const_iterator; + +public: + void set_params(const sched_cell_params_t& cell_params_) final; + void sched_users(std::map& ue_db, dl_sf_sched_itf* tti_sched) final; + +private: + const sched_cell_params_t* cc_cfg = nullptr; + srslte::log_ref log_h; + + struct ue_ctxt { + ue_ctxt(uint16_t rnti_) : rnti(rnti_) {} + float avg_rate() const { return nof_samples == 0 ? 0 : rate; } + uint32_t count() const { return nof_samples; } + void new_tti(const sched_cell_params_t& cell, sched_ue& ue, dl_sf_sched_itf* tti_sched); + void save_history(bool alloc, float alpha); + + const uint16_t rnti; + + uint32_t ue_cc_idx = 0; + bool is_retx = false; + float prio = 0; + dl_harq_proc* h = nullptr; + + private: + float rate = 0; + uint32_t nof_samples = 0; + }; + std::map ue_history_db; + struct ue_prio_compare { + bool operator()(const ue_ctxt* lhs, const ue_ctxt* rhs) const; + }; + std::priority_queue, ue_prio_compare> ue_queue; + + bool try_dl_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, dl_sf_sched_itf* tti_sched); +}; + +class sched_ul_pf : public sched::metric_ul +{ + using ue_cit_t = std::map::const_iterator; + +public: + void set_params(const sched_cell_params_t& cell_params_) final; + void sched_users(std::map& ue_db, ul_sf_sched_itf* tti_sched) final; + +private: + const sched_cell_params_t* cc_cfg = nullptr; + srslte::log_ref log_h; + struct ue_ctxt { + ue_ctxt(uint16_t rnti_) : rnti(rnti_) {} + float avg_rate() const { return nof_samples == 0 ? 0 : rate; } + uint32_t count() const { return nof_samples; } + void new_tti(const sched_cell_params_t& cell, sched_ue& ue, ul_sf_sched_itf* tti_sched); + void save_history(bool alloc, float alpha); + + const uint16_t rnti; + + uint32_t ue_cc_idx = 0; + float prio = 0; + ul_harq_proc* h = nullptr; + + private: + float rate = 0; + uint32_t nof_samples = 0; + }; + std::map ue_history_db; + struct ue_prio_compare { + bool operator()(const ue_ctxt* lhs, const ue_ctxt* rhs) const; + }; + std::priority_queue, ue_prio_compare> ue_queue; + + bool try_ul_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, ul_sf_sched_itf* tti_sched); +}; + +} // namespace srsenb + +#endif // SRSLTE_SCHED_PF_H diff --git a/srsenb/hdr/stack/mac/sched_ue.h b/srsenb/hdr/stack/mac/sched_ue.h index b343eca2c..6b4aeac8a 100644 --- a/srsenb/hdr/stack/mac/sched_ue.h +++ b/srsenb/hdr/stack/mac/sched_ue.h @@ -49,8 +49,8 @@ struct cc_sched_ue { const sched_cell_params_t* get_cell_cfg() const { return cell_params; } uint32_t get_ue_cc_idx() const { return ue_cc_idx; } void set_dl_cqi(uint32_t tti_tx_dl, uint32_t dl_cqi); - int cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool use_tbs_index_alt, bool is_ul, uint32_t* mcs); - cc_st cc_state() const { return cc_state_; } + int cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool is_ul, uint32_t* mcs); + cc_st cc_state() const { return cc_state_; } harq_entity harq_ent; @@ -144,11 +144,13 @@ public: rbg_interval get_required_dl_rbgs(uint32_t ue_cc_idx); srslte::interval get_requested_dl_bytes(uint32_t ue_cc_idx); uint32_t get_pending_dl_rlc_data() const; + uint32_t get_expected_dl_bitrate(uint32_t ue_cc_idx) const; uint32_t get_pending_ul_data_total(uint32_t tti, int this_ue_cc_idx); uint32_t get_pending_ul_new_data(uint32_t tti, int this_ue_cc_idx); uint32_t get_pending_ul_old_data(); uint32_t get_pending_ul_old_data(uint32_t cc_idx); + uint32_t get_expected_ul_bitrate(uint32_t ue_cc_idx) const; dl_harq_proc* get_pending_dl_harq(uint32_t tti_tx_dl, uint32_t cc_idx); dl_harq_proc* get_empty_dl_harq(uint32_t tti_tx_dl, uint32_t cc_idx); diff --git a/srsenb/src/stack/mac/CMakeLists.txt b/srsenb/src/stack/mac/CMakeLists.txt index 3bc30b94e..949487586 100644 --- a/srsenb/src/stack/mac/CMakeLists.txt +++ b/srsenb/src/stack/mac/CMakeLists.txt @@ -7,7 +7,7 @@ # set(SOURCES mac.cc ue.cc sched.cc sched_carrier.cc sched_grid.cc sched_harq.cc sched_metric.cc sched_ue.cc - sched_lch.cc sched_interface_helpers.cc) + sched_lch.cc sched_interface_helpers.cc sched_pf.cc) add_library(srsenb_mac STATIC ${SOURCES}) if(ENABLE_5GNR) diff --git a/srsenb/src/stack/mac/sched_carrier.cc b/srsenb/src/stack/mac/sched_carrier.cc index 1b0117c96..2cbe4b168 100644 --- a/srsenb/src/stack/mac/sched_carrier.cc +++ b/srsenb/src/stack/mac/sched_carrier.cc @@ -13,6 +13,7 @@ #include "srsenb/hdr/stack/mac/sched_carrier.h" #include "srsenb/hdr/stack/mac/sched_interface_helpers.h" #include "srsenb/hdr/stack/mac/sched_metric.h" +#include "srsenb/hdr/stack/mac/sched_pf.h" #include "srslte/common/log_helper.h" #include "srslte/common/logmap.h" @@ -288,9 +289,13 @@ void sched::carrier_sched::carrier_cfg(const sched_cell_params_t& cell_params_) ra_sched_ptr.reset(new ra_sched{*cc_cfg, *ue_db}); // Setup data scheduling algorithms - dl_metric.reset(new srsenb::dl_metric_rr{}); + // dl_metric.reset(new srsenb::dl_metric_rr{}); + // dl_metric->set_params(*cc_cfg); + // ul_metric.reset(new srsenb::ul_metric_rr{}); + // ul_metric->set_params(*cc_cfg); + dl_metric.reset(new srsenb::sched_dl_pf{}); dl_metric->set_params(*cc_cfg); - ul_metric.reset(new srsenb::ul_metric_rr{}); + ul_metric.reset(new srsenb::sched_ul_pf{}); ul_metric->set_params(*cc_cfg); // Initiate the tti_scheduler for each TTI diff --git a/srsenb/src/stack/mac/sched_harq.cc b/srsenb/src/stack/mac/sched_harq.cc index 2b1722e8b..714d2f986 100644 --- a/srsenb/src/stack/mac/sched_harq.cc +++ b/srsenb/src/stack/mac/sched_harq.cc @@ -371,21 +371,6 @@ void harq_entity::reset_pending_data(srslte::tti_point tti_rx) for (auto& h : dl_harqs) { h.reset_pending_data(); } - - // delete old DL harq procs - for (auto& h : dl_harqs) { - if (not h.is_empty()) { - if (tti_tx_dl > h.get_tti() + 100) { - srslte::logmap::get("MAC")->info("SCHED: pid=%d is old. tti_pid=%d, now is %d, resetting\n", - h.get_id(), - h.get_tti().to_uint(), - tti_tx_dl.to_uint()); - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - h.reset(tb); - } - } - } - } } /** diff --git a/srsenb/src/stack/mac/sched_metric.cc b/srsenb/src/stack/mac/sched_metric.cc index df71092fb..242814e09 100644 --- a/srsenb/src/stack/mac/sched_metric.cc +++ b/srsenb/src/stack/mac/sched_metric.cc @@ -245,6 +245,10 @@ ul_harq_proc* ul_metric_rr::allocate_user_retx_prbs(sched_ue* user) // if there are procedures and we have space if (h->has_pending_retx()) { + // Avoid measGaps + if (not user->pusch_enabled(tti_rx, cc_cfg->enb_cc_idx, false)) { + return nullptr; + } prb_interval alloc = h->get_alloc(); // If can schedule the same mask, do it @@ -257,6 +261,10 @@ ul_harq_proc* ul_metric_rr::allocate_user_retx_prbs(sched_ue* user) return nullptr; } + // Avoid measGaps accounting for PDCCH + if (not user->pusch_enabled(tti_rx, cc_cfg->enb_cc_idx, true)) { + return nullptr; + } if (find_allocation(alloc.length(), &alloc)) { ret = tti_alloc->alloc_ul_user(user, alloc); if (ret == alloc_outcome_t::SUCCESS) { diff --git a/srsenb/src/stack/mac/sched_pf.cc b/srsenb/src/stack/mac/sched_pf.cc new file mode 100644 index 000000000..21f9151bc --- /dev/null +++ b/srsenb/src/stack/mac/sched_pf.cc @@ -0,0 +1,355 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2020 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 "srsenb/hdr/stack/mac/sched_pf.h" +#include "srsenb/hdr/stack/mac/sched_harq.h" + +namespace srsenb { + +void sched_dl_pf::set_params(const sched_cell_params_t& cell_params_) +{ + cc_cfg = &cell_params_; + log_h = srslte::logmap::get("MAC"); +} + +void sched_dl_pf::sched_users(std::map& ue_db, dl_sf_sched_itf* tti_sched) +{ + if (ue_db.empty()) { + return; + } + // remove deleted users from history + for (auto it = ue_history_db.begin(); it != ue_history_db.end();) { + if (not ue_db.count(it->first)) { + it = ue_history_db.erase(it); + } else { + ++it; + } + } + // add new users to history db, and update priority queue + for (auto& u : ue_db) { + auto it = ue_history_db.find(u.first); + if (it == ue_history_db.end()) { + it = ue_history_db.insert(std::make_pair(u.first, ue_ctxt{u.first})).first; + } + it->second.new_tti(*cc_cfg, u.second, tti_sched); + ue_queue.push(&it->second); + } + + while (not ue_queue.empty()) { + ue_ctxt& ue = *ue_queue.top(); + bool alloc_success = try_dl_alloc(ue, ue_db[ue.rnti], tti_sched); + ue.save_history(alloc_success, 0.01); + ue_queue.pop(); + } +} + +void sched_dl_pf::ue_ctxt::new_tti(const sched_cell_params_t& cell, sched_ue& ue, dl_sf_sched_itf* tti_sched) +{ + h = nullptr; + prio = 0; + is_retx = false; + + auto p = ue.get_active_cell_index(cell.enb_cc_idx); + if (not p.first) { + return; + } + if (not ue.pdsch_enabled(srslte::tti_point(tti_sched->get_tti_tx_dl() - TX_ENB_DELAY), cell.enb_cc_idx)) { + return; + } + ue_cc_idx = p.second; + + // search for DL HARQ + h = ue.get_pending_dl_harq(tti_sched->get_tti_tx_dl(), ue_cc_idx); + is_retx = h != nullptr; + if (h == nullptr) { + h = ue.get_empty_dl_harq(tti_sched->get_tti_tx_dl(), ue_cc_idx); + if (h == nullptr) { + return; + } + } + + // calculate PF priority + float r = ue.get_expected_dl_bitrate(ue_cc_idx) / 8; + float R = avg_rate(); + prio = (R != 0) ? r / R : (r == 0 ? 0 : std::numeric_limits::max()); +} + +void sched_dl_pf::ue_ctxt::save_history(bool alloc, float alpha) +{ + float sample = alloc ? (h->get_tbs(0) + h->get_tbs(1)) : 0; + if (nof_samples < 1 / alpha) { + // fast start + rate = rate + (sample - rate) / (nof_samples + 1); + } else { + rate = (1 - alpha) * rate + (alpha)*sample; + } + nof_samples++; +} + +bool find_allocation(uint32_t min_nof_rbg, uint32_t max_nof_rbg, rbgmask_t* rbgmask, dl_sf_sched_itf* tti_alloc) +{ + if (tti_alloc->get_dl_mask().all()) { + return false; + } + // 1's for free rbgs + rbgmask_t localmask = ~(tti_alloc->get_dl_mask()); + + uint32_t i = 0, nof_alloc = 0; + for (; i < localmask.size() and nof_alloc < max_nof_rbg; ++i) { + if (localmask.test(i)) { + nof_alloc++; + } + } + if (nof_alloc < min_nof_rbg) { + return false; + } + localmask.fill(i, localmask.size(), false); + *rbgmask = localmask; + return true; +} + +bool sched_dl_pf::try_dl_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, dl_sf_sched_itf* tti_sched) +{ + if (tti_sched->is_dl_alloc(ue_ctxt.rnti) or ue_ctxt.prio == 0) { + return false; + } + alloc_outcome_t code; + if (ue_ctxt.is_retx) { + // Try to reuse the same mask + rbgmask_t retx_mask = ue_ctxt.h->get_rbgmask(); + code = tti_sched->alloc_dl_user(&ue, retx_mask, ue_ctxt.h->get_id()); + if (code == alloc_outcome_t::SUCCESS) { + return true; + } + if (code == alloc_outcome_t::DCI_COLLISION) { + // No DCIs available for this user. Move to next + log_h->info("SCHED: Couldn't find space in PDCCH for DL retx for rnti=0x%x\n", ue_ctxt.rnti); + return false; + } + + // If previous mask does not fit, find another with exact same number of rbgs + size_t nof_rbg = retx_mask.count(); + if (find_allocation(nof_rbg, nof_rbg, &retx_mask, tti_sched)) { + code = tti_sched->alloc_dl_user(&ue, retx_mask, ue_ctxt.h->get_id()); + if (code == alloc_outcome_t::SUCCESS) { + return true; + } + if (code == alloc_outcome_t::DCI_COLLISION) { + log_h->info("SCHED: Couldn't find space in PDCCH for DL retx for rnti=0x%x\n", ue.get_rnti()); + return false; + } + } + } else { + // Allocate resources based on pending data + rbg_interval req_rbgs = ue.get_required_dl_rbgs(ue_ctxt.ue_cc_idx); + if (req_rbgs.stop() > 0) { + rbgmask_t newtx_mask(tti_sched->get_dl_mask().size()); + if (find_allocation(req_rbgs.start(), req_rbgs.stop(), &newtx_mask, tti_sched)) { + // some empty spaces were found + code = tti_sched->alloc_dl_user(&ue, newtx_mask, ue_ctxt.h->get_id()); + if (code == alloc_outcome_t::SUCCESS) { + return true; + } else if (code == alloc_outcome_t::DCI_COLLISION) { + log_h->info("SCHED: Couldn't find space in PDCCH for DL tx for rnti=0x%x\n", ue_ctxt.rnti); + } + } + } + } + return false; +} + +bool sched_dl_pf::ue_prio_compare::operator()(const sched_dl_pf::ue_ctxt* lhs, const sched_dl_pf::ue_ctxt* rhs) const +{ + return (not lhs->is_retx and rhs->is_retx) or (lhs->is_retx == rhs->is_retx and lhs->prio < rhs->prio); +} + +/***************************************************************** + * + * Uplink Metric + * + *****************************************************************/ + +void sched_ul_pf::set_params(const sched_cell_params_t& cell_params_) +{ + cc_cfg = &cell_params_; + log_h = srslte::logmap::get("MAC"); +} + +void sched_ul_pf::sched_users(std::map& ue_db, ul_sf_sched_itf* tti_sched) +{ + if (ue_db.empty()) { + return; + } + // remove deleted users from history + for (auto it = ue_history_db.begin(); it != ue_history_db.end();) { + if (not ue_db.count(it->first)) { + it = ue_history_db.erase(it); + } else { + ++it; + } + } + // add new users to history db, and update priority queue + for (auto& u : ue_db) { + auto it = ue_history_db.find(u.first); + if (it == ue_history_db.end()) { + it = ue_history_db.insert(std::make_pair(u.first, ue_ctxt{u.first})).first; + } + it->second.new_tti(*cc_cfg, u.second, tti_sched); + ue_queue.push(&it->second); + } + while (not ue_queue.empty()) { + ue_ctxt& ue = *ue_queue.top(); + bool alloc_success = try_ul_alloc(ue, ue_db[ue.rnti], tti_sched); + ue.save_history(alloc_success, 0.01); + ue_queue.pop(); + } +} + +/** + * Finds a range of L contiguous PRBs that are empty + * @param L Size of the requested UL allocation in PRBs + * @param alloc Found allocation. It is guaranteed that 0 <= alloc->L <= L + * @return true if the requested allocation of size L was strictly met + */ +bool find_allocation(uint32_t L, prb_interval* alloc, ul_sf_sched_itf* tti_sched) +{ + const prbmask_t* used_rb = &tti_sched->get_ul_mask(); + *alloc = {}; + for (uint32_t n = 0; n < used_rb->size() && alloc->length() < L; n++) { + if (not used_rb->test(n) && alloc->length() == 0) { + alloc->displace_to(n); + } + if (not used_rb->test(n)) { + alloc->resize_by(1); + } else if (alloc->length() > 0) { + // avoid edges + if (n < 3) { + *alloc = {}; + } else { + break; + } + } + } + if (alloc->length() == 0) { + return false; + } + + // Make sure L is allowed by SC-FDMA modulation + while (!srslte_dft_precoding_valid_prb(alloc->length())) { + alloc->resize_by(-1); + } + return alloc->length() == L; +} + +bool sched_ul_pf::try_ul_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, ul_sf_sched_itf* tti_sched) +{ + if (ue_ctxt.h == nullptr or tti_sched->is_ul_alloc(ue_ctxt.rnti) or ue_ctxt.prio == 0) { + return false; + } + srslte::tti_point tti_rx{tti_sched->get_tti_tx_ul() - (TX_ENB_DELAY + FDD_HARQ_DELAY_DL_MS)}; + + alloc_outcome_t ret; + if (ue_ctxt.h->has_pending_retx()) { + prb_interval alloc = ue_ctxt.h->get_alloc(); + + // If can schedule the same mask, do it + ret = tti_sched->alloc_ul_user(&ue, alloc); + if (ret == alloc_outcome_t::SUCCESS) { + return true; + } + if (ret == alloc_outcome_t::DCI_COLLISION) { + log_h->info("SCHED: Couldn't find space in PDCCH for UL retx of rnti=0x%x\n", ue.get_rnti()); + return false; + } + + // Avoid measGaps accounting for PDCCH + if (not ue.pusch_enabled(tti_rx, cc_cfg->enb_cc_idx, true)) { + return false; + } + if (find_allocation(alloc.length(), &alloc, tti_sched)) { + ret = tti_sched->alloc_ul_user(&ue, alloc); + if (ret == alloc_outcome_t::SUCCESS) { + return true; + } + if (ret == alloc_outcome_t::DCI_COLLISION) { + log_h->info("SCHED: Couldn't find space in PDCCH for UL retx of rnti=0x%x\n", ue.get_rnti()); + } + } + } else { + // Avoid measGaps accounting for PDCCH + if (not ue.pusch_enabled(tti_rx, cc_cfg->enb_cc_idx, true)) { + return false; + } + + uint32_t pending_data = ue.get_pending_ul_new_data(tti_sched->get_tti_tx_ul(), ue_ctxt.ue_cc_idx); + // find an empty PID + if (ue_ctxt.h->is_empty(0) and pending_data > 0) { + uint32_t pending_rb = ue.get_required_prb_ul(ue_ctxt.ue_cc_idx, pending_data); + prb_interval alloc{}; + + find_allocation(pending_rb, &alloc, tti_sched); + if (alloc.length() > 0) { // at least one PRB was scheduled + ret = tti_sched->alloc_ul_user(&ue, alloc); + if (ret == alloc_outcome_t::SUCCESS) { + return true; + } + if (ret == alloc_outcome_t::DCI_COLLISION) { + log_h->info("SCHED: Couldn't find space in PDCCH for UL tx of rnti=0x%x\n", ue.get_rnti()); + } + } + } + } + return false; +} + +void sched_ul_pf::ue_ctxt::new_tti(const sched_cell_params_t& cell, sched_ue& ue, ul_sf_sched_itf* tti_sched) +{ + srslte::tti_point tti_rx = srslte::tti_point(tti_sched->get_tti_tx_ul() - TX_ENB_DELAY - FDD_HARQ_DELAY_DL_MS); + h = nullptr; + prio = 0; + + auto p = ue.get_active_cell_index(cell.enb_cc_idx); + if (not p.first) { + return; + } + if (not ue.pusch_enabled(tti_rx, cell.enb_cc_idx, false)) { + return; + } + ue_cc_idx = p.second; + h = ue.get_ul_harq(tti_sched->get_tti_tx_ul(), ue_cc_idx); + + // calculate PF priority + float r = ue.get_expected_ul_bitrate(ue_cc_idx) / 8; + float R = avg_rate(); + prio = (R != 0) ? r / R : (r == 0 ? 0 : std::numeric_limits::max()); +} + +void sched_ul_pf::ue_ctxt::save_history(bool alloc, float alpha) +{ + float sample = alloc ? h->get_pending_data() : 0; + if (nof_samples < 1 / alpha) { + // fast start + rate = rate + (sample - rate) / (nof_samples + 1); + } else { + rate = (1 - alpha) * rate + (alpha)*sample; + } + nof_samples++; +} + +bool sched_ul_pf::ue_prio_compare::operator()(const sched_ul_pf::ue_ctxt* lhs, const sched_ul_pf::ue_ctxt* rhs) const +{ + bool is_retx1 = lhs->h != nullptr and lhs->h->has_pending_retx(), + is_retx2 = rhs->h != nullptr and rhs->h->has_pending_retx(); + return (not is_retx1 and is_retx2) or (is_retx1 == is_retx2 and lhs->prio < rhs->prio); +} + +} // namespace srsenb diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index 54425a148..f7717cbd7 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -1035,6 +1035,34 @@ uint32_t sched_ue::get_pending_dl_rlc_data() const return pending_data; } +uint32_t sched_ue::get_expected_dl_bitrate(uint32_t ue_cc_idx) const +{ + const cc_sched_ue* cc = &carriers[ue_cc_idx]; + + auto* cell_cfg = carriers[ue_cc_idx].get_cell_cfg(); + uint32_t nof_re = + srslte_ra_dl_approx_nof_re(&cell_cfg->cfg.cell, cell_cfg->nof_prb(), cell_cfg->sched_cfg->max_nof_ctrl_symbols); + float max_coderate = srslte_cqi_to_coderate(std::min(cc->dl_cqi + 1u, 15u), cfg.use_tbs_index_alt); + + // Inverse of srslte_coderate(tbs, nof_re) + uint32_t tbs = max_coderate * nof_re - 24; + return tbs / tti_duration_ms; +} + +uint32_t sched_ue::get_expected_ul_bitrate(uint32_t ue_cc_idx) const +{ + const cc_sched_ue* cc = &carriers[ue_cc_idx]; + + uint32_t N_srs = 0; + uint32_t nof_symb = 2 * (SRSLTE_CP_NSYMB(cell.cp) - 1) - N_srs; + uint32_t nof_re = nof_symb * cell.nof_prb * SRSLTE_NRE; + float max_coderate = srslte_cqi_to_coderate(std::min(cc->ul_cqi + 1u, 15u), false); + + // Inverse of srslte_coderate(tbs, nof_re) + uint32_t tbs = max_coderate * nof_re - 24; + return tbs / tti_duration_ms; +} + /// Returns nof bytes allocated to active UL HARQs in the carrier cc_idx. /// NOTE: The returned value accounts for the MAC header and payload (RLC headers and actual data) uint32_t sched_ue::get_pending_ul_old_data(uint32_t ue_cc_idx) @@ -1249,7 +1277,7 @@ int sched_ue::enb_to_ue_cc_idx(uint32_t enb_cc_idx) const return it != carriers.end() ? std::distance(carriers.begin(), it) : -1; } -int cc_sched_ue::cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool use_tbs_index_alt, bool is_ul, uint32_t* mcs) +int cc_sched_ue::cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool is_ul, uint32_t* mcs) { using ul64qam_cap = sched_interface::ue_cfg_t::ul64qam_cap; uint32_t max_Qm; @@ -1261,17 +1289,17 @@ int cc_sched_ue::cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool use_tbs_inde max_coderate = srslte_cqi_to_coderate(std::min(ul_cqi + 1u, 15u), false); } else { max_mcs = max_mcs_dl; - max_Qm = use_tbs_index_alt ? 8 : 6; - max_coderate = srslte_cqi_to_coderate(std::min(dl_cqi + 1u, 15u), use_tbs_index_alt); + max_Qm = cfg->use_tbs_index_alt ? 8 : 6; + max_coderate = srslte_cqi_to_coderate(std::min(dl_cqi + 1u, 15u), cfg->use_tbs_index_alt); } // function with sign-flip at solution auto compute_tbs = [&](int sel_mcs) -> float { - uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(sel_mcs, use_tbs_index_alt, is_ul); + uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(sel_mcs, cfg->use_tbs_index_alt, is_ul); int tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb); float coderate = srslte_coderate(tbs, nof_re); srslte_mod_t mod = - (is_ul) ? srslte_ra_ul_mod_from_mcs(sel_mcs) : srslte_ra_dl_mod_from_mcs(sel_mcs, use_tbs_index_alt); + (is_ul) ? srslte_ra_ul_mod_from_mcs(sel_mcs) : srslte_ra_dl_mod_from_mcs(sel_mcs, cfg->use_tbs_index_alt); uint32_t Qm = std::min(max_Qm, srslte_mod_bits_x_symbol(mod)); return coderate - std::min(max_coderate, 0.930f * Qm); }; @@ -1288,7 +1316,7 @@ int cc_sched_ue::cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool use_tbs_inde } } int chosen_mcs = std::get<0>(ret); - uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(chosen_mcs, use_tbs_index_alt, is_ul); + uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(chosen_mcs, cfg->use_tbs_index_alt, is_ul); int chosen_tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb); if (mcs != nullptr) { @@ -1441,7 +1469,7 @@ int cc_sched_ue::alloc_tbs(uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes uint32_t sel_mcs = 0; // TODO: Compute real spectral efficiency based on PUSCH-UCI configuration - int tbs_bytes = cqi_to_tbs(nof_prb, nof_re, cfg->use_tbs_index_alt, is_ul, &sel_mcs) / 8; + int tbs_bytes = cqi_to_tbs(nof_prb, nof_re, is_ul, &sel_mcs) / 8; /* If less bytes are requested, lower the MCS */ if (tbs_bytes > (int)req_bytes && req_bytes > 0) {