From 31b8d98bb543cec5aa4257a0f42406fc1ed0e9b2 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 9 Dec 2024 12:45:42 +0100 Subject: [PATCH 1/6] Formating for PHY_ofdm_mod --- openair1/PHY/MODULATION/ofdm_mod.c | 119 ++++++++++++++--------------- 1 file changed, 57 insertions(+), 62 deletions(-) diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index de19d30819..4d0abf7b61 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -122,36 +122,43 @@ void nr_normal_prefix_mod(c16_t *txdataF, c16_t *txdata, uint8_t nsymb, const NR } -void PHY_ofdm_mod(int *input, /// pointer to complex input - int *output, /// pointer to complex output - int fftsize, /// FFT_SIZE - unsigned char nb_symbols, /// number of OFDM symbols - unsigned short nb_prefix_samples, /// cyclic prefix length - Extension_t etype /// type of extension - ) +void PHY_ofdm_mod(int *input, /// pointer to complex input + int *output, /// pointer to complex output + int fftsize, /// FFT_SIZE + unsigned char nb_symbols, /// number of OFDM symbols + unsigned short nb_prefix_samples, /// cyclic prefix length + Extension_t etype /// type of extension +) { + if (nb_symbols == 0) + return; - if(nb_symbols == 0) return; + int16_t temp[2 * 2 * 6144 * 4] __attribute__((aligned(32))); + int i, j; - int16_t temp[2*2*6144*4] __attribute__((aligned(32))); - int i,j; + volatile int *output_ptr = (int *)0; - volatile int *output_ptr=(int*)0; - - int *temp_ptr=(int*)0; + int *temp_ptr = (int *)0; idft_size_idx_t idft_size = get_idft(fftsize); #ifdef DEBUG_OFDM_MOD printf("[PHY] OFDM mod (size %d,prefix %d) Symbols %d, input %p, output %p\n", - fftsize,nb_prefix_samples,nb_symbols,input,output); + fftsize, + nb_prefix_samples, + nb_symbols, + input, + output); #endif - - - for (i=0; i %p)\n",i,nb_symbols,i*fftsize+(i*nb_prefix_samples),input,&input[i*fftsize],&output[(i*fftsize) + ((i)*nb_prefix_samples)]); + printf("[PHY] symbol %d/%d offset %d (%p,%p -> %p)\n", + i, + nb_symbols, + i * fftsize + (i * nb_prefix_samples), + input, + &input[i * fftsize], + &output[(i * fftsize) + ((i)*nb_prefix_samples)]); #endif // on AVX2 need 256-bit alignment @@ -161,70 +168,58 @@ void PHY_ofdm_mod(int *input, /// pointer to complex input // Note: will have to adjust for synchronization offset! switch (etype) { - case CYCLIC_PREFIX: - output_ptr = &output[(i*fftsize) + ((1+i)*nb_prefix_samples)]; - temp_ptr = (int *)temp; + case CYCLIC_PREFIX: + output_ptr = &output[(i * fftsize) + ((1 + i) * nb_prefix_samples)]; + temp_ptr = (int *)temp; + // msg("Doing cyclic prefix method\n"); - // msg("Doing cyclic prefix method\n"); + { + memcpy((void *)output_ptr, (void *)temp_ptr, fftsize << 2); + } + memcpy((void *)&output_ptr[-nb_prefix_samples], (void *)&output_ptr[fftsize - nb_prefix_samples], nb_prefix_samples << 2); + break; - { - memcpy((void*)output_ptr,(void*)temp_ptr,fftsize<<2); - } - memcpy((void*)&output_ptr[-nb_prefix_samples],(void*)&output_ptr[fftsize-nb_prefix_samples],nb_prefix_samples<<2); - break; + case CYCLIC_SUFFIX: - case CYCLIC_SUFFIX: + output_ptr = &output[(i * fftsize) + (i * nb_prefix_samples)]; + temp_ptr = (int *)temp; - output_ptr = &output[(i*fftsize)+ (i*nb_prefix_samples)]; + // msg("Doing cyclic suffix method\n"); - temp_ptr = (int *)temp; + for (j = 0; j < fftsize; j++) { + output_ptr[j] = temp_ptr[2 * j]; + } - // msg("Doing cyclic suffix method\n"); + for (j = 0; j < nb_prefix_samples; j++) + output_ptr[fftsize + j] = output_ptr[j]; - for (j=0; j Date: Mon, 9 Dec 2024 12:56:56 +0100 Subject: [PATCH 2/6] Optimize PHY_ofdm_mod CYCLIC_PREFIX in case of incidentally aligned pointers It seems that the cyclic prefix is in most cases a multiple of 512 samples. This means that in most cases the idft output pointer is already aligned and there is no need to perform an extra memcpy. This saves the memcpy time in most cyclic prefix insertion cases. --- openair1/PHY/MODULATION/ofdm_mod.c | 57 +++++++++++++++--------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 4d0abf7b61..61487eb433 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -133,12 +133,6 @@ void PHY_ofdm_mod(int *input, /// pointer to complex input if (nb_symbols == 0) return; - int16_t temp[2 * 2 * 6144 * 4] __attribute__((aligned(32))); - int i, j; - - volatile int *output_ptr = (int *)0; - - int *temp_ptr = (int *)0; idft_size_idx_t idft_size = get_idft(fftsize); #ifdef DEBUG_OFDM_MOD @@ -150,7 +144,7 @@ void PHY_ofdm_mod(int *input, /// pointer to complex input output); #endif - for (i = 0; i < nb_symbols; i++) { + for (int i = 0; i < nb_symbols; i++) { #ifdef DEBUG_OFDM_MOD printf("[PHY] symbol %d/%d offset %d (%p,%p -> %p)\n", i, @@ -162,57 +156,62 @@ void PHY_ofdm_mod(int *input, /// pointer to complex input #endif // on AVX2 need 256-bit alignment - idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1); // Copy to frame buffer with Cyclic Extension // Note: will have to adjust for synchronization offset! switch (etype) { - case CYCLIC_PREFIX: - output_ptr = &output[(i * fftsize) + ((1 + i) * nb_prefix_samples)]; - temp_ptr = (int *)temp; - - // msg("Doing cyclic prefix method\n"); - - { - memcpy((void *)output_ptr, (void *)temp_ptr, fftsize << 2); + case CYCLIC_PREFIX: { + int *output_ptr = &output[(i * fftsize) + ((1 + i) * nb_prefix_samples)]; + if ((uintptr_t)output_ptr % 32 == 0) { + // output ptr is aligned, do ifft inplace + idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)output_ptr, 1); + } else { + // output ptr is not aligned, needs an extra memcpy + c16_t temp[fftsize] __attribute__((aligned(32))); + idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1); + memcpy((void *)output_ptr, (void *)temp, fftsize << 2); } + // perform cyclic prefix insertion memcpy((void *)&output_ptr[-nb_prefix_samples], (void *)&output_ptr[fftsize - nb_prefix_samples], nb_prefix_samples << 2); break; + } - case CYCLIC_SUFFIX: + case CYCLIC_SUFFIX: { + c16_t temp[fftsize] __attribute__((aligned(32))); + idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1); + int *output_ptr = &output[(i * fftsize) + (i * nb_prefix_samples)]; - output_ptr = &output[(i * fftsize) + (i * nb_prefix_samples)]; - - temp_ptr = (int *)temp; + int *temp_ptr = (int *)temp; // msg("Doing cyclic suffix method\n"); - for (j = 0; j < fftsize; j++) { + for (int j = 0; j < fftsize; j++) { output_ptr[j] = temp_ptr[2 * j]; } - for (j = 0; j < nb_prefix_samples; j++) + for (int j = 0; j < nb_prefix_samples; j++) output_ptr[fftsize + j] = output_ptr[j]; - break; + } case ZEROS: break; - case NONE: - + case NONE: { + c16_t temp[fftsize] __attribute__((aligned(32))); + idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1); // msg("NO EXTENSION!\n"); - output_ptr = &output[fftsize]; + int *output_ptr = &output[fftsize]; - temp_ptr = (int *)temp; + int *temp_ptr = (int *)temp; - for (j = 0; j < fftsize; j++) { + for (int j = 0; j < fftsize; j++) { output_ptr[j] = temp_ptr[2 * j]; } - break; + } default: break; From b92ee59d419443efca4f423760e97d3af0c8bb5f Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 16 Dec 2024 15:21:11 +0100 Subject: [PATCH 3/6] Fix instrumentation target for old CMake versions Older make versions do not support source files to be added to INTERFACE type target. The source file is not needed there so it was removed. --- common/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 229c93b043..f58880b04a 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -3,7 +3,7 @@ add_subdirectory(config/yaml) configure_file(oai_version.h.in oai_version.h @ONLY) -add_library(instrumentation INTERFACE instrumentation.h) +add_library(instrumentation INTERFACE) target_include_directories(instrumentation INTERFACE .) if (TRACY_ENABLE) target_link_libraries(instrumentation INTERFACE Tracy::TracyClient) From 5ab9bd95bd29a4a0ed63c29abee7720a71e18eaf Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 16 Dec 2024 15:22:09 +0100 Subject: [PATCH 4/6] Add `const` to input argument in PHY_ofdm_mod --- openair1/PHY/MODULATION/modulation_common.h | 2 +- openair1/PHY/MODULATION/ofdm_mod.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/MODULATION/modulation_common.h b/openair1/PHY/MODULATION/modulation_common.h index a131cdae63..df521b10da 100644 --- a/openair1/PHY/MODULATION/modulation_common.h +++ b/openair1/PHY/MODULATION/modulation_common.h @@ -38,7 +38,7 @@ @param nb_prefix_samples The number of prefix/suffix/zero samples @param etype Type of extension (CYCLIC_PREFIX,CYCLIC_SUFFIX,ZEROS) */ -void PHY_ofdm_mod(int *input, +void PHY_ofdm_mod(const int *input, int *output, int fftsize, unsigned char nb_symbols, diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 61487eb433..31c056b712 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -122,7 +122,7 @@ void nr_normal_prefix_mod(c16_t *txdataF, c16_t *txdata, uint8_t nsymb, const NR } -void PHY_ofdm_mod(int *input, /// pointer to complex input +void PHY_ofdm_mod(const int *input, /// pointer to complex input int *output, /// pointer to complex output int fftsize, /// FFT_SIZE unsigned char nb_symbols, /// number of OFDM symbols From 9e6c0c8c78848b2a6343ca974c83c87394e38715 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 16 Dec 2024 15:37:56 +0100 Subject: [PATCH 5/6] Fix unused code paths in PHY_ofdm_mod For completeness sake, unused CYCLIC_SUFFIX and NONE extension types were fixed to match CYCLIC_PREFIX memcpy usage. --- openair1/PHY/MODULATION/ofdm_mod.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 31c056b712..595c4ce996 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -170,10 +170,10 @@ void PHY_ofdm_mod(const int *input, /// pointer to complex input // output ptr is not aligned, needs an extra memcpy c16_t temp[fftsize] __attribute__((aligned(32))); idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1); - memcpy((void *)output_ptr, (void *)temp, fftsize << 2); + memcpy((void *)output_ptr, (void *)temp, sizeof(temp)); } // perform cyclic prefix insertion - memcpy((void *)&output_ptr[-nb_prefix_samples], (void *)&output_ptr[fftsize - nb_prefix_samples], nb_prefix_samples << 2); + memcpy((void *)&output_ptr[-nb_prefix_samples], (void *)&output_ptr[fftsize - nb_prefix_samples], nb_prefix_samples * sizeof(c16_t)); break; } @@ -181,17 +181,8 @@ void PHY_ofdm_mod(const int *input, /// pointer to complex input c16_t temp[fftsize] __attribute__((aligned(32))); idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1); int *output_ptr = &output[(i * fftsize) + (i * nb_prefix_samples)]; - - int *temp_ptr = (int *)temp; - - // msg("Doing cyclic suffix method\n"); - - for (int j = 0; j < fftsize; j++) { - output_ptr[j] = temp_ptr[2 * j]; - } - - for (int j = 0; j < nb_prefix_samples; j++) - output_ptr[fftsize + j] = output_ptr[j]; + memcpy(output_ptr, temp, sizeof(temp)); + memcpy(&output_ptr[fftsize], temp, nb_prefix_samples * sizeof(c16_t)); break; } @@ -202,14 +193,8 @@ void PHY_ofdm_mod(const int *input, /// pointer to complex input case NONE: { c16_t temp[fftsize] __attribute__((aligned(32))); idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1); - // msg("NO EXTENSION!\n"); - int *output_ptr = &output[fftsize]; - - int *temp_ptr = (int *)temp; - - for (int j = 0; j < fftsize; j++) { - output_ptr[j] = temp_ptr[2 * j]; - } + int *output_ptr = &output[i * fftsize]; + memcpy(output_ptr, temp, sizeof(temp)); break; } From 55b5e04e8ddaa77c6a2b5be2290f4e726ef068b5 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 17 Dec 2024 11:02:40 +0100 Subject: [PATCH 6/6] Change alignment of temporary IDFT buffer in PHY_ofdm_mod Alignment of temporary IDFT buffer was changed to 64 bytes. This is in preparation for possible use of different IDFT implementation which could use AVX-512, requiring 64-byte alignment. --- openair1/PHY/MODULATION/ofdm_mod.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 595c4ce996..e25f7cd7f2 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -40,6 +40,9 @@ This section deals with basic functions for OFDM Modulation. #include "PHY/LTE_TRANSPORT/transport_common_proto.h" //#define DEBUG_OFDM_MOD +// Use 64-byte alignment for IDFT output buffer to ensure no +// runtime error in case IDFT implementation uses AVX-512. +#define IDFT_OUTPUT_BUFFER_ALIGNMENT 64 void normal_prefix_mod(int32_t *txdataF,int32_t *txdata,uint8_t nsymb,LTE_DL_FRAME_PARMS *frame_parms) { @@ -163,12 +166,13 @@ void PHY_ofdm_mod(const int *input, /// pointer to complex input switch (etype) { case CYCLIC_PREFIX: { int *output_ptr = &output[(i * fftsize) + ((1 + i) * nb_prefix_samples)]; + // Current idft implementation uses AVX-256: Check if buffer is already aligned to 256 bits (32 bytes) if ((uintptr_t)output_ptr % 32 == 0) { // output ptr is aligned, do ifft inplace idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)output_ptr, 1); } else { // output ptr is not aligned, needs an extra memcpy - c16_t temp[fftsize] __attribute__((aligned(32))); + c16_t temp[fftsize] __attribute__((aligned(IDFT_OUTPUT_BUFFER_ALIGNMENT))); idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1); memcpy((void *)output_ptr, (void *)temp, sizeof(temp)); } @@ -178,7 +182,8 @@ void PHY_ofdm_mod(const int *input, /// pointer to complex input } case CYCLIC_SUFFIX: { - c16_t temp[fftsize] __attribute__((aligned(32))); + // Use alignment of 64 bytes + c16_t temp[fftsize] __attribute__((aligned(IDFT_OUTPUT_BUFFER_ALIGNMENT))); idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1); int *output_ptr = &output[(i * fftsize) + (i * nb_prefix_samples)]; memcpy(output_ptr, temp, sizeof(temp)); @@ -191,7 +196,7 @@ void PHY_ofdm_mod(const int *input, /// pointer to complex input break; case NONE: { - c16_t temp[fftsize] __attribute__((aligned(32))); + c16_t temp[fftsize] __attribute__((aligned(IDFT_OUTPUT_BUFFER_ALIGNMENT))); idft(idft_size, (int16_t *)&input[i * fftsize], (int16_t *)temp, 1); int *output_ptr = &output[i * fftsize]; memcpy(output_ptr, temp, sizeof(temp));