From f5989abd0dd0f40b51b3c1af22592c6f522626d4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 15 Apr 2026 11:12:49 +0200 Subject: [PATCH] Use spsc_q for SRS processing Use the spsc queue to pass jobs from TX thread (scheduler) to RX thread (handling those jobs), reducing the amount spent searching for SRS jobs, clarifying the design, and making it thread-safe. Signed-off-by: Robert Schmidt --- openair1/PHY/INIT/nr_init.c | 8 +-- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 2 +- openair1/PHY/NR_TRANSPORT/srs_rx.c | 38 +++++------- openair1/PHY/defs_gNB.h | 6 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 61 +++++++++++-------- openair1/SIMULATION/NR_PHY/srssim.c | 15 ++--- 6 files changed, 62 insertions(+), 68 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 7d56f8b410..2246fcdde1 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -419,15 +419,13 @@ void init_nr_transport(PHY_VARS_gNB *gNB) buffer_ul_slots = (nb_ul_slots_period < slot_ahead) ? nb_ul_slots_period : slot_ahead; gNB->max_nb_pusch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1; - gNB->max_nb_srs = buffer_ul_slots ? buffer_ul_slots << 1 : 1; // assuming at most 2 SRS per slot int max_nb_pucch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1; gNB->pucch_queue = spsc_q_alloc(max_nb_pucch, sizeof(NR_gNB_PUCCH_job_t)); gNB->pusch_queue = spsc_q_alloc(gNB->max_nb_pusch, sizeof(NR_gNB_PUSCH_job_t)); - gNB->srs = (NR_gNB_SRS_t *)malloc16(gNB->max_nb_srs * sizeof(NR_gNB_SRS_t)); - for (int i = 0; i < gNB->max_nb_srs; i++) - gNB->srs[i].active = 0; + int max_nb_srs = buffer_ul_slots ? buffer_ul_slots << 1 : 1; // assuming at most 2 SRS per slot + gNB->srs_queue = spsc_q_alloc(max_nb_srs, sizeof(NR_gNB_SRS_job_t)); gNB->ulsch = (NR_gNB_ULSCH_t *)malloc16(gNB->max_nb_pusch * sizeof(NR_gNB_ULSCH_t)); for (int i = 0; i < gNB->max_nb_pusch; i++) { @@ -446,7 +444,7 @@ void reset_nr_transport(PHY_VARS_gNB *gNB) spsc_q_free(&gNB->pucch_queue); spsc_q_free(&gNB->pusch_queue); - free(gNB->srs); + spsc_q_free(&gNB->srs_queue); for (int i = 0; i < gNB->max_nb_pusch; i++) free_gNB_ulsch(&gNB->ulsch[i], fp->N_RB_UL); diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 54acd23351..32efa979cc 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -209,7 +209,7 @@ nr_srs_info_t nr_srs_rx_procedures(PHY_VARS_gNB *gNB, uint8_t N_ap, uint8_t N_symb_SRS, uint16_t ofdm_symbol_size, - const NR_gNB_SRS_t *srs, + const NR_gNB_SRS_job_t *srs, int *srs_est, int8_t *snr, c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS], diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 96695909a9..b0436cb2d7 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -29,31 +29,21 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu_t *srs_pdu) { - bool found = false; - for (int i = 0; i < gNB->max_nb_srs; i++) { - NR_gNB_SRS_t *srs = &gNB->srs[i]; - if (srs->active == false) { - found = true; - srs->frame = frame; - srs->slot = slot; - srs->active = true; - srs->beam_nb = 0; - if (gNB->common_vars.beam_id) { - const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position; - int bitmap = SL_to_bitmap(l0, 1 << srs_pdu->num_symbols); - int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; - srs->beam_nb = beam_index_allocation(gNB->enable_analog_das, - fapi_beam_idx, - &gNB->common_vars, - slot, - gNB->frame_parms.symbols_per_slot, - bitmap); - } - memcpy((void *)&srs->srs_pdu, (void *)srs_pdu, sizeof(nfapi_nr_srs_pdu_t)); - break; - } + NR_gNB_SRS_job_t srs = {.frame = frame, .slot = slot, .srs_pdu = *srs_pdu}; + if (gNB->common_vars.beam_id) { + const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position; + int bitmap = SL_to_bitmap(l0, 1 << srs_pdu->num_symbols); + int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; + srs.beam_nb = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, + &gNB->common_vars, + slot, + gNB->frame_parms.symbols_per_slot, + bitmap); } - AssertFatal(found, "SRS list is full\n"); + bool found = spsc_q_put(&gNB->srs_queue, &srs, sizeof(srs)); + if (!found) + LOG_W(NR_PHY, "SRS list is full: dropping SRS UE %04x\n", srs_pdu->rnti); } int nr_get_srs_signal(PHY_VARS_gNB *gNB, diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 20e820a298..479a214418 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -208,7 +208,6 @@ typedef struct { } NR_gNB_PUCCH_job_t; typedef struct { - bool active; // identifier for concurrent beams int beam_nb; /// Frame where current SRS pdu was received @@ -217,7 +216,7 @@ typedef struct { uint32_t slot; /// ULSCH PDU nfapi_nr_srs_pdu_t srs_pdu; -} NR_gNB_SRS_t; +} NR_gNB_SRS_job_t; typedef struct { /// \brief Pointers (dynamic) to the received data in the frequency domain. @@ -375,7 +374,6 @@ typedef struct PHY_VARS_gNB_s { nfapi_nr_ul_tti_request_t UL_tti_req; - int max_nb_srs; int max_nb_pdsch; int max_nb_pusch; @@ -387,7 +385,7 @@ typedef struct PHY_VARS_gNB_s { NR_gNB_PUSCH *pusch_vars; spsc_q_t pucch_queue; spsc_q_t pusch_queue; - NR_gNB_SRS_t *srs; + spsc_q_t srs_queue; NR_gNB_ULSCH_t *ulsch; NR_gNB_PHY_STATS_t phy_stats[MAX_MOBILES_PER_GNB]; t_nrPolar_params **polarParams; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 3c9f3fcf02..f9a1100724 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -536,7 +536,9 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, const NR_gNB_PUCCH_job_t *pucch, int n_pucch, const NR_gNB_PUSCH_job_t *pusch, - int n_pusch) + int n_pusch, + const NR_gNB_SRS_job_t *srs, + int n_srs) { for (int symbol = 0; symbol < 14; symbol++) { for (int m = 0; m < 9; m++) { @@ -581,11 +583,8 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, } } - for (int i = 0; i < gNB->max_nb_srs; i++) { - NR_gNB_SRS_t *srs = &gNB->srs[i]; - if (!(srs && srs->active && srs->frame == now.f && srs->slot == now.s)) - continue; - nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + for (int i = 0; i < n_srs; i++) { + const nfapi_nr_srs_pdu_t *srs_pdu = &srs[i].srs_pdu; const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position; for (int symbol = 0; symbol < (1 << srs_pdu->num_symbols); symbol++) { for (int rb = srs_pdu->bwp_start; rb < (srs_pdu->bwp_start + srs_pdu->bwp_size); rb++) { @@ -703,7 +702,7 @@ nr_srs_info_t nr_srs_rx_procedures(PHY_VARS_gNB *gNB, uint8_t N_ap, uint8_t N_symb_SRS, uint16_t ofdm_symbol_size, - const NR_gNB_SRS_t *srs, + const NR_gNB_SRS_job_t *srs, int *srs_est, int8_t *snr, c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS], @@ -875,7 +874,7 @@ nr_srs_info_t nr_srs_rx_procedures(PHY_VARS_gNB *gNB, return nr_srs_info; } -static void handle_srs(fsn_t now, PHY_VARS_gNB *gNB, const NR_gNB_SRS_t *srs, nfapi_nr_srs_indication_pdu_t *srs_indication) +static void handle_srs(fsn_t now, PHY_VARS_gNB *gNB, const NR_gNB_SRS_job_t *srs, nfapi_nr_srs_indication_pdu_t *srs_indication) { const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; const uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; @@ -1137,6 +1136,25 @@ static bool get_current_pusch(const void *data, void *user) return fsn_equal(t, *now); } +static bool drop_old_srs(const void *data, void *user) +{ + const NR_gNB_SRS_job_t *srs = data; + const fsn_t *now = user; + const fsn_t t = {srs->frame, srs->slot, now->mu}; + bool drop = fsn_in_the_past(t, *now); + if (drop) + LOG_E(NR_PHY, "%4d.%2d SRS job for UE %04x is in the past (%4d.%2d)\n", now->f, now->s, srs->srs_pdu.rnti, t.f, t.s); + return drop; +} + +static bool get_current_srs(const void *data, void *user) +{ + const NR_gNB_SRS_job_t *srs = data; + const fsn_t *now = user; + const fsn_t t = {srs->frame, srs->slot, now->mu}; + return fsn_equal(t, *now); +} + static int find_nr_ulsch_idx(PHY_VARS_gNB *gNB, uint16_t rnti, int pid) { AssertFatal(gNB != NULL, "gNB is null\n"); @@ -1201,6 +1219,10 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N NR_gNB_PUSCH_job_t pusch[MAX_UL_PDUS_PER_SLOT]; int n_pusch_jobs = spsc_q_get_while(&gNB->pusch_queue, get_current_pusch, &now, pusch, sizeof(*pusch), MAX_UL_PDUS_PER_SLOT); + spsc_q_drop_while(&gNB->srs_queue, drop_old_srs, &now); + NR_gNB_SRS_job_t srs[MAX_NUM_NR_SRS_PDUS]; + int n_srs = spsc_q_get_while(&gNB->srs_queue, get_current_srs, &now, srs, sizeof(*srs), MAX_NUM_NR_SRS_PDUS); + LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx); { // Mask of occupied RBs, per symbol and PRB @@ -1208,7 +1230,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N nfapi_nr_max_num_of_symbol_per_slot_t *slot_conf = NULL; if (frame_parms->frame_type == TDD) slot_conf = gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list; - fill_ul_rb_mask(gNB, now, rb_mask_ul, slot_conf, pucch, n_pucch, pusch, n_pusch_jobs); + fill_ul_rb_mask(gNB, now, rb_mask_ul, slot_conf, pucch, n_pucch, pusch, n_pusch_jobs, srs, n_srs); int first_symb = 0, num_symb = 0; if (frame_parms->frame_type == TDD) @@ -1273,22 +1295,13 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N if (gNB->max_nb_pusch == 1) stop_meas(&gNB->ulsch_decoding_stats); - for (int i = 0; i < gNB->max_nb_srs; i++) { - NR_gNB_SRS_t *srs = &gNB->srs[i]; - if (!(srs && srs->active && srs->frame == frame_rx && srs->slot == slot_rx)) - continue; - LOG_D(NR_PHY, "(%d.%d) gNB is waiting for SRS, id = %i\n", frame_rx, slot_rx, i); - + UL_INFO->srs_ind.sfn = frame_rx; + UL_INFO->srs_ind.slot = slot_rx; + UL_INFO->srs_ind.pdu_list = UL_INFO->srs_pdu_list; + UL_INFO->srs_ind.number_of_pdus = n_srs; + for (int i = 0; i < n_srs; ++i) { start_meas(&gNB->rx_srs_stats); - - UL_INFO->srs_ind.sfn = frame_rx; - UL_INFO->srs_ind.slot = slot_rx; - UL_INFO->srs_ind.pdu_list = UL_INFO->srs_pdu_list; - nfapi_nr_srs_indication_pdu_t *srs_indication = UL_INFO->srs_pdu_list + UL_INFO->srs_ind.number_of_pdus++; - - handle_srs(now, gNB, srs, srs_indication); - - srs->active = false; + handle_srs(now, gNB, &srs[i], &UL_INFO->srs_ind.pdu_list[i]); stop_meas(&gNB->rx_srs_stats); } diff --git a/openair1/SIMULATION/NR_PHY/srssim.c b/openair1/SIMULATION/NR_PHY/srssim.c index 144bce1ab9..0ab34dac47 100644 --- a/openair1/SIMULATION/NR_PHY/srssim.c +++ b/openair1/SIMULATION/NR_PHY/srssim.c @@ -435,11 +435,7 @@ int main(int argc, char *argv[]) .beamforming.num_prgs = m_SRS[srs_pdu.config_index], .beamforming.prg_size = 1}; - gNB->srs->srs_pdu = srs_pdu; - gNB->srs->active = true; - gNB->srs->beam_nb = 0; - gNB->srs->frame = frame; - gNB->srs->slot = slot; + NR_gNB_SRS_job_t srs_job = {.frame = frame, .slot = slot, .srs_pdu = srs_pdu}; // Configure SRS parameters at UE fapi_nr_ul_config_srs_pdu srs_config_pdu = {.rnti = srs_pdu.rnti, @@ -559,10 +555,9 @@ int main(int argc, char *argv[]) //----------- UE RX SRS procedures --------------------- start_meas(&gNB->rx_srs_stats); - NR_gNB_SRS_t *srs = &gNB->srs[0]; - uint8_t N_symb_SRS = 1 << srs->srs_pdu.num_symbols; - uint8_t N_ap = 1 << srs->srs_pdu.num_ant_ports; - int16_t snr_per_rb[srs->srs_pdu.bwp_size]; + uint8_t N_symb_SRS = 1 << srs_pdu.num_symbols; + uint8_t N_ap = 1 << srs_pdu.num_ant_ports; + int16_t snr_per_rb[srs_pdu.bwp_size]; uint16_t timing_advance_offset; int16_t timing_advance_offset_nsec[n_rx]; int srs_est; @@ -576,7 +571,7 @@ int main(int argc, char *argv[]) N_ap, N_symb_SRS, ofdm_symbol_size, - srs, + &srs_job, &srs_est, &snr, srs_estimated_channel_freq,