Commit 86398f6d authored by Robert Schmidt's avatar Robert Schmidt

Add Maximum Throughput scheduler, wbCqi

Selects the UE with the highest CQI. If two UEs have the same CQI,
choses the one with highest number of bytes in RLC queue. Allocates as
many RBGs as possible, and potentially continues with the next UE.
parent 8b46538b
......@@ -401,6 +401,156 @@ default_sched_dl_algo_t proportional_fair_wbcqi_dl = {
.data = NULL
};
void *mt_dl_setup(void) {
return NULL;
}
void mt_dl_unset(void **data) {
*data = NULL;
}
int mt_wbcqi_dl_run(module_id_t Mod_id,
int CC_id,
int frame,
int subframe,
UE_list_t *UE_list,
int max_num_ue,
int n_rbg_sched,
uint8_t *rbgalloc_mask,
void *data) {
DevAssert(UE_list->head >= 0);
DevAssert(n_rbg_sched > 0);
const int N_RBG = to_rbg(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth);
const int RBGsize = get_min_rb_unit(Mod_id, CC_id);
const int RBGlastsize = get_rbg_size_last(Mod_id, CC_id);
UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info;
int rbg = 0;
for (; !rbgalloc_mask[rbg]; rbg++)
; /* fast-forward to first allowed RBG */
UE_list_t UE_sched; // UEs that could be scheduled
int *uep = &UE_sched.head;
for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
// check whether there are HARQ retransmissions
const COMMON_channels_t *cc = &RC.mac[Mod_id]->common_channels[CC_id];
const uint8_t harq_pid = frame_subframe2_dl_harq_pid(cc->tdd_Config, frame, subframe);
UE_sched_ctrl_t *ue_ctrl = &UE_info->UE_sched_ctrl[UE_id];
const uint8_t round = ue_ctrl->round[CC_id][harq_pid];
if (round != 8) { // retransmission: allocate
const int nb_rb = UE_info->UE_template[CC_id][UE_id].nb_rb[harq_pid];
if (nb_rb == 0)
continue;
int nb_rbg = (nb_rb + (nb_rb % RBGsize)) / RBGsize;
// needs more RBGs than we can allocate
if (nb_rbg > n_rbg_sched) {
LOG_D(MAC,
"retransmission of UE %d needs more RBGs (%d) than we have (%d)\n",
UE_id, nb_rbg, n_rbg_sched);
continue;
}
// ensure that the number of RBs can be contained by the RBGs (!), i.e.
// if we allocate the last RBG this one should have the full RBGsize
if ((nb_rb % RBGsize) == 0 && nb_rbg == n_rbg_sched
&& rbgalloc_mask[N_RBG - 1] && RBGlastsize != RBGsize) {
LOG_D(MAC,
"retransmission of UE %d needs %d RBs, but the last RBG %d is too small (%d, normal %d)\n",
UE_id, nb_rb, N_RBG - 1, RBGlastsize, RBGsize);
continue;
}
const uint8_t cqi = ue_ctrl->dl_cqi[CC_id];
const int idx = CCE_try_allocate_dlsch(Mod_id, CC_id, subframe, UE_id, cqi);
if (idx < 0)
continue; // cannot allocate CCE
ue_ctrl->pre_dci_dl_pdu_idx = idx;
// retransmissions: directly allocate
n_rbg_sched -= nb_rbg;
ue_ctrl->pre_nb_available_rbs[CC_id] += nb_rb;
for (; nb_rbg > 0; rbg++) {
if (!rbgalloc_mask[rbg])
continue;
ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1;
rbgalloc_mask[rbg] = 0;
nb_rbg--;
}
LOG_D(MAC,
"%4d.%d n_rbg_sched %d after retransmission reservation for UE %d "
"round %d retx nb_rb %d pre_nb_available_rbs %d\n",
frame, subframe, n_rbg_sched, UE_id, round,
UE_info->UE_template[CC_id][UE_id].nb_rb[harq_pid],
ue_ctrl->pre_nb_available_rbs[CC_id]);
/* if there are no more RBG to give, return */
if (n_rbg_sched <= 0)
return 0;
max_num_ue--;
/* if there are no UEs that can be allocated anymore, return */
if (max_num_ue == 0)
return n_rbg_sched;
for (; !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ;
} else {
if (UE_info->UE_template[CC_id][UE_id].dl_buffer_total == 0)
continue;
*uep = UE_id;
uep = &UE_sched.next[UE_id];
}
}
*uep = -1;
while (max_num_ue > 0 && n_rbg_sched > 0 && UE_sched.head >= 0) {
int *max = &UE_sched.head; /* assume head is max */
int *p = &UE_sched.next[*max];
while (*p >= 0) {
/* if the current one has better CQI, or the same and more data */
const uint8_t maxCqi = UE_info->UE_sched_ctrl[*max].dl_cqi[CC_id];
const uint32_t maxB = UE_info->UE_template[CC_id][*max].dl_buffer_total;
const uint8_t pCqi = UE_info->UE_sched_ctrl[*p].dl_cqi[CC_id];
const uint32_t pB = UE_info->UE_template[CC_id][*p].dl_buffer_total;
if (pCqi > maxCqi || (pCqi == maxCqi && pB > maxB))
max = p;
p = &UE_sched.next[*p];
}
/* remove the max one */
const int UE_id = *max;
p = &UE_sched.next[*max];
*max = UE_sched.next[*max];
*p = -1;
const uint8_t cqi = UE_info->UE_sched_ctrl[UE_id].dl_cqi[CC_id];
const int idx = CCE_try_allocate_dlsch(Mod_id, CC_id, subframe, UE_id, cqi);
if (idx < 0)
continue;
UE_info->UE_sched_ctrl[UE_id].pre_dci_dl_pdu_idx = idx;
max_num_ue--;
/* allocate as much as possible */
const int mcs = cqi_to_mcs[cqi];
UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = mcs;
int req = find_nb_rb_DL(mcs,
UE_info->UE_template[CC_id][UE_id].dl_buffer_total,
n_rbg_sched * RBGsize,
RBGsize);
UE_sched_ctrl_t *ue_ctrl = &UE_info->UE_sched_ctrl[UE_id];
while (req > 0 && n_rbg_sched > 0) {
ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1;
rbgalloc_mask[rbg] = 0;
const int sRBG = rbg == N_RBG - 1 ? RBGlastsize : RBGsize;
ue_ctrl->pre_nb_available_rbs[CC_id] += sRBG;
req -= sRBG;
n_rbg_sched--;
for (rbg++; n_rbg_sched > 0 && !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ;
}
}
return n_rbg_sched;
}
default_sched_dl_algo_t maximum_throughput_wbcqi_dl = {
.name = "maximum_throughput_wbcqi_dl",
.setup = mt_dl_setup,
.unset = mt_dl_unset,
.run = mt_wbcqi_dl_run,
.data = NULL
};
// This function stores the downlink buffer for all the logical channels
void
store_dlsch_buffer(module_id_t Mod_id,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment