conversion of RLC AM tx window from std::map to array

This commit is contained in:
Francisco 2021-02-20 19:30:05 +00:00 committed by Francisco Paisana
parent 1660fc81a0
commit f86eb84876
3 changed files with 84 additions and 30 deletions

View File

@ -35,6 +35,9 @@ class circular_array
std::array<T, N> data{};
public:
using iterator = T*;
using const_iterator = const T*;
T& operator[](std::size_t pos) { return data[pos % N]; }
const T& operator[](std::size_t pos) const { return data[pos % N]; }
@ -43,6 +46,8 @@ public:
T* end() { return data.end(); }
const T* end() const { return data.end(); }
size_t size() const { return N; }
};
} // namespace srslte

View File

@ -14,6 +14,7 @@
#define SRSLTE_RLC_AM_LTE_H
#include "srslte/adt/accumulators.h"
#include "srslte/adt/circular_array.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
@ -43,6 +44,7 @@ struct rlc_amd_tx_pdu_t {
rlc_amd_pdu_header_t header;
unique_byte_buffer_t buf;
uint32_t retx_count;
uint32_t rlc_sn;
bool is_acked;
};
@ -66,6 +68,56 @@ struct pdcp_sdu_info_t {
std::vector<rlc_sn_info_t> rlc_sn_info_list; // List of RLC PDUs in transit and whether they have been acked or not.
};
struct tx_window_t {
tx_window_t() { std::fill(active_flag.begin(), active_flag.end(), false); }
void add_pdu(size_t sn)
{
assert(not active_flag[sn]);
window[sn].rlc_sn = sn;
active_flag[sn] = true;
count++;
}
void remove_pdu(size_t sn)
{
assert(active_flag[sn]);
window[sn] = {};
active_flag[sn] = false;
count--;
}
rlc_amd_tx_pdu_t& operator[](size_t sn)
{
assert(has_sn(sn));
return window[sn];
}
size_t size() const { return count; }
bool empty() const { return count == 0; }
void clear()
{
window = {};
std::fill(active_flag.begin(), active_flag.end(), false);
count = 0;
}
bool has_sn(uint32_t sn) const { return active_flag[sn] and window[sn].rlc_sn == sn; }
rlc_amd_tx_pdu_t& front()
{
assert(not empty());
uint32_t min_rlc_sn = std::numeric_limits<uint32_t>::max(), min_idx = std::numeric_limits<uint32_t>::max();
for (uint32_t i = 0; i < window.size(); ++i) {
if (active_flag[i] and window[i].rlc_sn < min_rlc_sn) {
min_idx = i;
min_rlc_sn = window[i].rlc_sn;
}
}
assert(has_sn(min_rlc_sn));
return window[min_idx];
}
private:
size_t count = 0;
srslte::circular_array<bool, 512> active_flag = {};
srslte::circular_array<rlc_amd_tx_pdu_t, 512> window;
};
class rlc_am_lte : public rlc_common
{
public:
@ -196,8 +248,8 @@ private:
bsr_callback_t bsr_callback;
// Tx windows
std::map<uint32_t, rlc_amd_tx_pdu_t> tx_window;
std::deque<rlc_amd_retx_t> retx_queue;
tx_window_t tx_window;
std::deque<rlc_amd_retx_t> retx_queue;
// Mutexes
pthread_mutex_t mutex;

View File

@ -313,7 +313,7 @@ uint32_t rlc_am_lte::rlc_am_lte_tx::get_buffer_state()
retx.is_segment ? "true" : "false",
retx.so_start,
retx.so_end);
if (tx_window.end() != tx_window.find(retx.sn)) {
if (tx_window.has_sn(retx.sn)) {
int req_bytes = required_buffer_size(retx);
if (req_bytes < 0) {
logger.error("In get_buffer_state(): Removing retx.sn=%d from queue", retx.sn);
@ -484,13 +484,13 @@ void rlc_am_lte::rlc_am_lte_tx::retransmit_pdu()
{
if (not tx_window.empty()) {
// select PDU in tx window for retransmission
std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator it = tx_window.begin();
logger.info("%s Schedule SN=%d for reTx.", RB_NAME, it->first);
rlc_amd_tx_pdu_t& pdu = tx_window.front();
logger.info("%s Schedule SN=%d for reTx.", RB_NAME, pdu.rlc_sn);
rlc_amd_retx_t retx = {};
retx.is_segment = false;
retx.so_start = 0;
retx.so_end = it->second.buf->N_bytes;
retx.sn = it->first;
retx.so_end = pdu.buf->N_bytes;
retx.sn = pdu.rlc_sn;
retx_queue.push_back(retx);
}
}
@ -576,7 +576,7 @@ int rlc_am_lte::rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_byt
rlc_amd_retx_t retx = retx_queue.front();
// Sanity check - drop any retx SNs not present in tx_window
while (tx_window.end() == tx_window.find(retx.sn)) {
while (not tx_window.has_sn(retx.sn)) {
retx_queue.pop_front();
if (!retx_queue.empty()) {
retx = retx_queue.front();
@ -972,10 +972,12 @@ int rlc_am_lte::rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_byt
vt_s = (vt_s + 1) % MOD;
// Place PDU in tx_window, write header and TX
tx_window.add_pdu(header.sn);
tx_window[header.sn].buf = std::move(pdu);
tx_window[header.sn].header = header;
tx_window[header.sn].is_acked = false;
tx_window[header.sn].retx_count = 0;
tx_window[header.sn].rlc_sn = header.sn;
const byte_buffer_t* buffer_ptr = tx_window[header.sn].buf.get();
uint8_t* ptr = payload;
@ -1017,7 +1019,6 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
}
// Handle ACKs and NACKs
std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator it;
bool update_vt_a = true;
uint32_t i = vt_a;
std::vector<uint32_t> notify_info_vec;
@ -1028,34 +1029,32 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
if (status.nacks[j].nack_sn == i) {
nack = true;
update_vt_a = false;
it = tx_window.find(i);
if (tx_window.end() != it) {
if (tx_window.has_sn(i)) {
auto& pdu = tx_window[i];
if (!retx_queue_has_sn(i)) {
rlc_amd_retx_t retx = {};
retx.sn = i;
retx.is_segment = false;
retx.so_start = 0;
retx.so_end = it->second.buf->N_bytes;
retx.so_end = pdu.buf->N_bytes;
if (status.nacks[j].has_so) {
// sanity check
if (status.nacks[j].so_start >= it->second.buf->N_bytes) {
if (status.nacks[j].so_start >= pdu.buf->N_bytes) {
// print error but try to send original PDU again
logger.info("SO_start is larger than original PDU (%d >= %d)",
status.nacks[j].so_start,
it->second.buf->N_bytes);
logger.info(
"SO_start is larger than original PDU (%d >= %d)", status.nacks[j].so_start, pdu.buf->N_bytes);
status.nacks[j].so_start = 0;
}
// check for special SO_end value
if (status.nacks[j].so_end == 0x7FFF) {
status.nacks[j].so_end = it->second.buf->N_bytes;
status.nacks[j].so_end = pdu.buf->N_bytes;
} else {
retx.so_end = status.nacks[j].so_end + 1;
}
if (status.nacks[j].so_start < it->second.buf->N_bytes &&
status.nacks[j].so_end <= it->second.buf->N_bytes) {
if (status.nacks[j].so_start < pdu.buf->N_bytes && status.nacks[j].so_end <= pdu.buf->N_bytes) {
retx.is_segment = true;
retx.so_start = status.nacks[j].so_start;
} else {
@ -1064,7 +1063,7 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
i,
status.nacks[j].so_start,
status.nacks[j].so_end,
it->second.buf->N_bytes);
pdu.buf->N_bytes);
}
}
retx_queue.push_back(retx);
@ -1075,15 +1074,13 @@ void rlc_am_lte::rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t no
if (!nack) {
// ACKed SNs get marked and removed from tx_window if possible
if (tx_window.count(i) > 0) {
it = tx_window.find(i);
if (it != tx_window.end()) {
update_notification_ack_info(it->second, notify_info_vec);
if (update_vt_a) {
tx_window.erase(it);
vt_a = (vt_a + 1) % MOD;
vt_ms = (vt_ms + 1) % MOD;
}
if (tx_window.has_sn(i)) {
auto& pdu = tx_window[i];
update_notification_ack_info(pdu, notify_info_vec);
if (update_vt_a) {
tx_window.remove_pdu(i);
vt_a = (vt_a + 1) % MOD;
vt_ms = (vt_ms + 1) % MOD;
}
}
}
@ -1160,7 +1157,7 @@ void rlc_am_lte::rlc_am_lte_tx::debug_state()
int rlc_am_lte::rlc_am_lte_tx::required_buffer_size(rlc_amd_retx_t retx)
{
if (!retx.is_segment) {
if (tx_window.count(retx.sn) == 1) {
if (tx_window.has_sn(retx.sn)) {
if (tx_window[retx.sn].buf) {
return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes;
} else {