This commit is contained in:
2026-09-19 23:28:08 +09:00
parent c50fe1af53
commit 67717ed5c1
43 changed files with 3145 additions and 294 deletions
@@ -86,8 +86,42 @@ static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused)) const
}
#if defined (NGRAN_GNB_DU)
static uldlcounter_t last_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static uldlcounter_t last_total_prbs[MAX_MOBILES_PER_GNB] = {0};
typedef struct ue_uldlcounter {
const NR_UE_info_t *ue;
rnti_t rnti;
uldlcounter_t value;
bool dl_valid;
bool ul_valid;
} ue_uldlcounter_t;
static ue_uldlcounter_t last_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static ue_uldlcounter_t last_total_prbs[MAX_MOBILES_PER_GNB] = {0};
/* The connected UE list is compacted when a UE leaves, so its iteration index
* is not a stable identity. Keep baselines by the MAC-assigned UID instead and
* reset them when that UID is reused for another UE. */
static ue_uldlcounter_t *get_ue_counter(ue_uldlcounter_t counters[MAX_MOBILES_PER_GNB],
const cudu_ue_info_pair_t ue_info)
{
AssertFatal(ue_info.ue != NULL, "KPM UE measurement requires MAC UE information\n");
const uid_t uid = ue_info.ue->uid;
AssertFatal(uid < MAX_MOBILES_PER_GNB, "KPM UE UID %u exceeds maximum %u\n", uid, MAX_MOBILES_PER_GNB);
ue_uldlcounter_t *counter = &counters[uid];
if (counter->ue != ue_info.ue || counter->rnti != ue_info.ue->rnti)
*counter = (ue_uldlcounter_t){.ue = ue_info.ue, .rnti = ue_info.ue->rnti};
return counter;
}
/* A new/reused UE counter and a reset/wrap have no valid preceding sample.
* Establish a fresh baseline and report zero for that single period. */
static uint32_t counter_delta(uint32_t current, uint32_t *previous, bool *valid)
{
const uint32_t delta = *valid && current >= *previous ? current - *previous : 0;
*previous = current;
*valid = true;
return delta;
}
static nr_rlc_statistics_t get_rlc_stats_per_drb(const rnti_t rnti, const int rb_id)
{
@@ -120,8 +154,16 @@ static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused)) const la
meas_record.value = REAL_MEAS_VALUE;
// Get the value of sojourn time at the RLC buffer
meas_record.real_val = rlc.txsdu_avg_time_to_tx; // [μs]
// Report the windowed-average RLC SDU sojourn (mean per-packet wait over the
// last 100 ms), not the instantaneous tx_list HOL snapshot. The snapshot
// (txsdu_wt_us) reads 0 whenever the tx_list is momentarily drained at the
// single sampling instant -- common with bursty DL even at high throughput --
// which systematically under-reports delay (era/load-dependent). The averaging
// accumulator is now activated once (reset guarded to off->on in
// nr_rlc_activate_avg_time_to_tx), so it accumulates continuously instead of
// being wiped on every read; it returns 0 only when no SDU was transmitted in
// the window (genuine idle/starvation).
meas_record.real_val = (double)rlc.txsdu_avg_time_to_tx; // [us] avg RLC SDU sojourn
return meas_record;
}
@@ -132,7 +174,7 @@ static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused)) const la
static meas_record_lst_t fill_DRB_UEThpDl(__attribute__((unused)) const label_info_lst_t label,
uint32_t gran_period_ms,
cudu_ue_info_pair_t ue_info,
const size_t ue_idx,
__attribute__((unused)) const size_t ue_idx,
__attribute__((unused))e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
@@ -142,8 +184,9 @@ static meas_record_lst_t fill_DRB_UEThpDl(__attribute__((unused)) const label_in
meas_record.value = REAL_MEAS_VALUE;
// Calculate DL Thp
meas_record.real_val = (double)(rlc.txpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].dl)*8/gran_period_ms; // [kbps]
last_rlc_pdu_total_bytes[ue_idx].dl = rlc.txpdu_bytes;
ue_uldlcounter_t *counter = get_ue_counter(last_rlc_pdu_total_bytes, ue_info);
const uint32_t bytes = counter_delta(rlc.txpdu_bytes, &counter->value.dl, &counter->dl_valid);
meas_record.real_val = gran_period_ms == 0 ? 0 : (double)bytes * 8 / gran_period_ms; // [kbps]
return meas_record;
}
@@ -154,7 +197,7 @@ static meas_record_lst_t fill_DRB_UEThpDl(__attribute__((unused)) const label_in
static meas_record_lst_t fill_DRB_UEThpUl(__attribute__((unused)) const label_info_lst_t label,
uint32_t gran_period_ms,
cudu_ue_info_pair_t ue_info,
const size_t ue_idx,
__attribute__((unused)) const size_t ue_idx,
__attribute__((unused))e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
@@ -166,8 +209,9 @@ static meas_record_lst_t fill_DRB_UEThpUl(__attribute__((unused)) const label_in
meas_record.value = REAL_MEAS_VALUE;
// Calculate UL Thp
meas_record.real_val = (double)(rlc.rxpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].ul)*8/gran_period_ms; // [kbps]
last_rlc_pdu_total_bytes[ue_idx].ul = rlc.rxpdu_bytes;
ue_uldlcounter_t *counter = get_ue_counter(last_rlc_pdu_total_bytes, ue_info);
const uint32_t bytes = counter_delta(rlc.rxpdu_bytes, &counter->value.ul, &counter->ul_valid);
meas_record.real_val = gran_period_ms == 0 ? 0 : (double)bytes * 8 / gran_period_ms; // [kbps]
return meas_record;
}
@@ -177,7 +221,7 @@ static meas_record_lst_t fill_DRB_UEThpUl(__attribute__((unused)) const label_in
static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused)) const label_info_lst_t label,
__attribute__((unused)) uint32_t gran_period_ms,
cudu_ue_info_pair_t ue_info,
const size_t ue_idx,
__attribute__((unused)) const size_t ue_idx,
e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
@@ -185,8 +229,13 @@ static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused)) const label_i
meas_record.value = INTEGER_MEAS_VALUE;
// Get the number of DL PRBs
meas_record.int_val = (ue_info.ue->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl) * 100 / (node_stats[1].mac_stats.dl.total_prb_aggregate - node_stats[0].mac_stats.dl.total_prb_aggregate); // [%]
last_total_prbs[ue_idx].dl = ue_info.ue->mac_stats.dl.total_rbs;
ue_uldlcounter_t *counter = get_ue_counter(last_total_prbs, ue_info);
const uint32_t ue_delta = counter_delta(ue_info.ue->mac_stats.dl.total_rbs, &counter->value.dl, &counter->dl_valid);
const uint64_t current = node_stats[1].mac_stats.dl.total_prb_aggregate;
const uint64_t previous = node_stats[0].mac_stats.dl.total_prb_aggregate;
const uint64_t total_delta = current >= previous ? current - previous : 0;
const uint64_t percentage = total_delta == 0 ? 0 : (uint64_t)ue_delta * 100 / total_delta;
meas_record.int_val = percentage > 100 ? 100 : percentage; // [%]
return meas_record;
}
@@ -196,7 +245,7 @@ static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused)) const label_i
static meas_record_lst_t fill_RRU_PrbTotUl(__attribute__((unused)) const label_info_lst_t label,
__attribute__((unused)) uint32_t gran_period_ms,
cudu_ue_info_pair_t ue_info,
const size_t ue_idx,
__attribute__((unused)) const size_t ue_idx,
e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
@@ -204,8 +253,13 @@ static meas_record_lst_t fill_RRU_PrbTotUl(__attribute__((unused)) const label_i
meas_record.value = INTEGER_MEAS_VALUE;
// Get the number of UL PRBs
meas_record.int_val = (ue_info.ue->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul) * 100 / (node_stats[1].mac_stats.ul.total_prb_aggregate - node_stats[0].mac_stats.ul.total_prb_aggregate); // [%]
last_total_prbs[ue_idx].ul = ue_info.ue->mac_stats.ul.total_rbs;
ue_uldlcounter_t *counter = get_ue_counter(last_total_prbs, ue_info);
const uint32_t ue_delta = counter_delta(ue_info.ue->mac_stats.ul.total_rbs, &counter->value.ul, &counter->ul_valid);
const uint64_t current = node_stats[1].mac_stats.ul.total_prb_aggregate;
const uint64_t previous = node_stats[0].mac_stats.ul.total_prb_aggregate;
const uint64_t total_delta = current >= previous ? current - previous : 0;
const uint64_t percentage = total_delta == 0 ? 0 : (uint64_t)ue_delta * 100 / total_delta;
meas_record.int_val = percentage > 100 ? 100 : percentage; // [%]
return meas_record;
}