Files
openairinterface5g/openair1/PHY/NR_REFSIG/refsig.c
T

175 lines
5.8 KiB
C

/*
* 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;
}
uint32_t *nr_gold_pbch(int Lmax, int Nid, int n_hf, int l)
{
int i_ssb = l & (Lmax - 1);
int i_ssb2 = i_ssb + (n_hf << 2);
uint32_t x2 = (1 << 11) * (i_ssb2 + 1) * ((Nid >> 2) + 1) + (1 << 6) * (i_ssb2 + 1) + (Nid & 3);
return gold_cache(x2, NR_PBCH_DMRS_LENGTH_DWORD);
}