Optimization of sched_ue methods to derive required number of prbs to allocate to a rnti

This optimization has been achieved by:
- implementation of "false position method" root-finding algorithm
- application of the false position method in cc_sched_ue::get_required_prb_dl/ul(...)

The number of iterations in the worst case scenario, reduced from 100 to 5 with
the proposed algorithm.
master
Francisco 4 years ago committed by Andre Puschmann
parent 2dc3fce9bd
commit 94efeab672

@ -89,6 +89,65 @@ bool operator==(const sched_interface::ue_cfg_t::cc_cfg_t& lhs, const sched_inte
return lhs.enb_cc_idx == rhs.enb_cc_idx and lhs.active == rhs.active; return lhs.enb_cc_idx == rhs.enb_cc_idx and lhs.active == rhs.active;
} }
template <typename YType, typename Callable, typename ErrorDetect>
std::tuple<int, YType, int, YType> false_position_method(int x1, int x2, YType y0, const Callable& f)
{
return false_position_method(x1, x2, y0, f, []() { return false; });
}
template <typename YType, typename Callable, typename ErrorDetect>
std::tuple<int, YType, int, YType>
false_position_method(int x1, int x2, YType y0, const Callable& f, const ErrorDetect& is_error)
{
static_assert(std::is_same<YType, decltype(f(x1))>::value,
"The type of the final result and callable return do not match\n");
YType y1 = f(x1);
if (is_error(y1) or y1 >= y0) {
return {x1, y1, x1, y1};
}
YType y2 = f(x2);
if (is_error(y2) or y2 <= y0) {
return {x2, y2, x2, y2};
}
YType y3;
while (x2 > x1 + 1) {
int x3 = round(x1 - ((x2 - x1) * (y1 - y0) / (float)(y2 - y1)));
if (x3 == x2) {
y3 = y2;
// check if in frontier
YType y3_1 = f(x3 - 1);
if (not is_error(y3_1) and y3_1 < y0) {
return {x3 - 1, y3_1, x3, y3};
} else {
x3--;
y3 = y3_1;
}
} else if (x3 == x1) {
y3 = y1;
// check if in frontier
YType y3_1 = f(x3 + 1);
if (not is_error(y3_1) and y3_1 >= y0) {
return {x3, y3, x3 + 1, y3_1};
} else {
x3++;
y3 = y3_1;
}
} else {
y3 = f(x3);
if (is_error(y3) or y3 == y0) {
return {x3, y3, x3, y3};
}
}
if (y3 < y0) {
x1 = x3;
y1 = y3;
} else {
x2 = x3;
y2 = y3;
}
}
return {x1, y1, x2, y2};
}
/******************************************************* /*******************************************************
* *
* Initialization and configuration functions * Initialization and configuration functions
@ -1425,68 +1484,46 @@ int cc_sched_ue::alloc_tbs_ul(uint32_t nof_prb, uint32_t nof_re, uint32_t req_by
int cc_sched_ue::get_required_prb_dl(uint32_t req_bytes, uint32_t nof_ctrl_symbols) int cc_sched_ue::get_required_prb_dl(uint32_t req_bytes, uint32_t nof_ctrl_symbols)
{ {
int mcs = 0; auto compute_tbs_approx = [this, nof_ctrl_symbols](uint32_t nof_prb) {
uint32_t nof_re = 0; uint32_t nof_re = srslte_ra_dl_approx_nof_re(&cell_params->cfg.cell, nof_prb, nof_ctrl_symbols);
int tbs = 0; int mcs, tbs;
uint32_t nbytes = 0;
uint32_t n;
for (n = 0; n < cell_params->nof_prb() and nbytes < req_bytes; ++n) {
nof_re = srslte_ra_dl_approx_nof_re(&cell_params->cfg.cell, n + 1, nof_ctrl_symbols);
if (fixed_mcs_dl < 0 or not dl_cqi_rx) { if (fixed_mcs_dl < 0 or not dl_cqi_rx) {
tbs = alloc_tbs_dl(n + 1, nof_re, 0, &mcs); return alloc_tbs_dl(nof_prb, nof_re, 0, &mcs);
} else {
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl, cfg->use_tbs_index_alt, false), n + 1) / 8;
} }
if (tbs > 0) { return srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl, cfg->use_tbs_index_alt, false), nof_prb) / 8;
nbytes = tbs; };
} else if (tbs < 0) {
return 0;
}
}
return (nbytes >= req_bytes) ? n : -1; std::tuple<uint32_t, int, uint32_t, int> ret = false_position_method(
1u, cell_params->nof_prb(), (int)req_bytes, compute_tbs_approx, [](int y) { return y == SRSLTE_ERROR; });
int upper_tbs = std::get<3>(ret);
uint32_t upper_nprb = std::get<2>(ret);
return (upper_tbs < 0) ? 0 : ((upper_tbs < (int)req_bytes) ? -1 : upper_nprb);
} }
uint32_t cc_sched_ue::get_required_prb_ul(uint32_t req_bytes) uint32_t cc_sched_ue::get_required_prb_ul(uint32_t req_bytes)
{ {
int mcs = 0;
uint32_t nbytes = 0;
uint32_t N_srs = 0;
uint32_t n = 0;
if (req_bytes == 0) { if (req_bytes == 0) {
return 0; return 0;
} }
auto compute_tbs_approx = [this](uint32_t nof_prb) {
uint32_t last_valid_n = 0; const uint32_t N_srs = 0;
for (n = 1; n < cell_params->nof_prb() && nbytes < req_bytes + 4; n++) { uint32_t nof_re = (2 * (SRSLTE_CP_NSYMB(cell_params->cfg.cell.cp) - 1) - N_srs) * nof_prb * SRSLTE_NRE;
uint32_t nof_re = (2 * (SRSLTE_CP_NSYMB(cell_params->cfg.cell.cp) - 1) - N_srs) * n * SRSLTE_NRE; int mcs, tbs;
int tbs = 0;
if (fixed_mcs_ul < 0) { if (fixed_mcs_ul < 0) {
tbs = alloc_tbs_ul(n, nof_re, 0, &mcs); return alloc_tbs_ul(nof_prb, nof_re, 0, &mcs);
} else {
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_ul, false, true), n) / 8;
}
if (tbs > 0) {
nbytes = tbs;
last_valid_n = n;
} }
} return srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_ul, false, true), nof_prb) / 8;
};
if (last_valid_n > 0) {
if (n != last_valid_n) { // find nof prbs that lead to a tbs just above req_bytes
n = last_valid_n; int target_tbs = req_bytes + 4;
} std::tuple<uint32_t, int, uint32_t, int> ret = false_position_method(
while (!srslte_dft_precoding_valid_prb(n) && n <= cell_params->nof_prb()) { 1u, cell_params->nof_prb(), target_tbs, compute_tbs_approx, [](int y) { return y == SRSLTE_ERROR; });
n++; uint32_t req_prbs = std::get<2>(ret);
} while (!srslte_dft_precoding_valid_prb(req_prbs) && req_prbs < cell_params->nof_prb()) {
return n; req_prbs++;
} else { }
// This should never happen. Just in case, return 0 PRB and handle it later return req_prbs;
log_h->error("SCHED: Could not obtain any valid number of PRB for an uplink allocation\n");
return 0;
}
} }
void cc_sched_ue::set_dl_cqi(uint32_t tti_tx_dl, uint32_t dl_cqi_) void cc_sched_ue::set_dl_cqi(uint32_t tti_tx_dl, uint32_t dl_cqi_)

Loading…
Cancel
Save