From 76aa112cec8355b779bd5e289ba1a86a72ea2039 Mon Sep 17 00:00:00 2001 From: Chieh-Chun Chen Date: Wed, 23 Aug 2023 16:49:17 +0200 Subject: [PATCH] Add more RLC stats and correct RLC stats - Add GOL-delay and AVG-soujour - Correct the types of/measurement the tx/rxsdu_bytes and tx/rxsdu_occ_bytes - Update txsdu_avg_time_to_tx value only when measurements activated Co-authored-by: Teodora Vladic --- openair2/LAYER2/nr_rlc/nr_rlc_entity.c | 35 ++++++++++++++++++++-- openair2/LAYER2/nr_rlc/nr_rlc_entity.h | 36 ++++++++++------------- openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c | 24 +++++++++++---- openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c | 6 ++-- openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c | 6 ++-- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 6 ++++ openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h | 4 +++ 7 files changed, 82 insertions(+), 35 deletions(-) diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity.c index e9fa7e5a6e..f0934ca599 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity.c @@ -36,10 +36,36 @@ static void nr_rlc_entity_get_stats( nr_rlc_statistics_t *out) { // printf("Stats from the RLC entity asked\n"); + uint64_t time_now = time_average_now(); *out = entity->stats; + + // Get the correct HOL RLC-SDU + nr_rlc_sdu_segment_t* sdu; + if (entity->stats.mode == NR_RLC_AM) { + nr_rlc_entity_am_t* am_entity = (nr_rlc_entity_am_t *) entity; + if (am_entity->retransmit_list != NULL) { + sdu = am_entity->retransmit_list; + } else { + sdu = am_entity->tx_list; + } + } else if (entity->stats.mode == NR_RLC_UM) { + nr_rlc_entity_um_t* um_entity = (nr_rlc_entity_um_t *) entity; + sdu = um_entity->tx_list; + } else { + nr_rlc_entity_tm_t* tm_entity = (nr_rlc_entity_tm_t *) entity; + sdu = tm_entity->tx_list; + } + + // Compute HOL waittime, make sure that segmented packets don't have 'zero' time-of-arrival + if (sdu != NULL) { + out->txsdu_wt_us = time_now - sdu->sdu->time_of_arrival; + } else { + // No HOL packets --> wait-time == 0 + out->txsdu_wt_us = 0; + } + if (entity->avg_time_is_on) - out->txsdu_avg_time_to_tx = time_average_get_average(entity->txsdu_avg_time_to_tx, - time_average_now()); + out->txsdu_avg_time_to_tx = time_average_get_average(entity->txsdu_avg_time_to_tx, time_now); else out->txsdu_avg_time_to_tx = 0; } @@ -112,8 +138,11 @@ nr_rlc_entity_t *new_nr_rlc_entity_am( ret->common.stats.mode = NR_RLC_AM; + ret->common.stats.rxsdu_bytes = 0; // init default arrivals (SDU) counter + ret->common.stats.txsdu_bytes = 0; // init default transmits (SDU) counter + /* let's take average over the last 100 milliseconds - * initial_size of 1024 is arbitrary + * initial_size of 1024 (packets) is arbitrary */ ret->common.txsdu_avg_time_to_tx = time_average_new(100 * 1000, 1024); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h index ec911e9217..7996d8c89e 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h @@ -41,8 +41,7 @@ typedef struct { /* TX */ uint32_t txpdu_pkts; /* aggregated number of transmitted RLC PDUs */ uint32_t txpdu_bytes; /* aggregated amount of transmitted bytes in RLC PDUs */ - /* TODO? */ - uint32_t txpdu_wt_ms; /* aggregated head-of-line tx packet waiting time to be transmitted (i.e. send to the MAC layer) */ + uint32_t txpdu_wt_ms; /* TODO: aggregated head-of-line tx packet waiting time to be transmitted (i.e. send to the MAC layer) */ uint32_t txpdu_dd_pkts; /* aggregated number of dropped or discarded tx packets by RLC */ uint32_t txpdu_dd_bytes; /* aggregated amount of bytes dropped or discarded tx packets by RLC */ uint32_t txpdu_retx_pkts; /* aggregated number of tx pdus/pkts to be re-transmitted (only applicable to RLC AM) */ @@ -50,10 +49,8 @@ typedef struct { uint32_t txpdu_segmented; /* aggregated number of segmentations */ uint32_t txpdu_status_pkts; /* aggregated number of tx status pdus/pkts (only applicable to RLC AM) */ uint32_t txpdu_status_bytes; /* aggregated amount of tx status bytes (only applicable to RLC AM) */ - /* TODO? */ - uint32_t txbuf_occ_bytes; /* current tx buffer occupancy in terms of amount of bytes (average: NOT IMPLEMENTED) */ - /* TODO? */ - uint32_t txbuf_occ_pkts; /* current tx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */ + uint32_t txbuf_occ_bytes; /* (IMPLEMENTED) transmitting bytes currently in buffer */ + uint32_t txbuf_occ_pkts; /* TODO: current tx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */ /* txbuf_wd_ms: the time window for which the txbuf occupancy value is obtained - NOT IMPLEMENTED */ /* RX */ @@ -70,31 +67,28 @@ typedef struct { /* rxpdu_rotout_ms: flag indicating rx reordering timeout in ms - NOT IMPLEMENTED */ /* rxpdu_potout_ms: flag indicating the poll retransmit time out in ms - NOT IMPLEMENTED */ /* rxpdu_sptout_ms: flag indicating status prohibit timeout in ms - NOT IMPLEMENTED */ - /* TODO? */ - uint32_t rxbuf_occ_bytes; /* current rx buffer occupancy in terms of amount of bytes (average: NOT IMPLEMENTED) */ - /* TODO? */ - uint32_t rxbuf_occ_pkts; /* current rx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */ + uint32_t rxbuf_occ_bytes; /* (IMPLEMENTED) received bytes currently in buffer */ + uint32_t rxbuf_occ_pkts; /* TODO: current rx buffer occupancy in terms of number of packets (average: NOT IMPLEMENTED) */ /* SDU stats */ /* TX */ uint32_t txsdu_pkts; /* number of SDUs delivered */ - uint32_t txsdu_bytes; /* number of bytes of SDUs delivered */ + uint64_t txsdu_bytes; /* (UPDATED) number of SDUs bytes successfully transmitted so far (counter) */ + /* Average time for an SDU to be passed to MAC: + * Actually measures the time it takes for THE FULL SDU to be passed to MAC FOR THE FIRST TIME. + * Since the MAC schedules in advance, it does not measure the time of + * transmission over the air, just the time to reach the MAC layer. + * => to control it, 'txsdu_wt_us' that measures the current HOL-delay is added. + */ + double txsdu_avg_time_to_tx; /* (100ms-windowed) per-packet sojourn (SDU to PDU) in microseconds */ + uint32_t txsdu_wt_us; /* HOL delay of the current radio bearer, in microseconds */ /* RX */ uint32_t rxsdu_pkts; /* number of SDUs received */ - uint32_t rxsdu_bytes; /* number of bytes of SDUs received */ + uint64_t rxsdu_bytes; /* (UPDATED) number of SDUs bytes arrived so far (counter) */ uint32_t rxsdu_dd_pkts; /* number of dropped or discarded SDUs */ uint32_t rxsdu_dd_bytes; /* number of bytes of SDUs dropped or discarded */ - /* Average time for an SDU to be passed to MAC. - * Actually measures the time it takes for any part of an SDU to be - * passed to MAC for the first time, that is: the first TX of (part of) the - * SDU. - * Since the MAC schedules in advance, it does not measure the time of - * transmission over the air, just the time to reach the MAC layer. - */ - double txsdu_avg_time_to_tx; - } nr_rlc_statistics_t; typedef struct { diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c index 033b436255..6840e2810a 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c @@ -224,7 +224,8 @@ static void reassemble_and_deliver(nr_rlc_entity_am_t *entity, int sn) sdu, so); entity->common.stats.txsdu_pkts++; - entity->common.stats.txsdu_bytes += so; + /* AM 'txsdu_bytes' now only count successfully transmitted bytes */ + // entity->common.stats.txsdu_bytes += so; } static void reception_actions(nr_rlc_entity_am_t *entity, nr_rlc_pdu_t *pdu) @@ -484,6 +485,8 @@ process_wait_list_head: end_wait_list = prev_wait_list; if (nr_rlc_free_sdu_segment(cur_wait_list)) { entity->tx_size -= sdu_size; + // Wait-ACK: count as successfully transmitted bytes + entity->common.stats.txsdu_bytes += sdu_size; entity->common.sdu_successful_delivery( entity->common.sdu_successful_delivery_data, (nr_rlc_entity_t *)entity, upper_layer_id); @@ -546,6 +549,8 @@ process_retransmit_list_head: + cur->size; if (nr_rlc_free_sdu_segment(cur)) { entity->tx_size -= sdu_size; + // Retransmit-ACK: count as successfully transmitted bytes + entity->common.stats.txsdu_bytes += sdu_size; entity->common.sdu_successful_delivery( entity->common.sdu_successful_delivery_data, (nr_rlc_entity_t *)entity, upper_layer_id); @@ -604,6 +609,8 @@ nacks_done: end_wait_list = prev_wait_list; if (nr_rlc_free_sdu_segment(cur_wait_list)) { entity->tx_size -= sdu_size; + // Wait-NACK done: count as successfully transmitted bytes + entity->common.stats.txsdu_bytes += sdu_size; entity->common.sdu_successful_delivery( entity->common.sdu_successful_delivery_data, (nr_rlc_entity_t *)entity, upper_layer_id); @@ -625,6 +632,8 @@ nacks_done: + cur->size; if (nr_rlc_free_sdu_segment(cur)) { entity->tx_size -= sdu_size; + // Retransmit-NACK done: count as successfully transmitted bytes + entity->common.stats.txsdu_bytes += sdu_size; entity->common.sdu_successful_delivery( entity->common.sdu_successful_delivery_data, (nr_rlc_entity_t *)entity, upper_layer_id); @@ -1619,11 +1628,11 @@ static int generate_tx_pdu(nr_rlc_entity_am_t *entity, char *buffer, int size) entity->common.stats.txpdu_pkts++; entity->common.stats.txpdu_bytes += ret_size; - if (sdu->sdu->time_of_arrival) { + /* No need to 'zero' time-of-arrival; + Segmented packets do need to be duplicated in time-sensitive use cases */ + if (entity->common.avg_time_is_on) { uint64_t time_now = time_average_now(); uint64_t waited_time = time_now - sdu->sdu->time_of_arrival; - /* set time_of_arrival to 0 so as to update stats only once */ - sdu->sdu->time_of_arrival = 0; time_average_add(entity->common.txsdu_avg_time_to_tx, time_now, waited_time); } @@ -1681,7 +1690,6 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity, nr_rlc_sdu_segment_t *sdu; entity->common.stats.rxsdu_pkts++; - entity->common.stats.rxsdu_bytes += size; if (size > NR_SDU_MAX) { LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n", @@ -1705,6 +1713,8 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity, } entity->tx_size += size; + // SDU received: Count as arrival bytes + entity->common.stats.rxsdu_bytes += size; sdu = nr_rlc_new_sdu(buffer, size, sdu_id); @@ -1899,6 +1909,10 @@ void nr_rlc_entity_am_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id) + cur->size; entity->tx_size -= cur->sdu->size; + + /* Uncomment to assert if SDU are ever discarded */ + // assert(0 != 0 && "[RLC-TRAP] SDU discard should never be reached!"); + nr_rlc_free_sdu_segment(cur); } diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c index cfadf43d99..afad2d23a2 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c @@ -79,11 +79,11 @@ static int generate_tx_pdu(nr_rlc_entity_tm_t *entity, char *buffer, int size) entity->common.stats.txpdu_pkts++; entity->common.stats.txpdu_bytes += size; - if (sdu->sdu->time_of_arrival) { + /* No need to 'zero' time-of-arrival; + Segmented packets do need to be duplicated in time-sensitive use cases */ + if (entity->common.avg_time_is_on) { uint64_t time_now = time_average_now(); uint64_t waited_time = time_now - sdu->sdu->time_of_arrival; - /* set time_of_arrival to 0 so as to update stats only once */ - sdu->sdu->time_of_arrival = 0; time_average_add(entity->common.txsdu_avg_time_to_tx, time_now, waited_time); } diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c index 43a2189c51..4a9a67e40c 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c @@ -521,11 +521,11 @@ static int generate_tx_pdu(nr_rlc_entity_um_t *entity, char *buffer, int size) entity->common.stats.txpdu_pkts++; entity->common.stats.txpdu_bytes += size; - if (sdu->sdu->time_of_arrival) { + /* No need to 'zero' time-of-arrival; + Segmented packets do need to be duplicated in time-sensitive use cases */ + if (entity->common.avg_time_is_on) { uint64_t time_now = time_average_now(); uint64_t waited_time = time_now - sdu->sdu->time_of_arrival; - /* set time_of_arrival to 0 so as to update stats only once */ - sdu->sdu->time_of_arrival = 0; time_average_add(entity->common.txsdu_avg_time_to_tx, time_now, waited_time); } diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 02c1c72fb7..10e2ebc3e7 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -1070,6 +1070,12 @@ const bool nr_rlc_get_statistics( if (rb != NULL) { rb->get_stats(rb, out); ret = true; + + // Patch buffer status using OAI results (no need to change anything in the RB) + // rb->set_time(rb, nr_rlc_current_time); + nr_rlc_entity_buffer_status_t oai_stat = rb->buffer_status(rb, 1000*1000); + out->rxbuf_occ_bytes = oai_stat.status_size; + out->txbuf_occ_bytes = oai_stat.tx_size + oai_stat.retx_size; } else { ret = false; } diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h index 15fe286435..feeb371244 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h @@ -35,6 +35,8 @@ #include "NR_RadioBearerConfig.h" #include "NR_CellGroupConfig.h" #include "openair2/RRC/NR/nr_rrc_proto.h" +#include "nr_rlc_ue_manager.h" + struct NR_RLC_Config; struct NR_LogicalChannelConfig; @@ -67,3 +69,5 @@ void nr_rlc_activate_srb0(int rnti, struct gNB_MAC_INST_s *mac, void *rawUE, const uint8_t *sdu, sdu_size_t sdu_len, void *rawUE)); + +const bool nr_rlc_get_statistics(int rnti, int srb_flag, int rb_id, nr_rlc_statistics_t *out);