From 59086151e0bd1c7fbcd0103dbb982ee2fbe7433e Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Fri, 26 Jul 2024 12:19:35 +0200 Subject: [PATCH] Add generic usage-based gold cache Add gold sequence cache with dynamic size, private to each thread. It periodically reorders by call rate. To free the gold sequences after end of life time of a thread, use the pthread API. --- CMakeLists.txt | 1 + openair1/PHY/NR_REFSIG/nr_gold_ue.c | 1 + openair1/PHY/NR_REFSIG/nr_refsig.h | 1 + openair1/PHY/NR_REFSIG/nr_refsig_common.h | 32 +++++ openair1/PHY/NR_REFSIG/refsig.c | 166 ++++++++++++++++++++++ openair1/PHY/NR_REFSIG/refsig_defs_ue.h | 2 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 1 + 7 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 openair1/PHY/NR_REFSIG/nr_refsig_common.h create mode 100644 openair1/PHY/NR_REFSIG/refsig.c 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"