diff --git a/common/platform_types.h b/common/platform_types.h index 26c4bafa75..5225f4566f 100644 --- a/common/platform_types.h +++ b/common/platform_types.h @@ -108,6 +108,7 @@ typedef struct { sdu_size_t head_sdu_remaining_size_to_send; /*!< \brief remaining size of sdu: could be the total size or the remaining size of already segmented sdu */ bool head_sdu_is_segmented; /*!< \brief 0 if head SDU has not been segmented, 1 if already segmented */ + uint64_t oldest_sdu_arrival_ms; /*!< \brief Timestamp (ms, RLC time) of oldest SDU in tx/retx queue, 0 if empty */ } mac_rlc_status_resp_t; #define SDU_CONFIRM_NO false diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 883b95d47e..613465e90c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -442,6 +442,7 @@ static int collect_dl_candidates(gNB_MAC_INST *mac, int n = 0; const frame_structure_t *fs = &mac->frame_structure; const float dl_slots_per_s = (float)get_dl_slots_per_period(fs) / fs->numb_slots_period * fs->numb_slots_frame * 100; + const uint64_t now_ms = get_nr_rlc_current_time(); UE_iterator (UE_list, UE) { if (n >= max_candidates) @@ -527,6 +528,11 @@ static int collect_dl_candidates(gNB_MAC_INST *mac, .alloc_beam_idx = 0, .alloc_new_beam = false, }; + nr_dl_candidate_t *c = &candidates[n - 1]; + FOR_EACH_SEQ_ARR(const nr_lc_config_t *, lc, &sched_ctrl->lc_config) { + const uint64_t ts = sched_ctrl->rlc_status[lc->lcid].oldest_sdu_arrival_ms; + c->hol_delay_ms[lc->lcid] = (ts > 0 && ts <= now_ms) ? (now_ms - ts) : 0; + } } else { /* new transmission candidate */ if (sched_ctrl->available_dl_harq.head < 0) @@ -572,8 +578,11 @@ static int collect_dl_candidates(gNB_MAC_INST *mac, .alloc_new_beam = false, }; nr_dl_candidate_t *c = &candidates[n - 1]; - for (int lcid = 0; lcid < NR_MAX_NUM_LCID; lcid++) - c->pending_bytes_per_lcid[lcid] = sched_ctrl->rlc_status[lcid].bytes_in_buffer; + FOR_EACH_SEQ_ARR(const nr_lc_config_t *, lc, &sched_ctrl->lc_config) { + c->pending_bytes_per_lcid[lc->lcid] = sched_ctrl->rlc_status[lc->lcid].bytes_in_buffer; + const uint64_t ts = sched_ctrl->rlc_status[lc->lcid].oldest_sdu_arrival_ms; + c->hol_delay_ms[lc->lcid] = (ts > 0 && ts <= now_ms) ? (now_ms - ts) : 0; + } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index ccd63fb5bf..244d992b6a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -917,6 +917,7 @@ struct nr_dl_candidate { int retx_rbSize; ///< RBs needed for retx, 0 for new tx uint32_t pending_bytes; ///< total bytes waiting in RLC buffers uint32_t pending_bytes_per_lcid[NR_MAX_NUM_LCID]; ///< per-LCID bytes waiting in RLC buffers + uint64_t hol_delay_ms[NR_MAX_NUM_LCID]; ///< per-LCID head-of-line delay in milliseconds (age of oldest SDU) float avg_throughput; ///< EWMA goodput in bps (dl_thr_ue) float bler; ///< current BLER estimate int current_mcs; ///< current MCS state (retx: from HARQ, new tx: from BLER tracker) diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h index cb9761aa2f..9fc9f3dd82 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h @@ -78,6 +78,7 @@ typedef struct { int status_size; int tx_size; int retx_size; + uint64_t oldest_sdu_arrival_ms; /* timestamp (ms, from sdu->arrival_ms) of oldest SDU in tx/retx queue, 0 if empty */ } nr_rlc_entity_buffer_status_t; typedef struct nr_rlc_entity_s { diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c index 62c1fa90c6..882a56a70f 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c @@ -1777,6 +1777,12 @@ nr_rlc_entity_buffer_status_t nr_rlc_entity_am_buffer_status( ret.tx_size = entity->common.bstatus.tx_size; ret.retx_size = entity->common.bstatus.retx_size; + ret.oldest_sdu_arrival_ms = 0; + if (entity->retransmit_list && entity->retransmit_list->sdu) + ret.oldest_sdu_arrival_ms = entity->retransmit_list->sdu->arrival_ms; + else if (entity->tx_list && entity->tx_list->sdu) + ret.oldest_sdu_arrival_ms = entity->tx_list->sdu->arrival_ms; + return ret; } @@ -1851,6 +1857,8 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity, if (entity->common.avg_time_is_on) sdu->sdu->time_of_arrival = time_average_now(); + + sdu->sdu->arrival_ms = entity->t_current; } /*************************************************************************/ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c index 1729db8ebf..52f9f7daec 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c @@ -88,6 +88,10 @@ nr_rlc_entity_buffer_status_t nr_rlc_entity_tm_buffer_status(nr_rlc_entity_t *_e ret.tx_size = entity->common.bstatus.tx_size; ret.retx_size = 0; + ret.oldest_sdu_arrival_ms = 0; + if (entity->tx_list && entity->tx_list->sdu) + ret.oldest_sdu_arrival_ms = entity->tx_list->sdu->arrival_ms; + return ret; } @@ -147,6 +151,8 @@ void nr_rlc_entity_tm_recv_sdu(nr_rlc_entity_t *_entity, if (entity->common.avg_time_is_on) sdu->sdu->time_of_arrival = time_average_now(); + + sdu->sdu->arrival_ms = entity->t_current; } /*************************************************************************/ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c index 4d47f78b7e..a25195a6d4 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c @@ -534,6 +534,10 @@ nr_rlc_entity_buffer_status_t nr_rlc_entity_um_buffer_status(nr_rlc_entity_t *_e ret.tx_size = entity->common.bstatus.tx_size; ret.retx_size = 0; + ret.oldest_sdu_arrival_ms = 0; + if (entity->tx_list && entity->tx_list->sdu) + ret.oldest_sdu_arrival_ms = entity->tx_list->sdu->arrival_ms; + return ret; } @@ -594,6 +598,8 @@ void nr_rlc_entity_um_recv_sdu(nr_rlc_entity_t *_entity, if (entity->common.avg_time_is_on) sdu->sdu->time_of_arrival = time_average_now(); + + sdu->sdu->arrival_ms = entity->t_current; } /*************************************************************************/ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 348c489df1..b298c55519 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -47,7 +47,7 @@ void unlock_nr_rlc_current_time(void) AssertFatal(0, "error locking mutex"); } -static uint64_t get_nr_rlc_current_time(void) +uint64_t get_nr_rlc_current_time(void) { lock_nr_rlc_current_time(); @@ -267,10 +267,12 @@ static mac_rlc_status_resp_t _nr_rlc_status_ind(nr_rlc_ue_t *ue, frame_t frame, // Fix me: temproary reduction meanwhile cpu cost of this computation is optimized buf_stat = rb->buffer_status(rb, 1000 * 1000); ret.bytes_in_buffer = buf_stat.status_size + buf_stat.retx_size + buf_stat.tx_size; + ret.oldest_sdu_arrival_ms = buf_stat.oldest_sdu_arrival_ms; } else { if (!(frame % 128) || channel_idP == 0) //to suppress this warning message LOG_W(RLC, "Radio Bearer (channel ID %d) is NULL for UE %d\n", channel_idP, ue->ue_id); ret.bytes_in_buffer = 0; + ret.oldest_sdu_arrival_ms = 0; } ret.pdus_in_buffer = 0; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h index 8fc7a3d3e0..554ea971d8 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h @@ -81,6 +81,8 @@ int nr_rlc_tx_list_occupancy(int ue_id, logical_chan_id_t lcid); void nr_rlc_activate_avg_time_to_tx(const int ue_id, const logical_chan_id_t channel_id, const bool is_on); +uint64_t get_nr_rlc_current_time(void); + void nr_rlc_srb_recv_sdu(const int ue_id, const logical_chan_id_t channel_id, unsigned char *buf, int size); bool nr_rlc_activate_srb0(int ue_id, diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_sdu.h b/openair2/LAYER2/nr_rlc/nr_rlc_sdu.h index 03b5e46c88..df6fb3384e 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_sdu.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_sdu.h @@ -25,6 +25,11 @@ typedef struct nr_rlc_sdu_t { * transmission is used for statistics */ uint64_t time_of_arrival; /* unit microsecond */ + + /* RLC time when the SDU was first received .Used for the HOL-delay + * in MAC. TODO: unify with time_of_arrival (feed E2AP/KPM in us) + */ + uint64_t arrival_ms; } nr_rlc_sdu_t; typedef struct nr_rlc_sdu_segment_t {