From 1495a6b01fc03b0d21f2e56fba23f249273be9b6 Mon Sep 17 00:00:00 2001
From: Cedric Roux <cedric.roux@eurecom.fr>
Date: Tue, 16 Nov 2021 13:22:49 +0100
Subject: [PATCH] nr rlc: speedup buffer status computation

TX and ReTX should be faster now (for RLC AM, UM and TM).

RLC AM Status (function nr_rlc_entity_am.c:status_size()) was not modified,
so its CPU usage is the same as before. (It's more complicated to change
than for TX and ReTX.)
---
 openair2/LAYER2/nr_rlc/nr_rlc_entity.h    |  2 +
 openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c | 84 +++++++++++++----------
 openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c | 23 +++----
 openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c | 67 +++++++++---------
 4 files changed, 93 insertions(+), 83 deletions(-)

diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h
index 5b12a90cfd..b9b638fe07 100644
--- a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h
+++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h
@@ -63,6 +63,8 @@ typedef struct nr_rlc_entity_t {
   void (*max_retx_reached)(void *max_retx_reached_data,
                            struct nr_rlc_entity_t *entity);
   void *max_retx_reached_data;
+  /* buffer status computation */
+  nr_rlc_entity_buffer_status_t bstatus;
 } nr_rlc_entity_t;
 
 nr_rlc_entity_t *new_nr_rlc_entity_am(
diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
index 8db5ce31ad..aaf5492241 100644
--- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
+++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
@@ -28,6 +28,19 @@
 
 #include "LOG/log.h"
 
+/* for a given SDU/SDU segment, computes the corresponding PDU header size */
+static int compute_pdu_header_size(nr_rlc_entity_am_t *entity,
+                                   nr_rlc_sdu_segment_t *sdu)
+{
+  int header_size = 2;
+  /* one more byte if SN field length is 18 */
+  if (entity->sn_field_length == 18)
+    header_size++;
+  /* two more bytes for SO if SDU segment is not the first */
+  if (!sdu->is_first) header_size += 2;
+  return header_size;
+}
+
 /*************************************************************************/
 /* PDU RX functions                                                      */
 /*************************************************************************/
@@ -114,6 +127,10 @@ static void consider_retransmission(nr_rlc_entity_am_t *entity,
   nr_rlc_sdu_segment_list_append(&entity->retransmit_list,
                                  &entity->retransmit_end,
                                  cur);
+
+  /* update buffer status */
+  entity->common.bstatus.retx_size += compute_pdu_header_size(entity, cur)
+                                      + cur->size;
 }
 
 /* checks that all the bytes of the SDU sn have been received (but SDU
@@ -351,6 +368,9 @@ static void process_received_ack(nr_rlc_entity_am_t *entity, int ack_sn)
       }
       /* remove from retransmit list */
       prev->next = cur->next;
+      /* update buffer status */
+      entity->common.bstatus.retx_size -= compute_pdu_header_size(entity, cur)
+                                          + cur->size;
       /* put the PDU in the ack list */
       entity->ack_list = nr_rlc_sdu_segment_list_add(sn_compare_tx, entity,
                                                      entity->ack_list, cur);
@@ -840,19 +860,6 @@ static int serialize_sdu(nr_rlc_entity_am_t *entity,
   return encoder.byte + sdu->size;
 }
 
-/* for a given SDU/SDU segment, computes the corresponding PDU header size */
-static int compute_pdu_header_size(nr_rlc_entity_am_t *entity,
-                                   nr_rlc_sdu_segment_t *sdu)
-{
-  int header_size = 2;
-  /* one more byte if SN field length is 18 */
-  if (entity->sn_field_length == 18)
-    header_size++;
-  /* two more bytes for SO if SDU segment is not the first */
-  if (!sdu->is_first) header_size += 2;
-  return header_size;
-}
-
 /* resize SDU/SDU segment for the corresponding PDU to fit into 'pdu_size'
  * bytes
  * - modifies SDU/SDU segment to become an SDU segment
@@ -1426,8 +1433,12 @@ static int generate_retx_pdu(nr_rlc_entity_am_t *entity, char *buffer,
 
   sdu->next = NULL;
 
-  /* segment if necessary */
   pdu_size = pdu_header_size + sdu->size;
+
+  /* update buffer status */
+  entity->common.bstatus.retx_size -= pdu_size;
+
+  /* segment if necessary */
   if (pdu_size > size) {
     nr_rlc_sdu_segment_t *next_sdu;
     next_sdu = resegment(sdu, entity, size);
@@ -1436,6 +1447,9 @@ static int generate_retx_pdu(nr_rlc_entity_am_t *entity, char *buffer,
     entity->retransmit_list = next_sdu;
     if (entity->retransmit_end == NULL)
       entity->retransmit_end = entity->retransmit_list;
+    /* update buffer status */
+    entity->common.bstatus.retx_size += compute_pdu_header_size(entity, next_sdu)
+                                        + next_sdu->size;
   }
 
   /* put SDU/SDU segment in the wait list */
@@ -1479,11 +1493,15 @@ static int generate_tx_pdu(nr_rlc_entity_am_t *entity, char *buffer, int size)
 
   sdu->next = NULL;
 
+  pdu_size = pdu_header_size + sdu->size;
+
+  /* update buffer status */
+  entity->common.bstatus.tx_size -= pdu_size;
+
   /* assign SN to SDU */
   sdu->sdu->sn = entity->tx_next;
 
   /* segment if necessary */
-  pdu_size = pdu_header_size + sdu->size;
   if (pdu_size > size) {
     nr_rlc_sdu_segment_t *next_sdu;
     next_sdu = resegment(sdu, entity, size);
@@ -1492,6 +1510,9 @@ static int generate_tx_pdu(nr_rlc_entity_am_t *entity, char *buffer, int size)
     entity->tx_list = next_sdu;
     if (entity->tx_end == NULL)
       entity->tx_end = entity->tx_list;
+    /* update buffer status */
+    entity->common.bstatus.tx_size += compute_pdu_header_size(entity, next_sdu)
+                                      + next_sdu->size;
   }
 
   /* update tx_next if the SDU segment is the last */
@@ -1520,24 +1541,6 @@ static int generate_tx_pdu(nr_rlc_entity_am_t *entity, char *buffer, int size)
   return serialize_sdu(entity, sdu, buffer, size, p);
 }
 
-/* Pretend to serialize all the SDUs in a list and return the size
- * of all the PDUs it would produce, limited to 'maxsize'.
- * Used for buffer status reporting.
- */
-static int tx_list_size(nr_rlc_entity_am_t *entity,
-                        nr_rlc_sdu_segment_t *l, int maxsize)
-{
-  int ret = 0;
-
-  while (l != NULL && ret < maxsize) {
-    ret += compute_pdu_header_size(entity, l) + l->size;
-    l = l->next;
-  }
-
-  if (ret > maxsize) ret = maxsize;
-  return ret;
-}
-
 nr_rlc_entity_buffer_status_t nr_rlc_entity_am_buffer_status(
     nr_rlc_entity_t *_entity, int maxsize)
 {
@@ -1549,8 +1552,8 @@ nr_rlc_entity_buffer_status_t nr_rlc_entity_am_buffer_status(
   else
     ret.status_size = 0;
 
-  ret.tx_size = tx_list_size(entity, entity->tx_list, maxsize);
-  ret.retx_size = tx_list_size(entity, entity->retransmit_list, maxsize);
+  ret.tx_size = entity->common.bstatus.tx_size;
+  ret.retx_size = entity->common.bstatus.retx_size;
 
   return ret;
 }
@@ -1606,6 +1609,10 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity,
   LOG_D(RLC, "Created new RLC SDU and append it to the RLC list \n");
 
   nr_rlc_sdu_segment_list_append(&entity->tx_list, &entity->tx_end, sdu);
+
+  /* update buffer status */
+  entity->common.bstatus.tx_size += compute_pdu_header_size(entity, sdu)
+                                    + sdu->size;
 }
 
 /*************************************************************************/
@@ -1793,6 +1800,10 @@ void nr_rlc_entity_am_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id)
       entity->tx_end = NULL;
   }
 
+  /* update buffer status */
+  entity->common.bstatus.tx_size -= compute_pdu_header_size(entity, cur)
+                                    + cur->size;
+
   nr_rlc_free_sdu_segment(cur);
 }
 
@@ -1845,6 +1856,9 @@ static void clear_entity(nr_rlc_entity_am_t *entity)
   entity->retransmit_end  = NULL;
 
   entity->ack_list        = NULL;
+
+  entity->common.bstatus.tx_size   = 0;
+  entity->common.bstatus.retx_size = 0;
 }
 
 void nr_rlc_entity_am_reestablishment(nr_rlc_entity_t *_entity)
diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c
index 26ae481889..75408276d1 100644
--- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c
+++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c
@@ -68,22 +68,12 @@ static int generate_tx_pdu(nr_rlc_entity_tm_t *entity, char *buffer, int size)
   memcpy(buffer, sdu->sdu->data, sdu->size);
 
   entity->tx_size -= sdu->size;
-  nr_rlc_free_sdu_segment(sdu);
 
-  return ret;
-}
-
-static int tx_list_size(nr_rlc_entity_tm_t *entity,
-                        nr_rlc_sdu_segment_t *l, int maxsize)
-{
-  int ret = 0;
+  /* update buffer status */
+  entity->common.bstatus.tx_size -= sdu->size;
 
-  while (l != NULL && ret < maxsize) {
-    ret += l->size;
-    l = l->next;
-  }
+  nr_rlc_free_sdu_segment(sdu);
 
-  if (ret > maxsize) ret = maxsize;
   return ret;
 }
 
@@ -94,7 +84,7 @@ nr_rlc_entity_buffer_status_t nr_rlc_entity_tm_buffer_status(
   nr_rlc_entity_buffer_status_t ret;
 
   ret.status_size = 0;
-  ret.tx_size = tx_list_size(entity, entity->tx_list, maxsize);
+  ret.tx_size = entity->common.bstatus.tx_size;
   ret.retx_size = 0;
 
   return ret;
@@ -136,6 +126,9 @@ void nr_rlc_entity_tm_recv_sdu(nr_rlc_entity_t *_entity,
   sdu = nr_rlc_new_sdu(buffer, size, sdu_id);
 
   nr_rlc_sdu_segment_list_append(&entity->tx_list, &entity->tx_end, sdu);
+
+  /* update buffer status */
+  entity->common.bstatus.tx_size += sdu->size;
 }
 
 /*************************************************************************/
@@ -165,6 +158,8 @@ static void clear_entity(nr_rlc_entity_tm_t *entity)
   entity->tx_list         = NULL;
   entity->tx_end          = NULL;
   entity->tx_size         = 0;
+
+  entity->common.bstatus.tx_size = 0;
 }
 
 void nr_rlc_entity_tm_reestablishment(nr_rlc_entity_t *_entity)
diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c
index 71173eee5a..7336e8f9da 100644
--- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c
+++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c
@@ -28,6 +28,20 @@
 
 #include "LOG/log.h"
 
+/* for a given SDU/SDU segment, computes the corresponding PDU header size */
+static int compute_pdu_header_size(nr_rlc_entity_um_t *entity,
+                                   nr_rlc_sdu_segment_t *sdu)
+{
+  int header_size = 1;
+
+  /* if SN to be included then one more byte if SN field length is 12 */
+  if (!(sdu->is_first && sdu->is_last) && entity->sn_field_length == 12)
+    header_size++;
+  /* two more bytes for SO if SDU segment is not the first */
+  if (!sdu->is_first) header_size += 2;
+  return header_size;
+}
+
 /*************************************************************************/
 /* PDU RX functions                                                      */
 /*************************************************************************/
@@ -375,20 +389,6 @@ static int serialize_sdu(nr_rlc_entity_um_t *entity,
   return encoder.byte + sdu->size;
 }
 
-/* for a given SDU/SDU segment, computes the corresponding PDU header size */
-static int compute_pdu_header_size(nr_rlc_entity_um_t *entity,
-                                   nr_rlc_sdu_segment_t *sdu)
-{
-  int header_size = 1;
-
-  /* if SN to be included then one more byte if SN field length is 12 */
-  if (!(sdu->is_first && sdu->is_last) && entity->sn_field_length == 12)
-    header_size++;
-  /* two more bytes for SO if SDU segment is not the first */
-  if (!sdu->is_first) header_size += 2;
-  return header_size;
-}
-
 /* resize SDU/SDU segment for the corresponding PDU to fit into 'pdu_size'
  * bytes
  * - modifies SDU/SDU segment to become an SDU segment
@@ -462,8 +462,12 @@ static int generate_tx_pdu(nr_rlc_entity_um_t *entity, char *buffer, int size)
   /* assign SN to SDU */
   sdu->sdu->sn = entity->tx_next;
 
-  /* segment if necessary */
   pdu_size = pdu_header_size + sdu->size;
+
+  /* update buffer status */
+  entity->common.bstatus.tx_size -= pdu_size;
+
+  /* segment if necessary */
   if (pdu_size > size) {
     nr_rlc_sdu_segment_t *next_sdu;
     next_sdu = resegment(sdu, entity, size);
@@ -474,6 +478,9 @@ static int generate_tx_pdu(nr_rlc_entity_um_t *entity, char *buffer, int size)
     entity->tx_list = next_sdu;
     if (entity->tx_end == NULL)
       entity->tx_end = entity->tx_list;
+    /* update buffer status */
+    entity->common.bstatus.tx_size += compute_pdu_header_size(entity, next_sdu)
+                                      + next_sdu->size;
   }
 
   /* update tx_next if the SDU is an SDU segment and is the last */
@@ -488,24 +495,6 @@ static int generate_tx_pdu(nr_rlc_entity_um_t *entity, char *buffer, int size)
   return ret;
 }
 
-/* Pretend to serialize all the SDUs in a list and return the size
- * of all the PDUs it would produce, limited to 'maxsize'.
- * Used for buffer status reporting.
- */
-static int tx_list_size(nr_rlc_entity_um_t *entity,
-                        nr_rlc_sdu_segment_t *l, int maxsize)
-{
-  int ret = 0;
-
-  while (l != NULL && ret < maxsize) {
-    ret += compute_pdu_header_size(entity, l) + l->size;
-    l = l->next;
-  }
-
-  if (ret > maxsize) ret = maxsize;
-  return ret;
-}
-
 nr_rlc_entity_buffer_status_t nr_rlc_entity_um_buffer_status(
     nr_rlc_entity_t *_entity, int maxsize)
 {
@@ -513,7 +502,7 @@ nr_rlc_entity_buffer_status_t nr_rlc_entity_um_buffer_status(
   nr_rlc_entity_buffer_status_t ret;
 
   ret.status_size = 0;
-  ret.tx_size = tx_list_size(entity, entity->tx_list, maxsize);
+  ret.tx_size = entity->common.bstatus.tx_size;
   ret.retx_size = 0;
 
   return ret;
@@ -555,6 +544,10 @@ void nr_rlc_entity_um_recv_sdu(nr_rlc_entity_t *_entity,
   sdu = nr_rlc_new_sdu(buffer, size, sdu_id);
 
   nr_rlc_sdu_segment_list_append(&entity->tx_list, &entity->tx_end, sdu);
+
+  /* update buffer status */
+  entity->common.bstatus.tx_size += compute_pdu_header_size(entity, sdu)
+                                    + sdu->size;
 }
 
 /*************************************************************************/
@@ -650,6 +643,10 @@ void nr_rlc_entity_um_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id)
       entity->tx_end = NULL;
   }
 
+  /* update buffer status */
+  entity->common.bstatus.tx_size -= compute_pdu_header_size(entity, cur)
+                                    + cur->size;
+
   nr_rlc_free_sdu_segment(cur);
 }
 
@@ -682,6 +679,8 @@ static void clear_entity(nr_rlc_entity_um_t *entity)
   entity->tx_list         = NULL;
   entity->tx_end          = NULL;
   entity->tx_size         = 0;
+
+  entity->common.bstatus.tx_size = 0;
 }
 
 void nr_rlc_entity_um_reestablishment(nr_rlc_entity_t *_entity)
-- 
2.26.2