diff --git a/CMakeLists.txt b/CMakeLists.txt index 94c49f8922..df3ad3d211 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1017,6 +1017,7 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_csi_rs.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_scrambling.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/scrambling_luts.c + ${OPENAIR1_DIR}/PHY/NR_REFSIG/refsig.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c ) diff --git a/openair1/PHY/NR_REFSIG/nr_gold_ue.c b/openair1/PHY/NR_REFSIG/nr_gold_ue.c index 3259aa3173..424ee8e650 100644 --- a/openair1/PHY/NR_REFSIG/nr_gold_ue.c +++ b/openair1/PHY/NR_REFSIG/nr_gold_ue.c @@ -20,6 +20,7 @@ */ #include "refsig_defs_ue.h" +#include "openair1/PHY/LTE_TRANSPORT/transport_proto.h" // for lte_gold_generic() void nr_gold_pbch(uint32_t nr_gold_pbch[2][64][NR_PBCH_DMRS_LENGTH_DWORD], int Nid, int Lmax) { diff --git a/openair1/PHY/NR_REFSIG/nr_refsig.h b/openair1/PHY/NR_REFSIG/nr_refsig.h index ffdb347656..ccae9cc629 100644 --- a/openair1/PHY/NR_REFSIG/nr_refsig.h +++ b/openair1/PHY/NR_REFSIG/nr_refsig.h @@ -25,6 +25,7 @@ #define __NR_REFSIG__H__ #include "PHY/defs_gNB.h" +#include "openair1/PHY/NR_REFSIG/nr_refsig_common.h" #include "PHY/LTE_REFSIG/lte_refsig.h" #include "PHY/sse_intrin.h" diff --git a/openair1/PHY/NR_REFSIG/nr_refsig_common.h b/openair1/PHY/NR_REFSIG/nr_refsig_common.h new file mode 100644 index 0000000000..303b1d7aa5 --- /dev/null +++ b/openair1/PHY/NR_REFSIG/nr_refsig_common.h @@ -0,0 +1,32 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* Definitions for NR Reference signals */ + +#ifndef __NR_REFSIG_COMMON_H__ +#define __NR_REFSIG_COMMON_H__ + +struct NR_DL_FRAME_PARMS; +typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; + +uint32_t *gold_cache(uint32_t key, int length); + +#endif diff --git a/openair1/PHY/NR_REFSIG/refsig.c b/openair1/PHY/NR_REFSIG/refsig.c new file mode 100644 index 0000000000..80fe2a6dc3 --- /dev/null +++ b/openair1/PHY/NR_REFSIG/refsig.c @@ -0,0 +1,166 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "nr_refsig.h" +#include "openair1/PHY/LTE_TRANSPORT/transport_proto.h" // for lte_gold_generic() + +#define REFRESH_RATE (1000 * 100) + +typedef struct { + int key; + int length; + int usage; +} gold_cache_t; + +typedef struct { + uint32_t *table; + uint32_t tblSz; + int calls; + int iterate; +} gold_cache_table_t; +static const int roundedHeaderSz = (((sizeof(gold_cache_t) + 63) / 64) * 64) / sizeof(uint32_t); +static const int grain = 64 / sizeof(uint32_t); + +// Allocate, also reorder to have the most frequent first, so the cache search is optimized +static void refresh_table(gold_cache_table_t *t, int sizeIncrease) +{ + uint32_t *old = t->table; + uint oldSz = t->tblSz; + if (t->tblSz == 0) + t->tblSz = PAGE_SIZE / sizeof(*t->table); + if (sizeIncrease) + t->tblSz += max(sizeIncrease, PAGE_SIZE / sizeof(*t->table)); + int ret = posix_memalign((void **)&t->table, 64, t->tblSz * sizeof(*t->table)); + AssertFatal(ret == 0, "No more memory"); + LOG_D(PHY, + "re-organize gold sequence table to %lu pages of memory calls since last reorder: %d, search rate: %f\n", + t->tblSz * sizeof(*t->table) / PAGE_SIZE, + t->calls, + t->calls ? t->iterate / (float)t->calls : 0.0); + int maxUsage; + uint32_t *currentTmp = t->table; + do { + maxUsage = 0; + gold_cache_t *entryToCopy = NULL; + for (uint32_t *searchmax = old; searchmax < old + oldSz; searchmax += roundedHeaderSz) { + gold_cache_t *tbl = (gold_cache_t *)searchmax; + if (!tbl->length) + break; + if (tbl->usage > maxUsage) { + maxUsage = tbl->usage; + entryToCopy = tbl; + } + searchmax += tbl->length; + } + if (maxUsage) { + memcpy(currentTmp, entryToCopy, (roundedHeaderSz + entryToCopy->length) * sizeof(*t->table)); + currentTmp += roundedHeaderSz + entryToCopy->length; + entryToCopy->usage = 0; + } + } while (maxUsage); + const uint usedSz = currentTmp - t->table; + memset(t->table + usedSz, 0, (t->tblSz - usedSz) * sizeof(*t->table)); + free(old); + t->calls = 0; + t->iterate = 0; + return; +} + +static pthread_key_t gold_table_key; +static pthread_once_t gold_key_once = PTHREAD_ONCE_INIT; + +static void delete_table(void *ptr) +{ + gold_cache_table_t *table = (gold_cache_table_t *)ptr; + if (table->table) + free(table->table); + free(ptr); +} + +static void make_table_key() +{ + (void)pthread_key_create(&gold_table_key, delete_table); +} + +uint32_t *gold_cache(uint32_t key, int length) +{ + (void)pthread_once(&gold_key_once, make_table_key); + gold_cache_table_t *tableCache; + if ((tableCache = pthread_getspecific(gold_table_key)) == NULL) { + tableCache = calloc(1, sizeof(gold_cache_table_t)); + (void)pthread_setspecific(gold_table_key, tableCache); + } + + // align for AVX512 + length = ((length + grain - 1) / grain) * grain; + tableCache->calls++; + + // periodic refresh + if (tableCache->calls > REFRESH_RATE) + refresh_table(tableCache, 0); + + uint32_t *ptr = tableCache->table; + // check if already cached + for (; ptr < tableCache->table + tableCache->tblSz; ptr += roundedHeaderSz) { + gold_cache_t *tbl = (gold_cache_t *)ptr; + tableCache->iterate++; + if (tbl->length >= length && tbl->key == key) { + tbl->usage++; + return ptr + roundedHeaderSz; + } + if (tbl->key == key) { + // We use a longer sequence, same key + // let's delete the shorter and force reorganize + tbl->usage = 0; + tableCache->calls += REFRESH_RATE; + } + if (!tbl->length) + break; + ptr += tbl->length; + } + + // not enough space in the table + if (!ptr || ptr > tableCache->table + tableCache->tblSz - (2 * roundedHeaderSz + length)) + refresh_table(tableCache, 2 * roundedHeaderSz + length); + + // We will add a new entry + uint32_t *firstFree; + int size = 0; + for (firstFree = tableCache->table; firstFree < tableCache->table + tableCache->tblSz; firstFree += roundedHeaderSz) { + gold_cache_t *tbl = (gold_cache_t *)firstFree; + if (!tbl->length) + break; + firstFree += tbl->length; + size++; + } + if (!tableCache->calls) + LOG_D(PHY, "Number of entries (after reorganization) in gold cache: %d\n", size); + + gold_cache_t *new = (gold_cache_t *)firstFree; + *new = (gold_cache_t){.key = key, .length = length, .usage = 1}; + unsigned int x1 = 0, x2 = key; + uint32_t *sequence = firstFree + roundedHeaderSz; + *sequence++ = lte_gold_generic(&x1, &x2, 1); + for (int n = 1; n < length; n++) + *sequence++ = lte_gold_generic(&x1, &x2, 0); + LOG_D(PHY, "created a gold sequence, start %d; len %d\n", key, length); + return firstFree + roundedHeaderSz; +} diff --git a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h index ffd16722cc..b4395e07a9 100644 --- a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h +++ b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h @@ -25,7 +25,7 @@ #define __NR_REFSIG_DEFS__H__ #include "PHY/defs_nr_UE.h" -#include "PHY/LTE_REFSIG/lte_refsig.h" +#include "nr_refsig_common.h" /*!\brief This function generates the NR Gold sequence (38-211, Sec 5.2.1) for the PBCH DMRS. @param PHY_VARS_NR_UE* ue structure provides configuration, frame parameters and the pointers to the 32 bits sequence storage tables diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index a12d203ae7..e7f40f0921 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -26,6 +26,7 @@ #include "PHY/NR_TRANSPORT/nr_ulsch.h" #include "PHY/NR_TRANSPORT/nr_dci.h" #include "PHY/NR_ESTIMATION/nr_ul_estimation.h" +#include "PHY/NR_REFSIG/nr_refsig_common.h" #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h" #include "fapi_nr_l1.h" #include "common/utils/LOG/log.h"