mirror of https://github.com/PentHertz/srsLTE.git
Implementation of time-domain PF scheduler
- PF scheduling becomes the new default
This commit is contained in:
parent
07d2bc4fe8
commit
d7fae0b7a3
|
@ -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 <queue>
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
class sched_dl_pf : public sched::metric_dl
|
||||
{
|
||||
using ue_cit_t = std::map<uint16_t, sched_ue>::const_iterator;
|
||||
|
||||
public:
|
||||
void set_params(const sched_cell_params_t& cell_params_) final;
|
||||
void sched_users(std::map<uint16_t, sched_ue>& 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<uint16_t, ue_ctxt> ue_history_db;
|
||||
struct ue_prio_compare {
|
||||
bool operator()(const ue_ctxt* lhs, const ue_ctxt* rhs) const;
|
||||
};
|
||||
std::priority_queue<ue_ctxt*, std::vector<ue_ctxt*>, 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<uint16_t, sched_ue>::const_iterator;
|
||||
|
||||
public:
|
||||
void set_params(const sched_cell_params_t& cell_params_) final;
|
||||
void sched_users(std::map<uint16_t, sched_ue>& 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<uint16_t, ue_ctxt> ue_history_db;
|
||||
struct ue_prio_compare {
|
||||
bool operator()(const ue_ctxt* lhs, const ue_ctxt* rhs) const;
|
||||
};
|
||||
std::priority_queue<ue_ctxt*, std::vector<ue_ctxt*>, 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
|
|
@ -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<uint32_t> 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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<uint16_t, sched_ue>& 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<float>::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<uint16_t, sched_ue>& 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<float>::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
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue