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.
This commit is contained in:
committed by
Robert Schmidt
parent
9c1a8733c1
commit
59086151e0
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user