Commit 09e114cd authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/oai_ue_performance_v1' into integration_2026_w29

NR_PHY: Optimize layer demapping for PDSCH/PUSCH receiver performance (#286)

Optimizes layer de-mapping in the NR receiver path and refactors the
implementation into a common function shared by both the UE (PDSCH) and
gNB (PUSCH) receive paths.

Commit 1: [NR_UE_PDSCH] Optimize PDSCH layer de-mapping

Uses a switch with a LAYER_DEMAPPING(MO) macro for modulation orders 2,
4, 6, and 8. Since the copy size is now known at compile time, the
compiler can replace memcpy calls with inline fixed-size vector stores.

Commit 2: [NR_PHY] Common layer de-mapping implementation

Extract a common nr_layer_demapping() function for both UE and gNB.
Update the UE and gNB receive paths to use the shared implementation,
reducing code duplication while bringing the same optimization to the
gNB PUSCH path.

With

    ./nr_dlsim -s30 -b106 -R106 -n100 -e25 -x2 -y2 -z2 -P

i.e. 64 QAM, 2 layers case, the layer demapping compute time reduces by ~35x times.

Develop:
    |__ DLSCH_CHANNEL_COMPENSATION_STATS 3.03 us (1300 trials) ( 3.94 total [ms])
    |__ DLSCH_LLR_STATS 17.54 us (100 trials) ( 1.75 total [ms])
    |__ DLSCH_LAYER_DEMAPPING 571.11 us (100 trials) ( 57.11 total [ms])

Post-optimization:
    |__ DLSCH_CHANNEL_COMPENSATION_STATS 2.67 us (1300 trials) ( 3.47 total [ms])
    |__ DLSCH_LLR_STATS 16.50 us (100 trials) ( 1.65 total [ms])
    |__ DLSCH_LAYER_DEMAPPING 16.14 us (100 trials) ( 1.61 total [ms])

Mod     2 Layers (µs)               3 Layers (µs)               4 Layers (µs)
        develop PB      speedup     develop PB      speedup     develop PB      speedup
64 QAM  571.11  16.14   35.39x      649.16  19.92   32.59x      953.22  30.00   31.77x
16 QAM  523.60  8.35    62.71x      651.99  13.39   48.69x      844.49  14.67   57.57x
QPSK    32.43   8.09    4.01x       35.17   9.21    3.82x       63.64   11.44   5.56x

Reviewed-By: Rakesh Mundlamuri <rakesh.mundlamuri@openairinterface.org
Reviewed-by: default avatarBartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
parents a4bdb3b9 680a944c
......@@ -392,11 +392,7 @@ static void nr_pusch_symbol_processing(void *arg)
int16_t *llr_ptr = llrs[0];
if (rel15_ul->nrOfLayers != 1) {
llr_ptr = &rdata->llr[pusch_vars->llr_offset[symbol] * rel15_ul->nrOfLayers];
for (int i = 0; i < (nb_re_pusch); i++)
for (int l = 0; l < rel15_ul->nrOfLayers; l++)
for (int m = 0; m < rel15_ul->qam_mod_order; m++)
llr_ptr[i * rel15_ul->nrOfLayers * rel15_ul->qam_mod_order + l * rel15_ul->qam_mod_order + m] =
llrss[l][i * rel15_ul->qam_mod_order + m];
nr_layer_demapping(rel15_ul->nrOfLayers, rel15_ul->qam_mod_order, nb_re_pusch, llrss, llr_ptr);
}
stop_meas(&rdata->ul_demap);
// unscrambling
......
......@@ -685,34 +685,14 @@ static void nr_dlsch_layer_demapping(const uint8_t Nl,
{
const int s0 = dlsch_config->start_symbol;
const int s1 = dlsch_config->number_symbols;
int k = 0;
switch (Nl) {
case 1:
for (int i = s0; i < (s0 + s1); i++) {
memcpy(llr + k, llr_layers[i][0], re_len[i] * mod_order * sizeof(int16_t));
k += re_len[i] * mod_order;
}
break;
case 2:
case 3:
case 4:
for (int i = s0; i < (s0 + s1); i++) {
int m = 0;
for (int j = 0; j < re_len[i]; j++) {
for (int l = 0; l < Nl; l++) {
memcpy(llr + k, llr_layers[i][l] + m * mod_order, sizeof(int16_t) * mod_order);
k += mod_order;
// if (i<4) printf("length%d: llr_layers[l%d][m%d]=%d: \n",length,l,m,llr_layers[l][i*mod_order+m]);
}
m++;
}
}
break;
default:
AssertFatal(0, "Not supported number of layers %d\n", Nl);
for (int i = s0; i < (s0 + s1); i++) {
int16_t *p_layer[Nl];
for (int l = 0; l < Nl; l++)
p_layer[l] = (int16_t *)llr_layers[i][l];
nr_layer_demapping(Nl, mod_order, re_len[i], p_layer, llr + k);
k += re_len[i] * mod_order * Nl;
}
}
......
......@@ -377,6 +377,22 @@ int nr_get_ssb_start_sc(int scs,
int ssb_sco,
frequency_range_t freq_range);
/**
* @brief Interleave per-layer LLRs into a flat output buffer (layer de-mapping).
*
* For Nl=1 the per-layer LLR array is copied contiguously into llr_out.
* For Nl>1 LLRs are interleaved as: RE0_L0, RE0_L1, ..., RE0_L(Nl-1),
* RE1_L0, ... so that the decoder sees all layers interleaved per RE.
*
* @param Nl Number of layers (1-4)
* @param mod_order Modulation order (2/4/6/8)
* @param nb_re Number of REs in this symbol
* @param llr_layers Per-layer LLR pointers: llr_layers[l] points to
* nb_re * mod_order int16_t values for layer l
* @param llr_out Output flat buffer (nb_re * mod_order * Nl int16_t values)
*/
void nr_layer_demapping(uint8_t Nl, uint8_t mod_order, int nb_re, int16_t **llr_layers, int16_t *llr_out);
#include "nr_channel_compensation.h"
#include "nr_compute_llr.h"
#endif
......@@ -489,3 +489,45 @@ int nr_get_ssb_start_sc(int scs, int ssb_offset_point_a, int ssb_sco, frequency_
return ssb_start_subcarrier;
}
/* Constant MO lets the compiler inline memcpy as fixed-size vector stores */
static inline void layer_demapping(uint8_t Nl, int nb_re, int16_t **llr_layers, int16_t *llr_out, int MO)
{
int k = 0;
for (int j = 0; j < nb_re; j++) {
for (int l = 0; l < Nl; l++) {
memcpy(llr_out + k, llr_layers[l] + j * MO, MO * sizeof(int16_t));
k += MO;
}
}
}
void nr_layer_demapping(uint8_t Nl, uint8_t mod_order, int nb_re, int16_t **llr_layers, int16_t *llr_out)
{
AssertFatal(Nl >= 1 && Nl <= 4, "Unsupported number of layers %d\n", Nl);
if (Nl == 1) {
/* Single layer: one contiguous memcpy, no interleaving needed. */
memcpy(llr_out, llr_layers[0], nb_re * mod_order * sizeof(int16_t));
return;
}
/* Switch on mod_order so MO is a compile-time literal, enabling the compiler
* to inline memcpy as fixed-size vector stores. */
switch (mod_order) {
case 2:
layer_demapping(Nl, nb_re, llr_layers, llr_out, 2);
break;
case 4:
layer_demapping(Nl, nb_re, llr_layers, llr_out, 4);
break;
case 6:
layer_demapping(Nl, nb_re, llr_layers, llr_out, 6);
break;
case 8:
layer_demapping(Nl, nb_re, llr_layers, llr_out, 8);
break;
default:
AssertFatal(0, "Unknown mod_order %d\n", mod_order);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment