lte,enb,rlc: compute and forward to scheduler the number of bytes pending for retx and status pdu in RLC AM bearer

master
Francisco 3 years ago committed by Francisco Paisana
parent b14e75218d
commit 4a58c10f30

@ -375,6 +375,7 @@ private:
bool has_data(); bool has_data();
uint32_t get_buffer_state(); uint32_t get_buffer_state();
void get_buffer_state(uint32_t& new_tx, uint32_t& prio_tx);
// Timeout callback interface // Timeout callback interface
void timer_expired(uint32_t timeout_id); void timer_expired(uint32_t timeout_id);

@ -436,10 +436,19 @@ void rlc_am_lte::rlc_am_lte_tx::check_sn_reached_max_retx(uint32_t sn)
uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state() uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state()
{ {
std::lock_guard<std::mutex> lock(mutex); uint32_t newtx = 0, priotx = 0;
uint32_t n_bytes = 0; get_buffer_state(newtx, priotx);
return newtx + priotx;
}
void rlc_am_lte::rlc_am_lte_tx::get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio)
{
n_bytes_newtx = 0;
n_bytes_prio = 0;
uint32_t n_sdus = 0; uint32_t n_sdus = 0;
std::lock_guard<std::mutex> lock(mutex);
logger.debug("%s Buffer state - do_status=%s, status_prohibit_running=%s (%d/%d)", logger.debug("%s Buffer state - do_status=%s, status_prohibit_running=%s (%d/%d)",
RB_NAME, RB_NAME,
do_status() ? "yes" : "no", do_status() ? "yes" : "no",
@ -449,8 +458,8 @@ uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state()
// Bytes needed for status report // Bytes needed for status report
if (do_status() && not status_prohibit_timer.is_running()) { if (do_status() && not status_prohibit_timer.is_running()) {
n_bytes += parent->rx.get_status_pdu_length(); n_bytes_prio += parent->rx.get_status_pdu_length();
logger.debug("%s Buffer state - total status report: %d bytes", RB_NAME, n_bytes); logger.debug("%s Buffer state - total status report: %d bytes", RB_NAME, n_bytes_prio);
} }
// Bytes needed for retx // Bytes needed for retx
@ -468,8 +477,8 @@ uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state()
logger.error("In get_buffer_state(): Removing retx.sn=%d from queue", retx.sn); logger.error("In get_buffer_state(): Removing retx.sn=%d from queue", retx.sn);
retx_queue.pop(); retx_queue.pop();
} else { } else {
n_bytes += req_bytes; n_bytes_prio += req_bytes;
logger.debug("Buffer state - retx: %d bytes", n_bytes); logger.debug("Buffer state - retx: %d bytes", n_bytes_prio);
} }
} }
} }
@ -477,25 +486,23 @@ uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state()
// Bytes needed for tx SDUs // Bytes needed for tx SDUs
if (tx_window.size() < 1024) { if (tx_window.size() < 1024) {
n_sdus = tx_sdu_queue.get_n_sdus(); n_sdus = tx_sdu_queue.get_n_sdus();
n_bytes += tx_sdu_queue.size_bytes(); n_bytes_newtx += tx_sdu_queue.size_bytes();
if (tx_sdu != NULL) { if (tx_sdu != NULL) {
n_sdus++; n_sdus++;
n_bytes += tx_sdu->N_bytes; n_bytes_newtx += tx_sdu->N_bytes;
} }
} }
// Room needed for header extensions? (integer rounding) // Room needed for header extensions? (integer rounding)
if (n_sdus > 1) { if (n_sdus > 1) {
n_bytes += ((n_sdus - 1) * 1.5) + 0.5; n_bytes_newtx += ((n_sdus - 1) * 1.5) + 0.5;
} }
// Room needed for fixed header of data PDUs // Room needed for fixed header of data PDUs
if (n_bytes > 0 && n_sdus > 0) { if (n_bytes_newtx > 0 && n_sdus > 0) {
n_bytes += 2; // Two bytes for fixed header with SN length = 10 n_bytes_newtx += 2; // Two bytes for fixed header with SN length = 10
logger.debug("%s Total buffer state - %d SDUs (%d B)", RB_NAME, n_sdus, n_bytes); logger.debug("%s Total buffer state - %d SDUs (%d B)", RB_NAME, n_sdus, n_bytes_newtx);
} }
return n_bytes;
} }
int rlc_am_lte::rlc_am_lte_tx::write_sdu(unique_byte_buffer_t sdu) int rlc_am_lte::rlc_am_lte_tx::write_sdu(unique_byte_buffer_t sdu)
@ -613,7 +620,9 @@ void rlc_am_lte::rlc_am_lte_tx::timer_expired(uint32_t timeout_id)
lock.unlock(); lock.unlock();
if (bsr_callback) { if (bsr_callback) {
bsr_callback(parent->lcid, get_buffer_state(), 0); uint32_t newtx = 0, priotx = 0;
get_buffer_state(newtx, priotx);
bsr_callback(parent->lcid, newtx, priotx);
} }
} }

@ -43,7 +43,7 @@ public:
// Buffer Status update // Buffer Status update
void ul_bsr(uint32_t lcg_id, uint32_t val); void ul_bsr(uint32_t lcg_id, uint32_t val);
void dl_buffer_state(uint8_t lcid, uint32_t tx_queue, uint32_t retx_queue); void dl_buffer_state(uint8_t lcid, uint32_t tx_queue, uint32_t prio_tx_queue);
// Configuration getters // Configuration getters
bool is_bearer_active(uint32_t lcid) const { return get_cfg(lcid).is_active(); } bool is_bearer_active(uint32_t lcid) const { return get_cfg(lcid).is_active(); }
@ -58,13 +58,13 @@ public:
/// DL newtx buffer status for given LCID (no RLC overhead included) /// DL newtx buffer status for given LCID (no RLC overhead included)
int get_dl_tx(uint32_t lcid) const { return is_bearer_dl(lcid) ? channels[lcid].buf_tx : 0; } int get_dl_tx(uint32_t lcid) const { return is_bearer_dl(lcid) ? channels[lcid].buf_tx : 0; }
/// DL retx buffer status for given LCID (no RLC overhead included) /// DL high prio tx buffer status for given LCID (no RLC overhead included)
int get_dl_retx(uint32_t lcid) const { return is_bearer_dl(lcid) ? channels[lcid].buf_retx : 0; } int get_dl_prio_tx(uint32_t lcid) const { return is_bearer_dl(lcid) ? channels[lcid].buf_prio_tx : 0; }
/// Sum of DL RLC newtx and retx buffer status for given LCID (no RLC overhead included) /// Sum of DL RLC newtx and high prio tx buffer status for given LCID (no RLC overhead included)
int get_dl_tx_total(uint32_t lcid) const { return get_dl_tx(lcid) + get_dl_retx(lcid); } int get_dl_tx_total(uint32_t lcid) const { return get_dl_tx(lcid) + get_dl_prio_tx(lcid); }
/// Sum of DL RLC newtx and retx buffer status for all LCIDS /// Sum of DL RLC newtx and high prio buffer status for all LCIDS
int get_dl_tx_total() const; int get_dl_tx_total() const;
// UL BSR methods // UL BSR methods
@ -82,7 +82,7 @@ protected:
struct logical_channel { struct logical_channel {
mac_lc_ch_cfg_t cfg; mac_lc_ch_cfg_t cfg;
int buf_tx = 0; int buf_tx = 0;
int buf_retx = 0; int buf_prio_tx = 0;
int Bj = 0; int Bj = 0;
int bucket_size = 0; int bucket_size = 0;
}; };

@ -53,7 +53,7 @@ public:
uint32_t get_ul_buffer(uint16_t rnti) final; uint32_t get_ul_buffer(uint16_t rnti) final;
uint32_t get_dl_buffer(uint16_t rnti) final; uint32_t get_dl_buffer(uint16_t rnti) final;
int dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) final; int dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t prio_tx_queue) final;
int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code, uint32_t nof_cmds = 1) final; int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code, uint32_t nof_cmds = 1) final;
int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) final; int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) final;

@ -267,10 +267,10 @@ public:
* @param rnti user rnti * @param rnti user rnti
* @param lc_id logical channel id for which the buffer update is concerned * @param lc_id logical channel id for which the buffer update is concerned
* @param tx_queue number of pending bytes for new DL RLC transmissions * @param tx_queue number of pending bytes for new DL RLC transmissions
* @param retx_queue number of pending bytes concerning RLC retransmissions * @param prio_tx_queue number of pending bytes concerning RLC retransmissions and status PDUs
* @return error code * @return error code
*/ */
virtual int dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) = 0; virtual int dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t prio_tx_queue) = 0;
/** /**
* Enqueue MAC CEs for DL transmission * Enqueue MAC CEs for DL transmission

@ -35,7 +35,7 @@ public:
using base_type::dl_buffer_state; using base_type::dl_buffer_state;
using base_type::get_bsr; using base_type::get_bsr;
using base_type::get_bsr_state; using base_type::get_bsr_state;
using base_type::get_dl_retx; using base_type::get_dl_prio_tx;
using base_type::get_dl_tx; using base_type::get_dl_tx;
using base_type::get_dl_tx_total; using base_type::get_dl_tx_total;
using base_type::is_bearer_active; using base_type::is_bearer_active;
@ -51,7 +51,7 @@ public:
bool has_pending_dl_txs() const; bool has_pending_dl_txs() const;
int get_dl_tx_total_with_overhead(uint32_t lcid) const; int get_dl_tx_total_with_overhead(uint32_t lcid) const;
int get_dl_tx_with_overhead(uint32_t lcid) const; int get_dl_tx_with_overhead(uint32_t lcid) const;
int get_dl_retx_with_overhead(uint32_t lcid) const; int get_dl_prio_tx_with_overhead(uint32_t lcid) const;
int get_bsr_with_overhead(uint32_t lcid) const; int get_bsr_with_overhead(uint32_t lcid) const;
int get_max_prio_lcid() const; int get_max_prio_lcid() const;
@ -61,7 +61,7 @@ public:
srsran::deque<ce_cmd> pending_ces; srsran::deque<ce_cmd> pending_ces;
private: private:
int alloc_retx_bytes(uint8_t lcid, int rem_bytes); int alloc_prio_tx_bytes(uint8_t lcid, int rem_bytes);
int alloc_tx_bytes(uint8_t lcid, int rem_bytes); int alloc_tx_bytes(uint8_t lcid, int rem_bytes);
size_t prio_idx = 0; size_t prio_idx = 0;

@ -112,19 +112,19 @@ void ue_buffer_manager<isNR>::ul_bsr(uint32_t lcg_id, uint32_t val)
} }
template <bool isNR> template <bool isNR>
void ue_buffer_manager<isNR>::dl_buffer_state(uint8_t lcid, uint32_t tx_queue, uint32_t retx_queue) void 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)) { if (not is_lcid_valid(lcid)) {
logger.warning("The provided lcid=%d is not valid", lcid); logger.warning("The provided lcid=%d is not valid", lcid);
return; return;
} }
if (lcid <= MAX_SRB_LC_ID and if (lcid <= MAX_SRB_LC_ID and
(channels[lcid].buf_tx != (int)tx_queue or channels[lcid].buf_retx != (int)retx_queue)) { (channels[lcid].buf_tx != (int)tx_queue or channels[lcid].buf_prio_tx != (int)prio_tx_queue)) {
logger.info("SCHED: DL lcid=%d buffer_state=%d,%d", lcid, tx_queue, retx_queue); logger.info("SCHED: DL lcid=%d buffer_state=%d,%d", lcid, tx_queue, prio_tx_queue);
} else { } else {
logger.debug("SCHED: DL lcid=%d buffer_state=%d,%d", lcid, tx_queue, retx_queue); logger.debug("SCHED: DL lcid=%d buffer_state=%d,%d", lcid, tx_queue, prio_tx_queue);
} }
channels[lcid].buf_retx = retx_queue; channels[lcid].buf_prio_tx = prio_tx_queue;
channels[lcid].buf_tx = tx_queue; channels[lcid].buf_tx = tx_queue;
} }

@ -165,9 +165,9 @@ uint32_t sched::get_ul_buffer(uint16_t rnti)
return ret; return ret;
} }
int sched::dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue) int sched::dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t prio_tx_queue)
{ {
return ue_db_access_locked(rnti, [&](sched_ue& ue) { ue.dl_buffer_state(lc_id, tx_queue, retx_queue); }); return ue_db_access_locked(rnti, [&](sched_ue& ue) { ue.dl_buffer_state(lc_id, tx_queue, prio_tx_queue); });
} }
int sched::dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code, uint32_t nof_cmds) int sched::dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code, uint32_t nof_cmds)

@ -94,9 +94,9 @@ int lch_ue_manager::get_max_prio_lcid() const
{ {
int min_prio_val = std::numeric_limits<int>::max(), prio_lcid = -1; int min_prio_val = std::numeric_limits<int>::max(), prio_lcid = -1;
// Prioritize retxs // Prioritized Txs first (e.g. Retxs, status PDUs)
for (uint32_t lcid = 0; is_lcid_valid(lcid); ++lcid) { for (uint32_t lcid = 0; is_lcid_valid(lcid); ++lcid) {
if (get_dl_retx(lcid) > 0 and channels[lcid].cfg.priority < min_prio_val) { if (get_dl_prio_tx(lcid) > 0 and channels[lcid].cfg.priority < min_prio_val) {
min_prio_val = channels[lcid].cfg.priority; min_prio_val = channels[lcid].cfg.priority;
prio_lcid = lcid; prio_lcid = lcid;
} }
@ -147,10 +147,10 @@ int lch_ue_manager::alloc_rlc_pdu(sched_interface::dl_sched_pdu_t* rlc_pdu, int
return alloc_bytes; return alloc_bytes;
} }
// try first to allocate retxs // try first to allocate high priority txs (e.g. retxs, status pdus)
alloc_bytes = alloc_retx_bytes(lcid, rem_bytes); alloc_bytes = alloc_prio_tx_bytes(lcid, rem_bytes);
// if no retx alloc, try newtx // if no prio tx alloc, try newtx
if (alloc_bytes == 0) { if (alloc_bytes == 0) {
alloc_bytes = alloc_tx_bytes(lcid, rem_bytes); alloc_bytes = alloc_tx_bytes(lcid, rem_bytes);
} }
@ -168,15 +168,15 @@ int lch_ue_manager::alloc_rlc_pdu(sched_interface::dl_sched_pdu_t* rlc_pdu, int
return alloc_bytes; return alloc_bytes;
} }
int lch_ue_manager::alloc_retx_bytes(uint8_t lcid, int rem_bytes) int lch_ue_manager::alloc_prio_tx_bytes(uint8_t lcid, int rem_bytes)
{ {
const int rlc_overhead = (lcid == 0) ? 0 : RLC_MAX_HEADER_SIZE_NO_LI; const int rlc_overhead = (lcid == 0) ? 0 : RLC_MAX_HEADER_SIZE_NO_LI;
if (rem_bytes <= rlc_overhead) { if (rem_bytes <= rlc_overhead) {
return 0; return 0;
} }
int rem_bytes_no_header = rem_bytes - rlc_overhead; int rem_bytes_no_header = rem_bytes - rlc_overhead;
int alloc = std::min(rem_bytes_no_header, get_dl_retx(lcid)); int alloc = std::min(rem_bytes_no_header, get_dl_prio_tx(lcid));
channels[lcid].buf_retx -= alloc; channels[lcid].buf_prio_tx -= alloc;
return alloc + (alloc > 0 ? rlc_overhead : 0); return alloc + (alloc > 0 ? rlc_overhead : 0);
} }
@ -211,7 +211,7 @@ bool lch_ue_manager::has_pending_dl_txs() const
int lch_ue_manager::get_dl_tx_total_with_overhead(uint32_t lcid) const int lch_ue_manager::get_dl_tx_total_with_overhead(uint32_t lcid) const
{ {
return get_dl_retx_with_overhead(lcid) + get_dl_tx_with_overhead(lcid); return get_dl_prio_tx_with_overhead(lcid) + get_dl_tx_with_overhead(lcid);
} }
int lch_ue_manager::get_dl_tx_with_overhead(uint32_t lcid) const int lch_ue_manager::get_dl_tx_with_overhead(uint32_t lcid) const
@ -219,9 +219,9 @@ int lch_ue_manager::get_dl_tx_with_overhead(uint32_t lcid) const
return get_dl_mac_sdu_size_with_overhead(lcid, get_dl_tx(lcid)); return get_dl_mac_sdu_size_with_overhead(lcid, get_dl_tx(lcid));
} }
int lch_ue_manager::get_dl_retx_with_overhead(uint32_t lcid) const int lch_ue_manager::get_dl_prio_tx_with_overhead(uint32_t lcid) const
{ {
return get_dl_mac_sdu_size_with_overhead(lcid, get_dl_retx(lcid)); return get_dl_mac_sdu_size_with_overhead(lcid, get_dl_prio_tx(lcid));
} }
int lch_ue_manager::get_bsr_with_overhead(uint32_t lcg) const int lch_ue_manager::get_bsr_with_overhead(uint32_t lcg) const

@ -44,7 +44,7 @@ int test_pdu_alloc_successful(srsenb::lch_ue_manager& lch_handler,
int test_retx_until_empty(srsenb::lch_ue_manager& lch_handler, int lcid, uint32_t rlc_payload_size) int test_retx_until_empty(srsenb::lch_ue_manager& lch_handler, int lcid, uint32_t rlc_payload_size)
{ {
int start_rlc_bytes = lch_handler.get_dl_retx(lcid); int start_rlc_bytes = lch_handler.get_dl_prio_tx(lcid);
int nof_pdus = ceil(static_cast<float>(start_rlc_bytes) / static_cast<float>(rlc_payload_size)); int nof_pdus = ceil(static_cast<float>(start_rlc_bytes) / static_cast<float>(rlc_payload_size));
int rem_rlc_bytes = start_rlc_bytes; int rem_rlc_bytes = start_rlc_bytes;
@ -53,7 +53,7 @@ int test_retx_until_empty(srsenb::lch_ue_manager& lch_handler, int lcid, uint32_
uint32_t expected_payload_size = std::min(rlc_payload_size, (uint32_t)rem_rlc_bytes); uint32_t expected_payload_size = std::min(rlc_payload_size, (uint32_t)rem_rlc_bytes);
TESTASSERT(test_pdu_alloc_successful(lch_handler, pdu, lcid, expected_payload_size) == SRSRAN_SUCCESS); TESTASSERT(test_pdu_alloc_successful(lch_handler, pdu, lcid, expected_payload_size) == SRSRAN_SUCCESS);
rem_rlc_bytes -= expected_payload_size; rem_rlc_bytes -= expected_payload_size;
TESTASSERT(lch_handler.get_dl_retx(lcid) == rem_rlc_bytes); TESTASSERT(lch_handler.get_dl_prio_tx(lcid) == rem_rlc_bytes);
} }
return start_rlc_bytes; return start_rlc_bytes;
} }
@ -97,15 +97,15 @@ int test_lc_ch_pbr_infinity()
lch_handler.dl_buffer_state(drb_to_lcid(lte_drb::drb2), 5000, 10000); lch_handler.dl_buffer_state(drb_to_lcid(lte_drb::drb2), 5000, 10000);
// TEST1 - retx of SRB1 is prioritized. Do not transmit other bearers until there are no SRB1 retxs // TEST1 - retx of SRB1 is prioritized. Do not transmit other bearers until there are no SRB1 retxs
int nof_pending_bytes = lch_handler.get_dl_retx(srb_to_lcid(lte_srb::srb1)); int nof_pending_bytes = lch_handler.get_dl_prio_tx(srb_to_lcid(lte_srb::srb1));
TESTASSERT(test_retx_until_empty(lch_handler, srb_to_lcid(lte_srb::srb1), 500) == nof_pending_bytes); TESTASSERT(test_retx_until_empty(lch_handler, srb_to_lcid(lte_srb::srb1), 500) == nof_pending_bytes);
// TEST2 - the DRB2 has lower prio level than SRB1, but has retxs // TEST2 - the DRB2 has lower prio level than SRB1, but has retxs
nof_pending_bytes = lch_handler.get_dl_retx(drb_to_lcid(lte_drb::drb2)); nof_pending_bytes = lch_handler.get_dl_prio_tx(drb_to_lcid(lte_drb::drb2));
TESTASSERT(test_retx_until_empty(lch_handler, drb_to_lcid(lte_drb::drb2), 500) == nof_pending_bytes); TESTASSERT(test_retx_until_empty(lch_handler, drb_to_lcid(lte_drb::drb2), 500) == nof_pending_bytes);
// TEST3 - the DRB1 has lower prio level, but has retxs // TEST3 - the DRB1 has lower prio level, but has retxs
nof_pending_bytes = lch_handler.get_dl_retx(drb_to_lcid(lte_drb::drb1)); nof_pending_bytes = lch_handler.get_dl_prio_tx(drb_to_lcid(lte_drb::drb1));
TESTASSERT(test_retx_until_empty(lch_handler, drb_to_lcid(lte_drb::drb1), 500) == nof_pending_bytes); TESTASSERT(test_retx_until_empty(lch_handler, drb_to_lcid(lte_drb::drb1), 500) == nof_pending_bytes);
// TEST4 - The SRB1 newtx buffer is emptied before other bearers newtxs // TEST4 - The SRB1 newtx buffer is emptied before other bearers newtxs
@ -154,11 +154,11 @@ int test_lc_ch_pbr_finite()
lch_handler.dl_buffer_state(drb_to_lcid(lte_drb::drb2), 50000, 0); lch_handler.dl_buffer_state(drb_to_lcid(lte_drb::drb2), 50000, 0);
// TEST1 - SRB1 retxs are emptied first // TEST1 - SRB1 retxs are emptied first
int nof_pending_bytes = lch_handler.get_dl_retx(srb_to_lcid(lte_srb::srb1)); int nof_pending_bytes = lch_handler.get_dl_prio_tx(srb_to_lcid(lte_srb::srb1));
TESTASSERT(test_retx_until_empty(lch_handler, srb_to_lcid(lte_srb::srb1), 500) == nof_pending_bytes); TESTASSERT(test_retx_until_empty(lch_handler, srb_to_lcid(lte_srb::srb1), 500) == nof_pending_bytes);
// TEST2 - DRB1 retxs are emptied // TEST2 - DRB1 retxs are emptied
nof_pending_bytes = lch_handler.get_dl_retx(drb_to_lcid(lte_drb::drb1)); nof_pending_bytes = lch_handler.get_dl_prio_tx(drb_to_lcid(lte_drb::drb1));
TESTASSERT(test_retx_until_empty(lch_handler, drb_to_lcid(lte_drb::drb1), 500) == nof_pending_bytes); TESTASSERT(test_retx_until_empty(lch_handler, drb_to_lcid(lte_drb::drb1), 500) == nof_pending_bytes);
// TEST3 - SRB1 newtxs are emptied (PBR==infinity) // TEST3 - SRB1 newtxs are emptied (PBR==infinity)

Loading…
Cancel
Save