Compare commits

...

3 Commits

Author SHA1 Message Date
Abdo-Gaber
52d905f0b8 PHY: Optimize T-Tracer memory allocation with static thread-local buffers
Replace dynamic per-call memory allocation with static thread-local buffers
for T-Tracer data recording to eliminate malloc/free overhead in the PHY
data path while maintaining thread safety.

Key changes:
- Added static _Thread_local buffers sized for maximum configuration
  (275 RBs × 12 SC × 14 symbols × 1 layers × 1 RX antennas), data recording supports now one layer and 1 Rx antenna
- Removed per-call aligned_alloc() and memset() operations
- Added comprehensive NULL pointer checks before all buffer dereferences
- Applied consistent NULL safety across nr_ulsch_demodulation.c and
  nr_ul_channel_estimation.c

Performance impact:
- Zero allocation overhead when T_TRACER enabled but traces inactive
- Eliminated memset per PUSCH processing
- No runtime cost when traces disabled (NULL pointers only)
- Thread-safe with per-thread buffer isolation

This optimization maintains zero performance impact on 5G NR real-time
processing while enabling robust data recording capabilities for PHY
layer debugging and analysis.
2025-11-27 15:34:43 +01:00
Abdo-Gaber
5cd0785b75 Add error message if supported messages by data recording enabled while #rx_ant larger than 1 2025-09-04 15:23:44 +02:00
Abdo-Gaber
482203c301 Optimize memory allocation of data recording app based on T-Tracer 2025-09-04 13:07:59 +02:00
2 changed files with 46 additions and 32 deletions

View File

@@ -175,9 +175,11 @@ static void nr_pusch_antenna_processing(void *arg)
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS)) {
// Trace channel coefficients
c16_t *pusch_ch_est_dmrs_pos_slot_mem = rdata->pusch_ch_est_dmrs_pos_slot_mem;
int dmrs_symbol_start_idx = rdata->dmrs_symbol_start_idx;
pusch_ch_est_dmrs_pos_slot_mem[dmrs_symbol_start_idx + delta + ch_est_cnt] = ch16; // 0, 2, 4, 6, 8, location of REs
pusch_ch_est_dmrs_pos_slot_mem[dmrs_symbol_start_idx + delta + ch_est_cnt + 2] = ch16; // 0, 2, 4, 6, 8, location of REs
if (pusch_ch_est_dmrs_pos_slot_mem != NULL) {
int dmrs_symbol_start_idx = rdata->dmrs_symbol_start_idx;
pusch_ch_est_dmrs_pos_slot_mem[dmrs_symbol_start_idx + delta + ch_est_cnt] = ch16; // 0, 2, 4, 6, 8, location of REs
pusch_ch_est_dmrs_pos_slot_mem[dmrs_symbol_start_idx + delta + ch_est_cnt + 2] = ch16; // 0, 2, 4, 6, 8, location of REs
}
}
ch_est_cnt += 4;
#endif
@@ -541,7 +543,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
//------------------Write DMRS to Memory for Data Recording ------------------//
int dmrs_symbol_start_idx = symbol * pusch_pdu->nrOfLayers * nb_rb_pusch * NR_NB_SC_PER_RB + nl * nb_rb_pusch * NR_NB_SC_PER_RB;
#if T_TRACER
if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS)) {
if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS) && pusch_dmrs_slot_mem != NULL) {
// used by T-Tracer to trace DMRS slot grid
int dmrs_delta = 0; // intialize it to zero currently, derive it later from above functions
for (int i = 0; i < (6 * nb_rb_pusch); i++) {

View File

@@ -22,6 +22,15 @@ static void copy_c16_data_to_slot_memory(c16_t *src, c16_t *dst_slot, int nb_re_
{
memcpy(&dst_slot[nb_re_pusch * symbol], src, nb_re_pusch * sizeof(c16_t));
}
// Static thread-local buffers for T-Tracer to avoid dynamic allocation overhead
// Sized for maximum configuration: 275 RBs * 12 subcarriers * 14 symbols * 4 layers * 4 RX antennas
// Since data recording app supports only SISO, set nb_layers and nb_rx_ant to 1
#define MAX_TTRACER_SLOT_BUFFER_SIZE (275 * 12 * 14 * 1 * 1)
static _Thread_local c16_t ttracer_pusch_dmrs_slot_mem[MAX_TTRACER_SLOT_BUFFER_SIZE];
static _Thread_local c16_t ttracer_pusch_ch_est_dmrs_pos_slot_mem[MAX_TTRACER_SLOT_BUFFER_SIZE];
static _Thread_local c16_t ttracer_pusch_ch_est_dmrs_interpl_slot_mem[MAX_TTRACER_SLOT_BUFFER_SIZE];
static _Thread_local c16_t ttracer_rxFext_slot_mem[MAX_TTRACER_SLOT_BUFFER_SIZE];
#endif
void nr_idft(int32_t *z, uint32_t Msc_PUSCH)
@@ -946,11 +955,11 @@ static void inner_rx(PHY_VARS_gNB *gNB,
frame_parms);
#if T_TRACER
int nb_re_pusch = NR_NB_SC_PER_RB * rel15_ul->rb_size;
// Assume assume Tx and Rx = 1
if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ)) {
// Assume Tx and Rx = 1
if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ) && rxFext_slot != NULL) {
copy_c16_data_to_slot_memory(rxFext[aarx], rxFext_slot, nb_re_pusch, symbol);
}
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL)) {
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL) && chFext_slot != NULL) {
copy_c16_data_to_slot_memory(chFext[aatx][aarx], chFext_slot, nb_re_pusch, symbol);
}
#endif
@@ -1163,35 +1172,36 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
LOG_D(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos);
// Memories to store data for data recording
int buffer_length_slot = rel15_ul->rb_size * NR_NB_SC_PER_RB * 14; // 14 OFDM Symbols per slot
int nb_rx_ant = frame_parms->nb_antennas_rx;
int nb_layer = rel15_ul->nrOfLayers;
// Initialize memory for DMRS signals
c16_t pusch_dmrs_slot_mem[nb_layer * buffer_length_slot] __attribute__((aligned(32)));
// Initialize memory for channel estimates based on DMRS positions
c16_t pusch_ch_est_dmrs_pos_slot_mem[buffer_length_slot * nb_layer * nb_rx_ant] __attribute__((aligned(32)));
// memory to store slot grid with channel coefficients based on DMRS positions after interpolation
c16_t pusch_ch_est_dmrs_interpl_slot_mem[buffer_length_slot * nb_layer * nb_rx_ant] __attribute__((aligned(32)));
// memory to store extracted data including PUSCH + DMRS
c16_t rxFext_slot_mem[nb_rx_ant * buffer_length_slot] __attribute__((aligned(32)));
// Point to static thread-local buffers or NULL depending on trace activation
c16_t *pusch_dmrs_slot_mem = NULL;
c16_t *pusch_ch_est_dmrs_pos_slot_mem = NULL;
c16_t *pusch_ch_est_dmrs_interpl_slot_mem = NULL;
c16_t *rxFext_slot_mem = NULL;
#if T_TRACER
// Initialize memory for DMRS signals
if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS))
memset(pusch_dmrs_slot_mem, 0, sizeof(c16_t) * nb_layer * buffer_length_slot);
if (nb_rx_ant == 1 && nb_layer == 1) {
// Use static thread-local buffers - no initialization needed as all writes are explicit
if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS))
pusch_dmrs_slot_mem = ttracer_pusch_dmrs_slot_mem;
// Initialize memory for channel estimates based on DMRS positions
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS))
memset(pusch_ch_est_dmrs_pos_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * nb_layer * nb_rx_ant);
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS))
pusch_ch_est_dmrs_pos_slot_mem = ttracer_pusch_ch_est_dmrs_pos_slot_mem;
// memory to store slot grid with channel coefficients based on DMRS positions after interpolation
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL))
memset(pusch_ch_est_dmrs_interpl_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * nb_layer * nb_rx_ant);
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL))
pusch_ch_est_dmrs_interpl_slot_mem = ttracer_pusch_ch_est_dmrs_interpl_slot_mem;
if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ))
rxFext_slot_mem = ttracer_rxFext_slot_mem;
}
else if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS) ||
T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS) ||
T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL) ||
T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ))
LOG_W(PHY, "Error: Data Recording App based on T_TRACER for UL PUSCH supports only 1 Rx antenna\n");
// memory to store extracted data including PUSCH + DMRS
if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ))
memset(rxFext_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * nb_rx_ant);
#endif
//----------------------------------------------------------
@@ -1472,7 +1482,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
// + 9 bytes timestamp = HHMMSSMMM
// Not Ready for MIMO
int dmrs_port = get_dmrs_port(0, rel15_ul->dmrs_ports);
if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS)) {
if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS) && pusch_dmrs_slot_mem != NULL) {
// Log GNB_PHY_UL_FD_DMRS using T-Tracer if activated
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
@@ -1515,7 +1525,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
T_BUFFER((c16_t *)(&(pusch_dmrs_slot_mem[0])), rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4));
}
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS)) {
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS) && pusch_ch_est_dmrs_pos_slot_mem != NULL) {
// Log GNB_PHY_UL_FD_CHAN_EST_DMRS_POS using T-Tracer if activated
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
@@ -1558,7 +1568,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
T_BUFFER((c16_t *)(&(pusch_ch_est_dmrs_pos_slot_mem[0])), rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4));
}
if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ)) {
if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ) && rxFext_slot_mem != NULL) {
// Log GNB_PHY_UL_FD_PUSCH_IQ using T-Tracer if activated
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
@@ -1602,7 +1612,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
T_BUFFER((c16_t *)(&(rxFext_slot_mem[0])),
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * frame_parms->nb_antennas_rx * 4));
}
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL)) {
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL) && pusch_ch_est_dmrs_interpl_slot_mem != NULL) {
// Log pusch_ch_est_dmrs_interpl_slot_mem using T-Tracer if activated
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
@@ -1649,6 +1659,8 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
}
#endif
// No need to free static thread-local buffers
join_task_ans(&ans);
stop_meas(&gNB->rx_pusch_symbol_processing_stats);