Compare commits

...

11 Commits

Author SHA1 Message Date
Romain Beurdouche
99cec62618 fix(time_meas): Avoid many short sorted lists in LDPC encoder/decoder 2026-02-13 11:10:55 +01:00
Romain Beurdouche
adfdaf269a feat(phytest): Add DL PMI setting with option -p 2026-02-13 11:10:55 +01:00
Romain Beurdouche
80fb76a779 feat(nr-softmodem): Enable option for advanced statistics
Option `-q` of the NR softmodem can now take an argument to choose the
NR L1 statistics to display:
* no `-q` show no statistics
* `-q` or `-q 1` shows the usual statistics with averaging from gNB start
* `-q 2` shows the advanced statistics with distribution with a reset every second
2026-02-13 11:10:55 +01:00
Romain Beurdouche
04b9b37fc7 fix(nrL1_stats): Do not start/stop/merge timers on mixed slots
When timers are started/stopped/merged on mixed slot,
the measured times are not homogeneous as the mixed slots are much
lighter than full UL/DL slots.
Then, to make the analysis of results easier,
we do not measure the mixed slots.
2026-02-13 11:10:55 +01:00
Romain Beurdouche
61082b0126 feat(nrL1_stats): Add min, d1, q1, median, q3 and d9 for nrL1_stats 2026-02-13 11:10:55 +01:00
Romain Beurdouche
3b5ed67e60 feat(time_meas): Use posix clock instead of cpu tick
Timers were relying on rdtsc which gives a number of ticks which should
be proportionated by the clock frequency.
But the clock frequency can vary.
Then this way of calculating time is not reliable.
This commit offers to use the posix clock monotonic raw instead.
2026-02-13 11:10:55 +01:00
Romain Beurdouche
beb248f8e5 feat(time_meas): Add more stats
* Standard Deviation
* Optional Sorted list enabling:
  * min
  * median
  * q1
  * q3
  * d1
  * d9

The sorted list is optional.
It is enabled by initializing the sorted list which allocates the list.
The size of the list that is allocated is an argument of the initialization.
2026-02-12 15:22:12 +01:00
Romain Beurdouche
dc728854da feat(nr_dlsch): option to provide the number of symbols per thread
* Add option `--tx-sym` for the softmodems and `-Y` for `nr_dlsim`
  to provide the number of symbols processed per thread.
  It defaults to 0 which makes that every symbols are processed in one thread.
* The last symbol processing task is processed in the L1 TX thread.
2026-02-11 11:38:20 +01:00
Romain Beurdouche
847cf9af06 fix(nr_dlsch): symbol offset calculation
There was an indexing error in the calculation of the symbol offset `re_beginning_of_symbol`.
The symbol was tested to hold PTRS or DMRS based on the index of the
first symbol processed in the task and not based on the index of the
symbol as it should be.
Then PDSCH generation was not working properly for more than one symbol
per task.
2026-02-11 11:38:20 +01:00
Robert Schmidt
f63f12480f Reformat 2026-02-11 11:38:20 +01:00
Raymond Knopp
42729d86bb added thread-pool support for TX symbol processing
removed warnings in nr_dlsch.c and changed return of do_onelayer
2026-02-11 11:38:20 +01:00
19 changed files with 939 additions and 210 deletions

View File

@@ -24,6 +24,7 @@ It is defined in include file [ common/config/config_paramdesc.h ](https://gitla
| `PARAMFLAG_NOFREE` | The end_configmodule API won't free the memory which has been possibly allocated to store the value of the parameter.| I |
| `PARAMFLAG_BOOL` | Parameter is a boolean, it can be specified without a value to set it to true | I |
| `PARAMFLAG_CMDLINE_NOPREFIXENABLED` | parameter can be specified without the prefix on the command line. Must be used with care, carefuly checking unicity, especially for short parameter names | I |
| `PARAMFLAG_VALUE_OPTIONAL` | Parameter can be specified with a value or without a value to set it to 1 | I |
| `PARAMFLAG_MALLOCINCONFIG` | Memory for the parameter value has been allocated by the configuration module |O |
| `PARAMFLAG_PARAMSET` | Parameter value has been explicitely set, as the parameter was specified either on the command line or the config source | O |
| `PARAMFLAG_PARAMSETDEF` | Parameter value has been set to it's default | O |

View File

@@ -80,7 +80,7 @@ static int processoption(configmodule_interface_t *cfg, paramdef_t *cfgoptions,
char defbool[2]="1";
if ( value == NULL) {
if( (cfgoptions->paramflags &PARAMFLAG_BOOL) == 0 ) { /* not a boolean, argument required */
if( (cfgoptions->paramflags & (PARAMFLAG_BOOL | PARAMFLAG_VALUE_OPTIONAL)) == 0 ) { /* not a boolean, argument required */
CONFIG_PRINTF_ERROR("[CONFIG] command line, option %s requires an argument\n",cfgoptions->optname);
AssertFatal(false, "[CONFIG] command line, requires an argument\n");
} else { /* boolean value option without argument, set value to true*/

View File

@@ -45,7 +45,8 @@
#define PARAMFLAG_NOFREE (1 << 3) // don't free parameter in end function
#define PARAMFLAG_BOOL (1 << 4) // integer param can be 0 or 1
#define PARAMFLAG_CMDLINE_NOPREFIXENABLED (1 << 5) // on the command line, allow a parameter to be specified without the prefix
#define PARAMFLAG_CMDLINEONLY (1 << 6) // this parameter cannot be specified in config file
#define PARAMFLAG_CMDLINEONLY (1 << 6) // this parameter cannot be specified in config file
#define PARAMFLAG_VALUE_OPTIONAL (1 << 7) // integer param is 1 if no value provided
/* Flags used by config modules to return info to calling modules and/or to for internal usage*/
#define PARAMFLAG_MALLOCINCONFIG (1 << 15) // parameter allocated in config module

View File

@@ -51,6 +51,11 @@ double get_cpu_freq_GHz(void)
}
static double StdDev(time_stats_t *ptr)
{
return sqrt((double)ptr->diff_square * 1e-6 / ptr->trials - pow((double)ptr->diff / ptr->trials / 1000, 2));
}
void print_meas_now(time_stats_t *ts,
const char *name,
@@ -110,6 +115,45 @@ void print_meas(time_stats_t *ts,
}
}
size_t print_meas_log_header(time_stats_t *total_exec_time,
time_stats_t *sf_exec_time,
char *output,
size_t outputlen)
{
const char *begin = output;
const char *end = output + outputlen;
if ((total_exec_time == NULL) || (sf_exec_time== NULL))
output += snprintf(output,
end - output,
"%25s %18s %18s %18s %15s %18s %18s %18s %18s %18s %18s %9s %6f\n",
"Name",
"Total",
"Max",
"Std",
"Num Trials",
"min",
"d1",
"q1",
"median",
"q3",
"d9",
"CPU_F_GHz",
cpu_freq_GHz);
else
output += snprintf(output,
end - output,
"%25s %18s %18s %15s %9s %6f\n",
"Name",
"Total",
"Average/Frame",
"Trials",
"CPU_F_GHz",
cpu_freq_GHz);
return output - begin;
}
size_t print_meas_log(time_stats_t *ts,
const char *name,
time_stats_t *total_exec_time,
@@ -119,46 +163,38 @@ size_t print_meas_log(time_stats_t *ts,
{
const char *begin = output;
const char *end = output + outputlen;
static int first_time = 0;
static double cpu_freq_GHz = 0.0;
if (cpu_freq_GHz == 0.0)
cpu_freq_GHz = get_cpu_freq_GHz();
if (first_time == 0) {
first_time=1;
if ((total_exec_time == NULL) || (sf_exec_time== NULL))
output += snprintf(output,
end - output,
"%25s %25s %25s %25s %25s %6f\n",
"Name",
"Total",
"Per Trials",
"Num Trials",
"CPU_F_GHz",
cpu_freq_GHz);
else
output += snprintf(output,
end - output,
"%25s %25s %25s %20s %15s %6f\n",
"Name",
"Total",
"Average/Frame",
"Trials",
"CPU_F_GHz",
cpu_freq_GHz);
}
if (ts->trials>0) {
if ((total_exec_time == NULL) || (sf_exec_time== NULL)) {
output += snprintf(output,
end - output,
"%25s: %15.3f us; %15d; %15.3f us;\n",
name,
ts->diff / ts->trials / cpu_freq_GHz / 1000.0,
ts->trials,
ts->max / cpu_freq_GHz / 1000.0);
if (is_enabled_time_stats_sorted_list(&ts->time_stats_sorted_list)) {
output += snprintf(output,
end - output,
"%25s: %15.3f us; %15.3f us; %15.3f us; %15d; %15.3f us; %15.3f us; %15.3f us; %15.3f us; %15.3f us; %15.3f us;\n",
name,
ts->diff / ts->trials / 1000.0,
ts->max / 1000.0,
StdDev(ts),
ts->trials,
get_min(&ts->time_stats_sorted_list) / 1000.0,
get_d1(&ts->time_stats_sorted_list) / 1000.0,
get_q1(&ts->time_stats_sorted_list) / 1000.0,
get_median(&ts->time_stats_sorted_list) / 1000.0,
get_q3(&ts->time_stats_sorted_list) / 1000.0,
get_d9(&ts->time_stats_sorted_list) / 1000.0);
} else {
output += snprintf(output,
end - output,
"%25s: %15.3f us; %15.3f us; %15.3f us; %15d;\n",
name,
ts->diff / ts->trials / 1000.0,
ts->max / 1000.0,
StdDev(ts),
ts->trials);
}
} else {
output += snprintf(output,
end - output,
@@ -302,3 +338,198 @@ void end_meas(void) {
msg->msgid = TIMESTAT_MSGID_END ;
pushNotifiedFIFO(&measur_fifo, nfe);
}
/**
* \brief initializes sorted list
* if dst is already initialized then asserts
* \param time_stats_sorted_list sorted list to be initialized
* \param size size of the sorted list
*/
void init_time_stats_sorted_list(time_stats_sorted_list_t *time_stats_sorted_list, unsigned int size)
{
if (time_stats_sorted_list->size == 0) {
time_stats_sorted_list->list = calloc(size, sizeof(oai_cputime_t));
time_stats_sorted_list->size = size;
time_stats_sorted_list->nb_elm = 0;
} else {
AssertFatal(time_stats_sorted_list->size == 0, "Calling init_time_stats_sorted_list on initialized sorted list\n");
}
}
/**
* \brief free sorted list
* if dst is already free then does nothing
* \param time_stats_sorted_list sorted list to be freed
*/
void free_time_stats_sorted_list(time_stats_sorted_list_t *time_stats_sorted_list)
{
if (time_stats_sorted_list->size > 0) {
free(time_stats_sorted_list->list);
time_stats_sorted_list->size = 0;
}
}
/**
* \brief returns true if the sorted list is enabled and false otherwise
* \param time_stats_sorted_list sorted list to be tested
*/
int is_enabled_time_stats_sorted_list(const time_stats_sorted_list_t *time_stats_sorted_list)
{
return (time_stats_sorted_list->size > 0);
}
/**
* \brief empties sorted list
* if dst is not initialized then does nothing
* \param time_stats_sorted_list sorted list to be emptied
*/
void reset_time_stats_sorted_list(time_stats_sorted_list_t *time_stats_sorted_list)
{
if (time_stats_sorted_list->size > 0) {
time_stats_sorted_list->nb_elm = 0;
}
}
/**
* \brief inserts value sorted list
* if dst is not initialized then does nothing
* if dst is full then does nothing
* \param time_stats_sorted_list sorted list to insert in
* \param time time value to insert
*/
void insert_in_time_stats_sorted_list(time_stats_sorted_list_t *time_stats_sorted_list, oai_cputime_t time)
{
if (time_stats_sorted_list->size > 0) {
if (time_stats_sorted_list->nb_elm < time_stats_sorted_list->size) {
unsigned int i = 0;
#ifdef DICHOTOMY
//TODO
#else
for (; i < time_stats_sorted_list->nb_elm && time_stats_sorted_list->list[i] < time; i++);
#endif
// dst and src may overlap => use memmove rather than memcpy
memmove(&time_stats_sorted_list->list[i+1], &time_stats_sorted_list->list[i], (time_stats_sorted_list->nb_elm - i) * sizeof(oai_cputime_t));
time_stats_sorted_list->list[i] = time;
time_stats_sorted_list->nb_elm++;
}
}
}
/**
* \brief copy sorted list src into dst, freeing and replacing dst
* dst and src should be initialized, otherwise does nothing
* \param dst destination sorted list
* should be intitialized even with a dummy size 1 buffer to make sure that copying the list there is expected by the caller
* \param src source sorted list
*/
void copy_time_stats_sorted_list(time_stats_sorted_list_t *dst, const time_stats_sorted_list_t *src)
{
if (dst->size > 0 && src->size > 0) {
if (dst->size != src->size) {
free_time_stats_sorted_list(dst);
init_time_stats_sorted_list(dst, src->size);
}
memcpy(dst->list, src->list, src->nb_elm * sizeof(oai_cputime_t));
dst->nb_elm = src->nb_elm;
}
}
/**
* \brief inserts the content of sorted list src into dst
* dst and src should be initialized, otherwise does nothing
* if dst is not large enough to copy src then does nothing
* \param dst destination sorted list
* \param src source sorted list
*/
void merge_time_stats_sorted_list(time_stats_sorted_list_t *dst, const time_stats_sorted_list_t *src)
{
if (dst->size > 0 && src->size > 0) {
if ((dst->size - dst->nb_elm) >= src->nb_elm) {
unsigned int j = 0;
for (unsigned int i = 0; i < src->nb_elm; i++) {
#ifdef DICHOTOMY
//TODO
#else
for (; j < dst->nb_elm && dst->list[j] < src->list[i]; j++);
#endif
// dst and src may overlap => use memmove rather than memcpy
memmove(&dst->list[j+1], &dst->list[j], (dst->nb_elm - j) * sizeof(oai_cputime_t));
dst->list[j] = src->list[i];
dst->nb_elm++;
j++;
}
}
}
}
/**
* \brief get the minimum from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_min(time_stats_sorted_list_t *time_stats_sorted_list)
{
if (time_stats_sorted_list->size > 0 && time_stats_sorted_list->nb_elm > 0) {
return time_stats_sorted_list->list[0];
} else {
return -1;
}
}
/**
* \brief get the median from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_median(time_stats_sorted_list_t *time_stats_sorted_list)
{
if (time_stats_sorted_list->size > 0 && time_stats_sorted_list->nb_elm > 0) {
return time_stats_sorted_list->list[time_stats_sorted_list->nb_elm / 2];
} else {
return -1;
}
}
/**
* \brief get the first quartile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_q1(time_stats_sorted_list_t *time_stats_sorted_list)
{
if (time_stats_sorted_list->size > 0 && time_stats_sorted_list->nb_elm > 0) {
return time_stats_sorted_list->list[time_stats_sorted_list->nb_elm / 4];
} else {
return -1;
}
}
/**
* \brief get the third quartile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_q3(time_stats_sorted_list_t *time_stats_sorted_list)
{
if (time_stats_sorted_list->size > 0 && time_stats_sorted_list->nb_elm > 0) {
return time_stats_sorted_list->list[3 * time_stats_sorted_list->nb_elm / 4];
} else {
return -1;
}
}
/**
* \brief get the first decile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_d1(time_stats_sorted_list_t *time_stats_sorted_list)
{
if (time_stats_sorted_list->size > 0 && time_stats_sorted_list->nb_elm > 0) {
return time_stats_sorted_list->list[time_stats_sorted_list->nb_elm / 10];
} else {
return -1;
}
}
/**
* \brief get the nineth decile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_d9(time_stats_sorted_list_t *time_stats_sorted_list)
{
if (time_stats_sorted_list->size > 0 && time_stats_sorted_list->nb_elm > 0) {
return time_stats_sorted_list->list[9 * time_stats_sorted_list->nb_elm / 10];
} else {
return -1;
}
}

View File

@@ -55,20 +55,121 @@ typedef struct {
meas_printfunc_t displayFunc; /*!< \brief function to call when DISPLAY message is received*/
} time_stats_msg_t;
/**
* \typedef time_stats_sorted_list_t
* \brief sorted list of time stats to get med, q1, q2
* it can be left disabled by leaving size equal to 0
* \var size allocated size of the list
* 0 is the sorted list is disabled
* \var nb_elm number of elements in the list
* \var list pointer to the list
*/
typedef struct {
unsigned int size;
unsigned int nb_elm;
oai_cputime_t *list;
} time_stats_sorted_list_t;
/**
* \brief initializes sorted list
* if dst is already initialized then asserts
* \param time_stats_sorted_list sorted list to be initialized
* \param size size of the sorted list
*/
void init_time_stats_sorted_list(time_stats_sorted_list_t *time_stats_sorted_list, unsigned int size);
/**
* \brief free sorted list
* if dst is already free then does nothing
* \param time_stats_sorted_list sorted list to be freed
*/
void free_time_stats_sorted_list(time_stats_sorted_list_t *time_stats_sorted_list);
/**
* \brief returns true if the sorted list is enabled and false otherwise
* \param time_stats_sorted_list sorted list to be tested
*/
int is_enabled_time_stats_sorted_list(const time_stats_sorted_list_t *time_stats_sorted_list);
/**
* \brief empties sorted list
* if dst is not initialized then does nothing
* \param time_stats_sorted_list sorted list to be emptied
*/
void reset_time_stats_sorted_list(time_stats_sorted_list_t *time_stats_sorted_list);
/**
* \brief inserts value sorted list
* if dst is not initialized then does nothing
* if dst is full then does nothing
* \param time_stats_sorted_list sorted list to insert in
* \param time time value to insert
*/
void insert_in_time_stats_sorted_list(time_stats_sorted_list_t *time_stats_sorted_list, oai_cputime_t time);
/**
* \brief copy sorted list src into dst, freeing and replacing dst
* dst and src should be initialized, otherwise does nothing
* \param dst destination sorted list
* should be intitialized even with a dummy size 1 buffer to make sure that copying the list there is expected by the caller
* \param src source sorted list
*/
void copy_time_stats_sorted_list(time_stats_sorted_list_t *dst, const time_stats_sorted_list_t *src);
/**
* \brief inserts the content of sorted list src into dst
* dst and src should be initialized, otherwise does nothing
* if dst is not large enough to copy src then does nothing
* \param dst destination sorted list
* \param src source sorted list
*/
void merge_time_stats_sorted_list(time_stats_sorted_list_t *dst, const time_stats_sorted_list_t *src);
/**
* \brief get the minimum from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_min(time_stats_sorted_list_t *time_stats_sorted_list);
/**
* \brief get the median from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_median(time_stats_sorted_list_t *time_stats_sorted_list);
/**
* \brief get the first quartile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_q1(time_stats_sorted_list_t *time_stats_sorted_list);
/**
* \brief get the third quartile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_q3(time_stats_sorted_list_t *time_stats_sorted_list);
/**
* \brief get the first decile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_d1(time_stats_sorted_list_t *time_stats_sorted_list);
/**
* \brief get the nineth decile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_d9(time_stats_sorted_list_t *time_stats_sorted_list);
struct notifiedFIFO_elt_s;
typedef struct time_stats {
oai_cputime_t in; /*!< \brief time at measure starting point */
oai_cputime_t diff; /*!< \brief average difference between time at starting point and time at endpoint*/
oai_cputime_t p_time; /*!< \brief absolute process duration */
double diff_square; /*!< \brief process duration square */
oai_cputime_t max; /*!< \brief maximum difference between time at starting point and time at endpoint*/
int trials; /*!< \brief number of start point - end point iterations */
int meas_flag; /*!< \brief 1: stop_meas not called (consecutive calls of start_meas) */
char *meas_name; /*!< \brief name to use when printing the measure (not used for PHY simulators)*/
int meas_index; /*!< \brief index of this measure in the measure array (not used for PHY simulators)*/
int meas_enabled; /*!< \brief per measure enablement flag. send_meas tests this flag, unused today in start_meas and stop_meas*/
struct notifiedFIFO_elt_s *tpoolmsg; /*!< \brief message pushed to the cpu measurment queue to report a measure START or STOP */
time_stats_msg_t *tstatptr; /*!< \brief pointer to the time_stats_msg_t data in the tpoolmsg, stored here for perf considerations*/
oai_cputime_t in; /*!< \brief time at measure starting point */
oai_cputime_t diff; /*!< \brief average difference between time at starting point and time at endpoint*/
oai_cputime_t p_time; /*!< \brief absolute process duration */
double diff_square; /*!< \brief process duration square */
oai_cputime_t max; /*!< \brief maximum difference between time at starting point and time at endpoint*/
int trials; /*!< \brief number of start point - end point iterations */
int meas_flag; /*!< \brief 1: stop_meas not called (consecutive calls of start_meas) */
char *meas_name; /*!< \brief name to use when printing the measure (not used for PHY simulators)*/
int meas_index; /*!< \brief index of this measure in the measure array (not used for PHY simulators)*/
int meas_enabled; /*!< \brief per measure enablement flag. send_meas tests this flag, unused today in start_meas and stop_meas*/
struct notifiedFIFO_elt_s *tpoolmsg; /*!< \brief message pushed to the cpu measurment queue to report a measure START or STOP */
time_stats_msg_t *tstatptr; /*!< \brief pointer to the time_stats_msg_t data in the tpoolmsg, stored here for perf considerations */
time_stats_sorted_list_t time_stats_sorted_list; /*!< \brief optional sorted list to get med, q1, q2 */
} time_stats_t;
#define MEASURE_ENABLED(X) (X->meas_enabled)
@@ -77,6 +178,10 @@ static inline void stop_meas(time_stats_t *ts) __attribute__((always_inline));
void print_meas_now(time_stats_t *ts, const char *name, FILE *file_name);
void print_meas(time_stats_t *ts, const char *name, time_stats_t *total_exec_time, time_stats_t *sf_exec_time);
size_t print_meas_log_header(time_stats_t *total_exec_time,
time_stats_t *sf_exec_time,
char *output,
size_t outputlen);
size_t print_meas_log(time_stats_t *ts,
const char *name,
time_stats_t *total_exec_time,
@@ -118,6 +223,19 @@ static inline uint32_t rdtsc_oai(void) {
}
#endif
static inline long long clock_gettime_oai()
{
struct timespec time;
#ifdef CLOCK_MONOTONIC_RAW
// CLOCK_MONOTONIC_RAW only on linux
// See clock_getres(2)
clock_gettime(CLOCK_MONOTONIC_RAW, &time);
#else
clock_gettime(CLOCK_REALTIME, &time);
#endif
return 1e+9 * time.tv_sec + time.tv_nsec;
}
#define CPUMEAS_DISABLE 0
#define CPUMEAS_ENABLE 1
#define CPUMEAS_GETSTATE 2
@@ -143,10 +261,10 @@ static inline void start_meas(time_stats_t *ts) {
if (cpu_meas_enabled) {
if (ts->meas_flag==0) {
ts->trials++;
ts->in = rdtsc_oai();
ts->in = clock_gettime_oai();
ts->meas_flag=1;
} else {
ts->in = rdtsc_oai();
ts->in = clock_gettime_oai();
}
if ((ts->trials&16383)<10) ts->max=0;
}
@@ -154,7 +272,7 @@ static inline void start_meas(time_stats_t *ts) {
static inline void stop_meas(time_stats_t *ts) {
if (cpu_meas_enabled) {
long long out = rdtsc_oai();
long long out = clock_gettime_oai();
if (ts->in) {
ts->diff += (out - ts->in);
/// process duration is the difference between two clock points
@@ -164,6 +282,7 @@ static inline void stop_meas(time_stats_t *ts) {
if ((out - ts->in) > ts->max)
ts->max = out - ts->in;
insert_in_time_stats_sorted_list(&ts->time_stats_sorted_list, (out - ts->in));
ts->meas_flag = 0;
}
}
@@ -177,6 +296,7 @@ static inline void reset_meas(time_stats_t *ts) {
ts->max=0;
ts->trials=0;
ts->meas_flag=0;
reset_time_stats_sorted_list(&ts->time_stats_sorted_list);
}
static inline void copy_meas(time_stats_t *dst_ts,time_stats_t *src_ts) {
@@ -184,6 +304,7 @@ static inline void copy_meas(time_stats_t *dst_ts,time_stats_t *src_ts) {
dst_ts->trials=src_ts->trials;
dst_ts->diff=src_ts->diff;
dst_ts->max=src_ts->max;
copy_time_stats_sorted_list(&dst_ts->time_stats_sorted_list, &src_ts->time_stats_sorted_list);
}
}
@@ -196,6 +317,23 @@ static inline void merge_meas(time_stats_t *dst_ts, const time_stats_t *src_ts)
dst_ts->diff_square += src_ts->diff_square;
if (src_ts->max > dst_ts->max)
dst_ts->max = src_ts->max;
if (is_enabled_time_stats_sorted_list(&src_ts->time_stats_sorted_list)) {
merge_time_stats_sorted_list(&dst_ts->time_stats_sorted_list, &src_ts->time_stats_sorted_list);
} else if (src_ts->trials == 1) {
insert_in_time_stats_sorted_list(&dst_ts->time_stats_sorted_list, src_ts->max);
}
}
#define TIME_STATS_ADVANCED_MODE 2
static inline void init_sorted_list_meas(time_stats_t *ts, unsigned int size)
{
init_time_stats_sorted_list(&ts->time_stats_sorted_list, size);
}
static inline void free_sorted_list_meas(time_stats_t *ts)
{
free_time_stats_sorted_list(&ts->time_stats_sorted_list);
}
#define CPUMEASUR_SECTION "cpumeasur"

View File

@@ -120,7 +120,9 @@ static void tx_func(processingData_L1tx_t *info)
// TODO check for analog_bf_vendor_ext set to 1 is a workaround while no beam API for beam selection is implemented
if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx
|| IS_SOFTMODEM_RFSIM || cfg->analog_beamforming_ve.analog_bf_vendor_ext.value) {
start_meas(&info->gNB->phy_proc_tx);
if (tx_slot_type == NR_DOWNLINK_SLOT) {
start_meas(&info->gNB->phy_proc_tx);
}
phy_procedures_gNB_TX(info->gNB,
&sched_response.DL_req,
&sched_response.TX_req,
@@ -137,7 +139,9 @@ static void tx_func(processingData_L1tx_t *info)
syncMsgRU.timestamp_tx = info->timestamp_tx;
LOG_D(PHY, "gNB: %d.%d : calling RU TX function\n", syncMsgRU.frame_tx, syncMsgRU.slot_tx);
ru_tx_func((void *)&syncMsgRU);
stop_meas(&info->gNB->phy_proc_tx);
if (tx_slot_type == NR_DOWNLINK_SLOT) {
stop_meas(&info->gNB->phy_proc_tx);
}
}
}
@@ -150,9 +154,14 @@ void *L1_rx_thread(void *arg)
if (res == NULL)
break;
processingData_L1_t *info = (processingData_L1_t *)NotifiedFifoData(res);
start_meas(&gNB->l1_rx_proc);
int slot_type = nr_slot_select(&gNB->gNB_config, info->frame_rx, info->slot_rx);
if (slot_type == NR_UPLINK_SLOT) {
start_meas(&gNB->l1_rx_proc);
}
rx_func(info);
stop_meas(&gNB->l1_rx_proc);
if (slot_type == NR_UPLINK_SLOT) {
stop_meas(&gNB->l1_rx_proc);
}
delNotifiedFIFO_elt(res);
}
return NULL;
@@ -166,9 +175,14 @@ void *L1_tx_thread(void *arg) {
if (res == NULL) // stopping condition, happens only when queue is freed
break;
processingData_L1tx_t *info = (processingData_L1tx_t *)NotifiedFifoData(res);
start_meas(&gNB->l1_tx_proc);
int slot_type = nr_slot_select(&gNB->gNB_config, info->frame, info->slot);
if (slot_type == NR_DOWNLINK_SLOT) {
start_meas(&gNB->l1_tx_proc);
}
tx_func(info);
stop_meas(&gNB->l1_tx_proc);
if (slot_type == NR_DOWNLINK_SLOT) {
stop_meas(&gNB->l1_tx_proc);
}
delNotifiedFIFO_elt(res);
}
return NULL;
@@ -214,9 +228,13 @@ static void rx_func(processingData_L1_t *info)
phy_procedures_gNB_uespec_RX(gNB, frame_rx, slot_rx, &UL_INFO);
// Call the scheduler
start_meas(&gNB->ul_indication_stats);
if (rx_slot_type == NR_UPLINK_SLOT) {
start_meas(&gNB->ul_indication_stats);
}
gNB->if_inst->NR_UL_indication(&UL_INFO);
stop_meas(&gNB->ul_indication_stats);
if (rx_slot_type == NR_UPLINK_SLOT) {
stop_meas(&gNB->ul_indication_stats);
}
notifiedFIFO_elt_t *res = newNotifiedFIFO_elt(sizeof(processingData_L1_t), 0, &gNB->L1_rx_out, NULL);
processingData_L1_t *syncMsg = NotifiedFifoData(res);
@@ -233,15 +251,24 @@ static void rx_func(processingData_L1_t *info)
static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size_t outputlen) {
const char *begin = output;
const char *end = output + outputlen;
output += print_meas_log_header(NULL, NULL, output, end - output);
output += print_meas_log(&gNB->l1_tx_proc, "L1 Tx job", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->l1_rx_proc, "L1 Rx job", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->phy_proc_tx, "L1 Tx processing", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->dlsch_encoding_stats, "DLSCH encoding", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->dlsch_segmentation_stats, "DL segment segmentation", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->tinput, "DL encoding input", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->tprep, "DL encoding preparation", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->tparity, "DL encoding parity", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->toutput, "DL encoding output", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->dlsch_rate_matching_stats, "DL rate matching", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->dlsch_interleaving_stats, "DL interleaving", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->dlsch_scrambling_stats, "DLSCH scrambling", NULL, NULL, output, end-output);
output += print_meas_log(&gNB->dlsch_modulation_stats, "DLSCH modulation", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->dlsch_resource_mapping_stats, "DLSCH resource mapping", NULL, NULL, output,end-output);
output += print_meas_log(&gNB->dlsch_precoding_stats, "DLSCH precoding", NULL, NULL, output,end-output);
output += print_meas_log(&gNB->dlsch_pdsch_generation_stats, "DLSCH generation", NULL, NULL, output,end-output);
output += print_meas_log(&gNB->phy_proc_rx, "L1 Rx processing", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->ulsch_decoding_stats, "ULSCH decoding", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->ts_deinterleave, "UL segment deinterleaving", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->ts_rate_unmatch, "UL segment rate recovery", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->ts_ldpc_decode, "UL segments decoding", NULL, NULL, output, end - output);
@@ -249,8 +276,9 @@ static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size
output += print_meas_log(&gNB->slot_indication_stats, "Slot Indication", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL, output, end - output);
output += print_meas_log(&gNB->rx_prach, "PRACH RX", NULL, NULL, output, end - output);
if (ru->feprx)
if (ru->feprx) {
output += print_meas_log(&ru->ofdm_demod_stats, "feprx", NULL, NULL, output, end - output);
}
bool full_slot = ru->half_slot_parallelization == 0;
if (ru->feptx_prec) {
@@ -274,8 +302,9 @@ static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size
output += print_meas_log(&ru->txdataF_copy_stats, "txdataF_copy", NULL, NULL, output, end - output);
}
if (ru->fh_north_asynch_in)
if (ru->fh_north_asynch_in) {
output += print_meas_log(&ru->rx_fhaul,"rx_fhaul",NULL,NULL, output, end - output);
}
output += print_meas_log(&ru->tx_fhaul,"tx_fhaul",NULL,NULL, output, end - output);
@@ -283,9 +312,62 @@ static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size
output += print_meas_log(&ru->compression,"compression",NULL,NULL, output, end - output);
output += print_meas_log(&ru->transport,"transport",NULL,NULL, output, end - output);
}
if (cpu_meas_enabled == TIME_STATS_ADVANCED_MODE) {
reset_meas(&gNB->l1_tx_proc);
reset_meas(&gNB->l1_rx_proc);
reset_meas(&gNB->phy_proc_tx);
reset_meas(&gNB->dlsch_encoding_stats);
reset_meas(&gNB->dlsch_segmentation_stats);
reset_meas(&gNB->tinput);
reset_meas(&gNB->tprep);
reset_meas(&gNB->tparity);
reset_meas(&gNB->toutput);
reset_meas(&gNB->dlsch_rate_matching_stats);
reset_meas(&gNB->dlsch_interleaving_stats);
reset_meas(&gNB->dlsch_scrambling_stats);
reset_meas(&gNB->dlsch_modulation_stats);
reset_meas(&gNB->dlsch_resource_mapping_stats);
reset_meas(&gNB->dlsch_pdsch_generation_stats);
reset_meas(&gNB->phy_proc_rx);
reset_meas(&gNB->ulsch_decoding_stats);
reset_meas(&gNB->ts_deinterleave);
reset_meas(&gNB->ts_rate_unmatch);
reset_meas(&gNB->ts_ldpc_decode);
reset_meas(&gNB->ul_indication_stats);
reset_meas(&gNB->slot_indication_stats);
reset_meas(&gNB->rx_pusch_stats);
reset_meas(&gNB->rx_prach);
if (ru->feprx) {
reset_meas(&ru->ofdm_demod_stats);
}
if (ru->feptx_prec) {
reset_meas(&ru->precoding_stats);
}
if (ru->feptx_ofdm) {
reset_meas(&ru->txdataF_copy_stats);
reset_meas(&ru->ofdm_mod_stats);
reset_meas(&ru->ofdm_total_stats);
reset_meas(&ru->txdataF_copy_stats);
}
if (ru->fh_north_asynch_in) {
reset_meas(&ru->rx_fhaul);
}
reset_meas(&ru->tx_fhaul);
if (ru->fh_north_out) {
reset_meas(&ru->compression);
reset_meas(&ru->transport);
}
}
return output - begin;
}
#define SORTED_LIST_SIZE 2048
void *nrL1_stats_thread(void *param) {
PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param;
RU_t *ru = RC.ru[0];
@@ -298,21 +380,95 @@ void *nrL1_stats_thread(void *param) {
return NULL;
}
if (cpu_meas_enabled == TIME_STATS_ADVANCED_MODE) {
init_sorted_list_meas(&gNB->l1_tx_proc, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->l1_rx_proc, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->phy_proc_tx, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->dlsch_encoding_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->tinput, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->tprep, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->tparity, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->toutput, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->dlsch_segmentation_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->dlsch_rate_matching_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->dlsch_interleaving_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->dlsch_scrambling_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->dlsch_modulation_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->dlsch_pdsch_generation_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->phy_proc_rx, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->ulsch_decoding_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->ts_deinterleave, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->ts_rate_unmatch, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->ts_ldpc_decode, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->ul_indication_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->slot_indication_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->rx_pusch_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&gNB->rx_prach, SORTED_LIST_SIZE);
if (ru->feprx) {
init_sorted_list_meas(&ru->ofdm_demod_stats, SORTED_LIST_SIZE);
}
if (ru->feptx_prec) {
init_sorted_list_meas(&ru->precoding_stats, SORTED_LIST_SIZE);
}
if (ru->feptx_ofdm) {
init_sorted_list_meas(&ru->txdataF_copy_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&ru->ofdm_mod_stats, SORTED_LIST_SIZE);
init_sorted_list_meas(&ru->ofdm_total_stats, SORTED_LIST_SIZE);
}
if (ru->fh_north_asynch_in) {
init_sorted_list_meas(&ru->rx_fhaul, SORTED_LIST_SIZE);
}
init_sorted_list_meas(&ru->tx_fhaul, SORTED_LIST_SIZE);
if (ru->fh_north_out) {
init_sorted_list_meas(&ru->compression, SORTED_LIST_SIZE);
init_sorted_list_meas(&ru->transport, SORTED_LIST_SIZE);
}
}
reset_meas(&gNB->l1_tx_proc);
reset_meas(&gNB->l1_rx_proc);
reset_meas(&gNB->phy_proc_tx);
reset_meas(&gNB->dlsch_encoding_stats);
reset_meas(&gNB->dlsch_segmentation_stats);
reset_meas(&gNB->tinput);
reset_meas(&gNB->tprep);
reset_meas(&gNB->tparity);
reset_meas(&gNB->toutput);
reset_meas(&gNB->dlsch_rate_matching_stats);
reset_meas(&gNB->dlsch_interleaving_stats);
reset_meas(&gNB->dlsch_scrambling_stats);
reset_meas(&gNB->dlsch_modulation_stats);
reset_meas(&gNB->dlsch_pdsch_generation_stats);
reset_meas(&gNB->phy_proc_rx);
reset_meas(&gNB->ulsch_decoding_stats);
reset_meas(&gNB->ts_deinterleave);
reset_meas(&gNB->ts_rate_unmatch);
reset_meas(&gNB->ts_ldpc_decode);
reset_meas(&gNB->ul_indication_stats);
reset_meas(&gNB->slot_indication_stats);
reset_meas(&gNB->rx_pusch_stats);
reset_meas(&gNB->dlsch_scrambling_stats);
reset_meas(&gNB->dlsch_modulation_stats);
reset_meas(&gNB->dlsch_resource_mapping_stats);
reset_meas(&gNB->dlsch_precoding_stats);
reset_meas(&gNB->rx_prach);
if (ru->feprx) {
reset_meas(&ru->ofdm_demod_stats);
}
if (ru->feptx_prec) {
reset_meas(&ru->precoding_stats);
}
if (ru->feptx_ofdm) {
reset_meas(&ru->txdataF_copy_stats);
reset_meas(&ru->ofdm_mod_stats);
reset_meas(&ru->ofdm_total_stats);
}
if (ru->fh_north_asynch_in) {
reset_meas(&ru->rx_fhaul);
}
reset_meas(&ru->tx_fhaul);
if (ru->fh_north_out) {
reset_meas(&ru->compression);
reset_meas(&ru->transport);
}
while (!oai_exit) {
sleep(1);
if (ftruncate(fileno(fd), 0) != 0 || fseek(fd, 0, SEEK_SET) != 0) {
@@ -326,6 +482,54 @@ void *nrL1_stats_thread(void *param) {
fprintf(fd,"%s\n",output);
fflush(fd);
}
if (cpu_meas_enabled == TIME_STATS_ADVANCED_MODE) {
free_sorted_list_meas(&gNB->l1_tx_proc);
free_sorted_list_meas(&gNB->l1_rx_proc);
free_sorted_list_meas(&gNB->phy_proc_tx);
free_sorted_list_meas(&gNB->dlsch_encoding_stats);
free_sorted_list_meas(&gNB->dlsch_segmentation_stats);
free_sorted_list_meas(&gNB->tinput);
free_sorted_list_meas(&gNB->tprep);
free_sorted_list_meas(&gNB->tparity);
free_sorted_list_meas(&gNB->toutput);
free_sorted_list_meas(&gNB->dlsch_rate_matching_stats);
free_sorted_list_meas(&gNB->dlsch_interleaving_stats);
free_sorted_list_meas(&gNB->dlsch_scrambling_stats);
free_sorted_list_meas(&gNB->dlsch_modulation_stats);
free_sorted_list_meas(&gNB->dlsch_pdsch_generation_stats);
free_sorted_list_meas(&gNB->phy_proc_rx);
free_sorted_list_meas(&gNB->ulsch_decoding_stats);
free_sorted_list_meas(&gNB->ts_deinterleave);
free_sorted_list_meas(&gNB->ts_rate_unmatch);
free_sorted_list_meas(&gNB->ts_ldpc_decode);
free_sorted_list_meas(&gNB->ul_indication_stats);
free_sorted_list_meas(&gNB->slot_indication_stats);
free_sorted_list_meas(&gNB->rx_pusch_stats);
free_sorted_list_meas(&gNB->rx_prach);
if (ru->feprx) {
free_sorted_list_meas(&ru->ofdm_demod_stats);
}
if (ru->feptx_prec) {
free_sorted_list_meas(&ru->precoding_stats);
}
if (ru->feptx_ofdm) {
free_sorted_list_meas(&ru->txdataF_copy_stats);
free_sorted_list_meas(&ru->ofdm_mod_stats);
free_sorted_list_meas(&ru->ofdm_total_stats);
free_sorted_list_meas(&ru->txdataF_copy_stats);
}
if (ru->fh_north_asynch_in) {
free_sorted_list_meas(&ru->rx_fhaul);
}
free_sorted_list_meas(&ru->tx_fhaul);
if (ru->fh_north_out) {
free_sorted_list_meas(&ru->compression);
free_sorted_list_meas(&ru->transport);
}
}
fclose(fd);
return(NULL);
}
@@ -342,6 +546,7 @@ void init_gNB_Tpool(int inst)
gNB_L1_proc_t *proc = &gNB->proc;
// PUSCH symbols per thread need to be calculated by how many threads we have
gNB->num_pusch_symbols_per_thread = 1;
gNB->num_pdsch_symbols_per_thread = get_softmodem_params()->num_pdsch_symbols_per_thread;
// ULSCH decoding threadpool
initTpool(get_softmodem_params()->threadPoolConfig, &gNB->threadPool, cpumeas(CPUMEAS_GETSTATE));

View File

@@ -31,6 +31,7 @@
/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */
#define CONFIG_HLP_DLMCS_PHYTEST "Set the downlink MCS for PHYTEST mode\n"
#define CONFIG_HLP_DLNL_PHYTEST "Set the downlink nrOfLayers for PHYTEST mode\n"
#define CONFIG_HLP_DLPMI_PHYTEST "Set the downlink Precoding Matrix Index for PHYTEST mode\n"
#define CONFIG_HLP_ULNL_PHYTEST "Set the uplink nrOfLayers for PHYTEST mode\n"
#define CONFIG_HLP_DLBW_PHYTEST "Set the number of PRBs used for DLSCH in PHYTEST mode\n"
#define CONFIG_HLP_ULBW_PHYTEST "Set the number of PRBs used for ULSCH in PHYTEST mode\n"

View File

@@ -17,9 +17,10 @@
/*----------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
// clang-format off
#define CMDLINE_PARAMS_DESC_GNB { \
{"m" , CONFIG_HLP_DLMCS_PHYTEST, 0, .uptr=&target_dl_mcs, .defintval=0, TYPE_UINT, 0}, \
{"l" , CONFIG_HLP_DLNL_PHYTEST, 0, .uptr=&target_dl_Nl, .defintval=0, TYPE_UINT, 0}, \
{"L" , CONFIG_HLP_ULNL_PHYTEST, 0, .uptr=&target_ul_Nl, .defintval=0, TYPE_UINT, 0}, \
{"p" , CONFIG_HLP_DLPMI_PHYTEST, 0, .uptr=&target_dl_pmi, .defintval=0, TYPE_UINT, 0}, \
{"m" , CONFIG_HLP_DLMCS_PHYTEST, 0, .uptr=&target_dl_mcs, .defintval=0, TYPE_UINT, 0}, \
{"t" , CONFIG_HLP_ULMCS_PHYTEST, 0, .uptr=&target_ul_mcs, .defintval=0, TYPE_UINT, 0}, \
{"M" , CONFIG_HLP_DLBW_PHYTEST, 0, .uptr=&target_dl_bw, .defintval=0, TYPE_UINT, 0}, \
{"T" , CONFIG_HLP_ULBW_PHYTEST, 0, .uptr=&target_ul_bw, .defintval=0, TYPE_UINT, 0}, \
@@ -30,9 +31,10 @@
}
// clang-format on
extern uint32_t target_dl_mcs;
extern uint32_t target_dl_Nl;
extern uint32_t target_ul_Nl;
extern uint32_t target_dl_pmi;
extern uint32_t target_dl_mcs;
extern uint32_t target_ul_mcs;
extern uint32_t target_dl_bw;
extern uint32_t target_ul_bw;

View File

@@ -47,6 +47,7 @@ extern "C"
example: -1,3 launches two working threads one floating, the second set on core 3\n\
default 8 floating threads\n\
use N for no pool (runs in calling thread) recommended with rfsim.\n"
#define CONFIG_HLP_TX_SYM "number of symbols processed per PDSCH generation thread\n"
#define CONFIG_HLP_CALUER "set UE RX calibration\n"
#define CONFIG_HLP_CALUERM ""
#define CONFIG_HLP_CALUERB ""
@@ -107,6 +108,7 @@ extern "C"
/*-----------------------------------------------------------------------------------------------------------------------------------------------------*/
#define RF_CONFIG_FILE softmodem_params.rf_config_file
#define TP_CONFIG softmodem_params.threadPoolConfig
#define TX_SYM softmodem_params.num_pdsch_symbols_per_thread
#define CONTINUOUS_TX softmodem_params.continuous_tx
#define PHY_TEST softmodem_params.phy_test
#define DO_RA softmodem_params.do_ra
@@ -132,6 +134,7 @@ extern int usrp_tx_thread;
#define CMDLINE_PARAMS_DESC { \
{"rf-config-file", CONFIG_HLP_RFCFGF, 0, .strptr=&RF_CONFIG_FILE, .defstrval=NULL, TYPE_STRING, 0}, \
{"thread-pool", CONFIG_HLP_TPOOL, 0, .strptr=&TP_CONFIG, .defstrval="-1,-1,-1,-1,-1,-1,-1,-1", TYPE_STRING, 0}, \
{"tx-sym", CONFIG_HLP_TX_SYM, 0, .iptr=&TX_SYM, .defintval=0, TYPE_INT, 0}, \
{"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, .iptr=&PHY_TEST, .defintval=0, TYPE_INT, 0}, \
{"do-ra", CONFIG_HLP_DORA, PARAMFLAG_BOOL, .iptr=&DO_RA, .defintval=0, TYPE_INT, 0}, \
{"sl-mode", CONFIG_HLP_SL_MODE, 0, .u8ptr=&SL_MODE, .defintval=0, TYPE_UINT8, 0}, \
@@ -142,7 +145,7 @@ extern int usrp_tx_thread;
{"CO" , CONFIG_HLP_ULF, 0, .iptr=&(uplink_frequency_offset[0][0]), .defintval=0, TYPE_INT, 0}, \
{"a" , CONFIG_HLP_CHOFF, 0, .iptr=&CHAIN_OFFSET, .defintval=0, TYPE_INT, 0}, \
{"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, .uptr=&do_forms, .defintval=0, TYPE_UINT, 0}, \
{"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, .iptr=&cpu_meas_enabled, .defintval=0, TYPE_INT, 0}, \
{"q" , CONFIG_HLP_STMON, PARAMFLAG_VALUE_OPTIONAL, .iptr=&cpu_meas_enabled, .defintval=0, TYPE_INT, 0}, \
{"numerology" , CONFIG_HLP_NUMEROLOGY, 0, .iptr=&NUMEROLOGY, .defintval=1, TYPE_INT, 0}, \
{"band" , CONFIG_HLP_BAND, 0, .iptr=&BAND, .defintval=78, TYPE_INT, 0}, \
{"parallel-config", CONFIG_HLP_PARALLEL_CMD, 0, .strptr=&parallel_config, .defstrval=NULL, TYPE_STRING, 0}, \
@@ -196,6 +199,7 @@ extern int usrp_tx_thread;
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s3a = { config_checkstr_assign_integer, \
{"MONOLITHIC", "PNF", "VNF", "AERIAL","UE_STUB_PNF","UE_STUB_OFFNET","STANDALONE_PNF"}, \
{NFAPI_MONOLITHIC, NFAPI_MODE_PNF, NFAPI_MODE_VNF, NFAPI_MODE_AERIAL,NFAPI_UE_STUB_PNF,NFAPI_UE_STUB_OFFNET,NFAPI_MODE_STANDALONE_PNF}, \
@@ -294,6 +298,7 @@ typedef struct {
//THREAD_STRUCT thread_struct;
char *rf_config_file;
char *threadPoolConfig;
int num_pdsch_symbols_per_thread;
int phy_test;
int do_ra;
uint8_t sl_mode;

View File

@@ -121,7 +121,8 @@ int main(int argc, char *argv[])
}
}
// Initiate timing. (Results depend on CPU Frequency. Therefore, might change due to performance variances during simulation.)
time_stats_t timeEncoder, timeDecoder;
time_stats_t timeEncoder = {0};
time_stats_t timeDecoder = {0};
cpu_meas_enabled = 1;
reset_meas(&timeEncoder);
reset_meas(&timeDecoder);

View File

@@ -9,7 +9,8 @@
configmodule_interface_t *uniqCfg = NULL;
int main(int argc, char *argv[])
{
time_stats_t timeEncoder, timeDecoder;
time_stats_t timeEncoder = {0};
time_stats_t timeDecoder = {0};
cpu_meas_enabled = 1;
reset_meas(&timeEncoder);
reset_meas(&timeDecoder);

View File

@@ -337,22 +337,22 @@ static inline void neg_dmrs(c16_t *in, c16_t *out, int sz)
*out++ = i % 2 ? (c16_t){-in[i].r, -in[i].i} : in[i];
}
static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
int slot,
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15,
int layer,
c16_t *output,
c16_t *txl_start,
int start_sc,
int symbol_sz,
int l_symbol,
uint16_t dlPtrsSymPos,
int n_ptrs,
int amp,
int16_t amp_dmrs,
int l_prime,
nfapi_nr_dmrs_type_e dmrs_Type,
c16_t *dmrs_start)
static inline void do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
int slot,
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15,
int layer,
c16_t *output,
c16_t *txl_start,
int start_sc,
int symbol_sz,
int l_symbol,
uint16_t dlPtrsSymPos,
int n_ptrs,
int amp,
int16_t amp_dmrs,
int l_prime,
nfapi_nr_dmrs_type_e dmrs_Type,
c16_t *dmrs_start)
{
c16_t *txl = txl_start;
const uint sz = rel15->rbSize * NR_NB_SC_PER_RB;
@@ -450,7 +450,7 @@ static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
txl += no_ptrs_dmrs_case(output + start_sc, txl, amp, upper_limit);
txl += no_ptrs_dmrs_case(output, txl, amp, remaining_re);
} // no DMRS/PTRS in symbol
return txl - txl_start;
return;
}
static inline void do_txdataF(c16_t **txdataF,
@@ -548,28 +548,149 @@ static inline void do_txdataF(c16_t **txdataF,
rb += rb_step;
} // RB loop: while(rb < rel15->rbSize)
}
static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSCH_t *dlsch, int slot)
typedef struct pdschSymbolProc_s {
PHY_VARS_gNB *gNB;
NR_DL_FRAME_PARMS *frame_parms;
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15;
unsigned int slot;
unsigned int startSymbol;
unsigned int numSymbols;
task_ans_t *ans;
unsigned int layerSz2;
unsigned int dlPtrsSymPos;
unsigned int n_ptrs;
unsigned int beam_nb;
unsigned int re_beginning_of_symbol[14];
c16_t *tx_layers[4];
} pdschSymbolProc_t;
static void nr_pdsch_symbol_processing(void *arg)
{
pdschSymbolProc_t *rdata = (pdschSymbolProc_t *)arg;
PHY_VARS_gNB *gNB = rdata->gNB;
NR_DL_FRAME_PARMS *frame_parms = rdata->frame_parms;
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = rdata->rel15;
int slot = rdata->slot;
c16_t *tx_layers[rel15->nrOfLayers];
for (int l = 0; l < rel15->nrOfLayers; l++)
tx_layers[l] = rdata->tx_layers[l];
const int nb_re_dmrs = rel15->numDmrsCdmGrpsNoData * (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4);
const int n_dmrs = (rel15->BWPStart + rel15->rbStart + rel15->rbSize) * nb_re_dmrs;
// Loop Over OFDM symbols:
c16_t mod_dmrs[(n_dmrs + 63) & ~63] __attribute__((aligned(64)));
const uint32_t txdataF_offset = slot * frame_parms->samples_per_slot_wCP;
const int symbol_sz = frame_parms->ofdm_symbol_size;
c16_t **txdataF = gNB->common_vars.txdataF[rdata->beam_nb];
uint16_t start_sc = frame_parms->first_carrier_offset + (rel15->rbStart + rel15->BWPStart) * NR_NB_SC_PER_RB;
if (start_sc >= symbol_sz)
start_sc -= symbol_sz;
#ifdef DEBUG_DLSCH_MAPPING
printf("slot %d PDSCH resource mapping started (start SC %d\tstart symbol %d\tnum symbols %d\tN_PRB %d,nb_layers %d)\n",
rdata->slot,
start_sc,
rdata->startSymbol,
rdata->numSymbols,
rel15->rbSize,
rel15->nrOfLayers);
#endif
for (int l_symbol = rdata->startSymbol; l_symbol < rdata->startSymbol + rdata->numSymbols; l_symbol++) {
start_meas(&gNB->dlsch_resource_mapping_stats);
int l_prime = 0; // single symbol layer 0
int l_overline = get_l0(rel15->dlDmrsSymbPos);
#ifdef DEBUG_DLSCH_MAPPING
printf("PDSCH resource mapping symbol %d\n", l_symbol);
#endif
/// DMRS QPSK modulation
if ((rel15->dlDmrsSymbPos & (1 << l_symbol))) { // DMRS time occasion
// The reference point for is subcarrier -1 of the lowest-numbered resource block in CORESET 0 if the corresponding
// PDCCH is associated with CORESET -1 and Type0-PDCCH common search space and is addressed to SI-RNTI
// 2GPP TS 38.211 V15.8.0 Section 7.4.1.1.2 Mapping to physical resources
if (l_symbol == (l_overline + 1)) // take into account the double DMRS symbols
l_prime = 1;
else if (l_symbol > (l_overline + 1)) { // new DMRS pair
l_overline = l_symbol;
l_prime = 0;
}
#ifdef DEBUG_DLSCH_MAPPING
printf("dlDmrsScramblingId %d, SCID %d slot %d l_symbol %d\n", rel15->dlDmrsScramblingId, rel15->SCID, slot, l_symbol);
#endif
const uint32_t *gold = nr_gold_pdsch(frame_parms->N_RB_DL,
frame_parms->symbols_per_slot,
rel15->dlDmrsScramblingId,
rel15->SCID,
slot,
l_symbol);
// Qm = 1 as DMRS is QPSK modulated
nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_dmrs);
#ifdef DEBUG_DLSCH_MAPPING
printf("DMRS modulation (symbol %d, %d symbols, type %d):\n", l_symbol, n_dmrs, dmrs_Type);
for (int i = 0; i < n_dmrs / 2; i += 8) {
for (int j = 0; j < 8; j++) {
printf("%d %d\t", mod_dmrs[i + j].r, mod_dmrs[i + j].i);
}
printf("\n");
}
#endif
}
uint32_t dmrs_idx = rel15->rbStart;
if (rel15->refPoint == 0)
dmrs_idx += rel15->BWPStart;
dmrs_idx *= rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4;
c16_t txdataF_precoding[rel15->nrOfLayers][symbol_sz] __attribute__((aligned(64)));
for (int layer = 0; layer < rel15->nrOfLayers; layer++) {
do_onelayer(frame_parms,
slot,
rel15,
layer,
txdataF_precoding[layer],
tx_layers[layer] + rdata->re_beginning_of_symbol[l_symbol],
start_sc,
symbol_sz,
l_symbol,
rdata->dlPtrsSymPos,
rdata->n_ptrs,
gNB->TX_AMP,
min((double)gNB->TX_AMP * sqrt(rel15->numDmrsCdmGrpsNoData), INT16_MAX),
l_prime,
rel15->dmrsConfigType,
mod_dmrs + dmrs_idx);
} // layer loop
stop_meas(&gNB->dlsch_resource_mapping_stats);
start_meas(&gNB->dlsch_precoding_stats);
for (int ant = 0; ant < frame_parms->nb_antennas_tx; ant++) {
const size_t txdataF_offset_per_symbol = l_symbol * symbol_sz + txdataF_offset;
do_txdataF(txdataF, symbol_sz, txdataF_precoding, gNB, rel15, ant, start_sc, txdataF_offset_per_symbol);
}
stop_meas(&gNB->dlsch_precoding_stats);
}
// Task running in // completed
completed_task_ans(rdata->ans);
}
static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSCH_t *dlsch, int frame, int slot)
{
const int16_t amp = gNB->TX_AMP;
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
time_stats_t *dlsch_scrambling_stats = &gNB->dlsch_scrambling_stats;
time_stats_t *dlsch_modulation_stats = &gNB->dlsch_modulation_stats;
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu->pdsch_pdu_rel15;
const int layerSz = frame_parms->N_RB_DL * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB;
const int symbol_sz=frame_parms->ofdm_symbol_size;
const int dmrs_Type = rel15->dmrsConfigType;
const int nb_re_dmrs = rel15->numDmrsCdmGrpsNoData * (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4);
const int16_t amp_dmrs = min((double)amp * sqrt(rel15->numDmrsCdmGrpsNoData), INT16_MAX); // 3GPP TS 38.214 Section 4.1: Table 4.1-1
LOG_D(PHY,
"pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n",
rel15->BWPStart,
rel15->BWPSize,
rel15->rbStart,
rel15->rbSize);
const int n_dmrs = (rel15->BWPStart + rel15->rbStart + rel15->rbSize) * nb_re_dmrs;
const int n_dmrs = rel15->rbSize * nb_re_dmrs;
const int dmrs_symbol_map = rel15->dlDmrsSymbPos; // single DMRS: 010000100 Double DMRS 110001100
const int xOverhead = 0;
const int nb_re =
(12 * rel15->NrOfSymbols - nb_re_dmrs * get_num_dmrs(rel15->dlDmrsSymbPos) - xOverhead) * rel15->rbSize * rel15->nrOfLayers;
@@ -608,9 +729,12 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
memcpy(dlsch->f, input_ptr, (encoded_length + 7) >> 3);
c16_t mod_symbs[rel15->NrOfCodewords][encoded_length] __attribute__((aligned(64)));
int slot_type = nr_slot_select(&gNB->gNB_config, frame, slot);
for (int codeWord = 0; codeWord < rel15->NrOfCodewords; codeWord++) {
/// scrambling
start_meas(dlsch_scrambling_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
start_meas(dlsch_scrambling_stats);
}
uint32_t scrambled_output[(encoded_length >> 5) + 4]; // modulator acces by 4 bytes in some cases
memset(scrambled_output, 0, sizeof(scrambled_output));
nr_pdsch_codeword_scrambling(input_ptr, encoded_length, codeWord, rel15->dataScramblingId, rel15->rnti, scrambled_output);
@@ -624,12 +748,18 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
}
#endif
stop_meas(dlsch_scrambling_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
stop_meas(dlsch_scrambling_stats);
}
/// Modulation
start_meas(dlsch_modulation_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
start_meas(dlsch_modulation_stats);
}
nr_modulation(scrambled_output, encoded_length, Qm, (int16_t *)mod_symbs[codeWord]);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 0);
stop_meas(dlsch_modulation_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
stop_meas(dlsch_modulation_stats);
}
#ifdef DEBUG_DLSCH
printf("PDSCH Modulation: Qm %d(%d)\n", Qm, nb_re);
for (int i = 0; i < nb_re; i += 8) {
@@ -641,29 +771,18 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
#endif
}
start_meas(&gNB->dlsch_pdsch_generation_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
start_meas(&gNB->dlsch_pdsch_generation_stats);
}
/// Resource mapping
// Non interleaved VRB to PRB mapping
uint16_t start_sc = frame_parms->first_carrier_offset + (rel15->rbStart + rel15->BWPStart) * NR_NB_SC_PER_RB;
if (start_sc >= symbol_sz)
start_sc -= symbol_sz;
const uint32_t txdataF_offset = slot * frame_parms->samples_per_slot_wCP;
#ifdef DEBUG_DLSCH_MAPPING
printf("PDSCH resource mapping started (start SC %d\tstart symbol %d\tN_PRB %d\tnb_re %d,nb_layers %d)\n",
start_sc,
rel15->StartSymbolIndex,
rel15->rbSize,
nb_re,
rel15->nrOfLayers);
#endif
AssertFatal(n_dmrs, "n_dmrs can't be 0\n");
// make a large enough tail to process all re with SIMD regardless a garbadge filler
c16_t mod_dmrs[(n_dmrs+63)&~63] __attribute__((aligned(64)));
unsigned int re_beginning_of_symbol = 0;
start_meas(&gNB->dlsch_layer_mapping_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
start_meas(&gNB->dlsch_layer_mapping_stats);
}
int layerSz2 = (layerSz + 63) & ~63;
c16_t tx_layers[rel15->nrOfLayers][layerSz2] __attribute__((aligned(64)));
memset(tx_layers, 0, sizeof(tx_layers));
@@ -685,86 +804,69 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
slot,
frame_parms->symbols_per_slot,
bitmap);
c16_t **txdataF = gNB->common_vars.txdataF[beam_nb];
stop_meas(&gNB->dlsch_layer_mapping_stats);
// Loop Over OFDM symbols:
for (int l_symbol = rel15->StartSymbolIndex; l_symbol < rel15->StartSymbolIndex + rel15->NrOfSymbols; l_symbol++) {
start_meas(&gNB->dlsch_resource_mapping_stats);
int l_prime = 0; // single symbol layer 0
int l_overline = get_l0(rel15->dlDmrsSymbPos);
#ifdef DEBUG_DLSCH_MAPPING
printf("PDSCH resource mapping symbol %d\n", l_symbol);
#endif
/// DMRS QPSK modulation
if ((dmrs_symbol_map & (1 << l_symbol))) { // DMRS time occasion
// The reference point for is subcarrier -1 of the lowest-numbered resource block in CORESET 0 if the corresponding
// PDCCH is associated with CORESET -1 and Type0-PDCCH common search space and is addressed to SI-RNTI
// 2GPP TS 38.211 V15.8.0 Section 7.4.1.1.2 Mapping to physical resources
if (l_symbol == (l_overline + 1)) // take into account the double DMRS symbols
l_prime = 1;
else if (l_symbol > (l_overline + 1)) { // new DMRS pair
l_overline = l_symbol;
l_prime = 0;
}
#ifdef DEBUG_DLSCH_MAPPING
printf("dlDmrsScramblingId %d, SCID %d slot %d l_symbol %d\n", rel15->dlDmrsScramblingId, rel15->SCID, slot, l_symbol);
#endif
const uint32_t *gold = nr_gold_pdsch(frame_parms->N_RB_DL,
frame_parms->symbols_per_slot,
rel15->dlDmrsScramblingId,
rel15->SCID,
slot,
l_symbol);
// Qm = 1 as DMRS is QPSK modulated
nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_dmrs);
#ifdef DEBUG_DLSCH_MAPPING
printf("DMRS modulation (symbol %d, %d symbols, type %d):\n", l_symbol, n_dmrs, dmrs_Type);
for (int i = 0; i < n_dmrs / 2; i += 8) {
for (int j = 0; j < 8; j++) {
printf("%d %d\t", mod_dmrs[i + j].r, mod_dmrs[i + j].i);
}
printf("\n");
}
#endif
}
uint32_t dmrs_idx = rel15->rbStart;
if (rel15->refPoint == 0)
dmrs_idx += rel15->BWPStart;
dmrs_idx *= dmrs_Type == NFAPI_NR_DMRS_TYPE1 ? 6 : 4;
c16_t txdataF_precoding[rel15->nrOfLayers][symbol_sz] __attribute__((aligned(64)));
int layer_sz = 0;
for (int layer = 0; layer < rel15->nrOfLayers; layer++) {
layer_sz = do_onelayer(frame_parms,
slot,
rel15,
layer,
txdataF_precoding[layer],
tx_layers[layer] + re_beginning_of_symbol,
start_sc,
symbol_sz,
l_symbol,
dlPtrsSymPos,
n_ptrs,
amp,
amp_dmrs,
l_prime,
dmrs_Type,
mod_dmrs + dmrs_idx);
} // layer loop
re_beginning_of_symbol += layer_sz;
stop_meas(&gNB->dlsch_resource_mapping_stats);
start_meas(&gNB->dlsch_precoding_stats);
for (int ant = 0; ant < frame_parms->nb_antennas_tx; ant++) {
const size_t txdataF_offset_per_symbol = l_symbol * symbol_sz + txdataF_offset;
do_txdataF(txdataF, symbol_sz, txdataF_precoding, gNB, rel15, ant, start_sc, txdataF_offset_per_symbol);
}
stop_meas(&gNB->dlsch_precoding_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
stop_meas(&gNB->dlsch_layer_mapping_stats);
}
// spawn symbol threads
int nb_tasks = 1;
int num_pdsch_symbols_per_task = rel15->NrOfSymbols;
if (gNB->num_pdsch_symbols_per_thread > 0) {
// symbol processing in thread pool enabled
num_pdsch_symbols_per_task = gNB->num_pdsch_symbols_per_thread;
nb_tasks = rel15->NrOfSymbols / num_pdsch_symbols_per_task;
if ((rel15->NrOfSymbols % num_pdsch_symbols_per_task) > 0)
nb_tasks++;
}
pdschSymbolProc_t arr[nb_tasks];
task_ans_t ans;
init_task_ans(&ans, nb_tasks);
int sz_arr = 0;
unsigned int re_beginning_of_symbol = 0;
int res = 0;
for (int l_symbol = rel15->StartSymbolIndex; l_symbol < rel15->StartSymbolIndex + rel15->NrOfSymbols;
l_symbol += num_pdsch_symbols_per_task) {
pdschSymbolProc_t *rdata = &arr[sz_arr];
rdata->ans = &ans;
++sz_arr;
rdata->gNB = gNB;
rdata->frame_parms = frame_parms;
rdata->rel15 = rel15;
rdata->slot = slot;
rdata->startSymbol = l_symbol;
res = rel15->NrOfSymbols - (l_symbol - rel15->StartSymbolIndex);
if (res >= num_pdsch_symbols_per_task)
rdata->numSymbols = num_pdsch_symbols_per_task;
else
rdata->numSymbols = res;
rdata->layerSz2 = layerSz2;
rdata->dlPtrsSymPos = dlPtrsSymPos;
rdata->n_ptrs = n_ptrs;
rdata->beam_nb = beam_nb;
for (int s = l_symbol; s < l_symbol + rdata->numSymbols; s++) {
rdata->re_beginning_of_symbol[s] = re_beginning_of_symbol;
re_beginning_of_symbol += rel15->rbSize * NR_NB_SC_PER_RB;
if (n_ptrs > 0 && is_ptrs_symbol(s, dlPtrsSymPos)) {
re_beginning_of_symbol -= n_ptrs;
} else if (rel15->dlDmrsSymbPos & (1 << s)) {
re_beginning_of_symbol -= n_dmrs;
}
}
for (int l = 0; l < rel15->nrOfLayers; l++)
rdata->tx_layers[l] = tx_layers[l];
if (l_symbol < rel15->StartSymbolIndex + rel15->NrOfSymbols - num_pdsch_symbols_per_task) {
task_t t = {.func = &nr_pdsch_symbol_processing, .args = rdata};
pushTpool(&gNB->threadPool, t);
} else {
nr_pdsch_symbol_processing(rdata);
}
}
join_task_ans(&ans);
if (slot_type == NR_DOWNLINK_SLOT) {
stop_meas(&gNB->dlsch_pdsch_generation_stats);
}
stop_meas(&gNB->dlsch_pdsch_generation_stats);
/* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits)
* should remain a multiple of 8 * 64 with enough offset to fit each dlsch
*/
@@ -827,7 +929,10 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
unsigned char output[size_output >> 3] __attribute__((aligned(64)));
bzero(output, sizeof(output));
start_meas(dlsch_encoding_stats);
int slot_type = nr_slot_select(&gNB->gNB_config, frame, slot);
if (slot_type == NR_DOWNLINK_SLOT) {
start_meas(dlsch_encoding_stats);
}
if (nr_dlsch_encoding(gNB,
n_dlsch,
dlsch_array,
@@ -845,11 +950,13 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
== -1) {
return;
}
stop_meas(dlsch_encoding_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
stop_meas(dlsch_encoding_stats);
}
unsigned char *output_ptr = output;
for (int i = 0; i < n_dlsch; i++) {
output_ptr += do_one_dlsch(output_ptr, gNB, &dlsch_array[i], slot);
output_ptr += do_one_dlsch(output_ptr, gNB, &dlsch_array[i], frame, slot);
}
}

View File

@@ -125,6 +125,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
int num_segments = 0;
int slot_type = nr_slot_select(&gNB->gNB_config, frame, slot);
for (int i = 0; i < n_dlsch; i++) {
NR_gNB_DLSCH_t *dlsch = &dlsch_array[i];
@@ -190,7 +191,9 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
TB_parameters->harq_unique_pid = i;
TB_parameters->BG = rel15->maintenance_parms_v3.ldpcBaseGraph;
TB_parameters->A = A;
start_meas(dlsch_segmentation_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
start_meas(dlsch_segmentation_stats);
}
TB_parameters->Kb = nr_segmentation(dlsch->b,
dlsch->c,
B,
@@ -199,7 +202,9 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
&TB_parameters->Z,
&TB_parameters->F,
TB_parameters->BG);
stop_meas(dlsch_segmentation_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
stop_meas(dlsch_segmentation_stats);
}
if (TB_parameters->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * rel15->nrOfLayers) {
LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", TB_parameters->C, B);
@@ -286,9 +291,11 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[i];
for (int r = 0; r < TB_parameters->C; r++) {
nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r];
merge_meas(dlsch_interleaving_stats, &segment_parameters->ts_interleave);
merge_meas(dlsch_rate_matching_stats, &segment_parameters->ts_rate_match);
// merge_meas(, &segment_parameters->ts_ldpc_encode);
if (slot_type == NR_DOWNLINK_SLOT) {
merge_meas(dlsch_interleaving_stats, &segment_parameters->ts_interleave);
merge_meas(dlsch_rate_matching_stats, &segment_parameters->ts_rate_match);
// merge_meas(, &segment_parameters->ts_ldpc_encode);
}
}
}

View File

@@ -279,7 +279,14 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
}
}
int slot_type = nr_slot_select(&phy_vars_gNB->gNB_config, frame, nr_tti_rx);
if (slot_type == NR_UPLINK_SLOT) {
start_meas(&phy_vars_gNB->ulsch_decoding_stats);
}
int ret_decoder = phy_vars_gNB->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters);
if (slot_type == NR_UPLINK_SLOT) {
stop_meas(&phy_vars_gNB->ulsch_decoding_stats);
}
// post decode
for (uint8_t pusch_id = 0; pusch_id < nb_pusch; pusch_id++) {
@@ -303,9 +310,11 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
}
offset += ((harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
merge_meas(&phy_vars_gNB->ts_deinterleave, &nrLDPC_segment_decoding_parameters.ts_deinterleave);
merge_meas(&phy_vars_gNB->ts_rate_unmatch, &nrLDPC_segment_decoding_parameters.ts_rate_unmatch);
merge_meas(&phy_vars_gNB->ts_ldpc_decode, &nrLDPC_segment_decoding_parameters.ts_ldpc_decode);
if (slot_type == NR_UPLINK_SLOT) {
merge_meas(&phy_vars_gNB->ts_deinterleave, &nrLDPC_segment_decoding_parameters.ts_deinterleave);
merge_meas(&phy_vars_gNB->ts_rate_unmatch, &nrLDPC_segment_decoding_parameters.ts_rate_unmatch);
merge_meas(&phy_vars_gNB->ts_ldpc_decode, &nrLDPC_segment_decoding_parameters.ts_ldpc_decode);
}
}
}

View File

@@ -16,6 +16,7 @@ int cpu_meas_enabled;
THREAD_STRUCT thread_struct;
uint32_t target_ul_mcs = 9;
uint32_t target_dl_mcs = 9;
uint32_t target_dl_pmi = 0;
uint64_t dlsch_slot_bitmap = (1<<1);
uint64_t ulsch_slot_bitmap = (1<<8);
uint32_t target_ul_bw = 50;

View File

@@ -493,6 +493,7 @@ typedef struct PHY_VARS_gNB_s {
notifiedFIFO_t L1_rx_out;
tpool_t threadPool;
int num_pusch_symbols_per_thread;
int num_pdsch_symbols_per_thread;
int dmrs_num_antennas_per_thread;
pthread_t L1_rx_thread;
int L1_rx_thread_core;

View File

@@ -333,7 +333,10 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
}
//apply the OFDM symbol rotation here
start_meas(&gNB->phase_comp_stats);
int slot_type = nr_slot_select(&gNB->gNB_config, frame, slot);
if (slot_type == NR_DOWNLINK_SLOT) {
start_meas(&gNB->phase_comp_stats);
}
for (int i = 0; i < gNB->common_vars.num_beams_period; ++i) {
for (int aa = 0; aa < cfg->carrier_config.num_tx_ant.value; aa++) {
if (gNB->phase_comp) {
@@ -353,7 +356,9 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
T_BUFFER(&gNB->common_vars.txdataF[i][aa][txdataF_offset], fp->samples_per_slot_wCP * sizeof(int32_t)));
}
}
stop_meas(&gNB->phase_comp_stats);
if (slot_type == NR_DOWNLINK_SLOT) {
stop_meas(&gNB->phase_comp_stats);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_TX + gNB->CC_id, 0);
}
@@ -1027,7 +1032,10 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
}
const int soffset = (slot_rx & 3) * nb_symb * ofdm_symbol_size;
start_meas(&gNB->phy_proc_rx);
int slot_type = nr_slot_select(&gNB->gNB_config, frame_rx, slot_rx);
if (slot_type == NR_UPLINK_SLOT) {
start_meas(&gNB->phy_proc_rx);
}
for (int i = 0; i < gNB->max_nb_pucch; i++) {
NR_gNB_PUCCH_t *pucch = &gNB->pucch[i];
@@ -1385,7 +1393,9 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
stop_meas(&gNB->rx_srs_stats);
}
stop_meas(&gNB->phy_proc_rx);
if (slot_type == NR_UPLINK_SLOT) {
stop_meas(&gNB->phy_proc_rx);
}
if (pucch_decode_done || pusch_decode_done) {
T(T_GNB_PHY_PUCCH_PUSCH_IQ,

View File

@@ -394,6 +394,7 @@ int main(int argc, char **argv)
uint8_t dlsch_threads = 0;
int chest_type[2] = {0};
uint8_t max_ldpc_iterations = 5;
int num_pdsch_symbols_per_thread = 0;
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) {
exit_fun("[NR_DLSIM] Error, configuration module init failed\n");
}
@@ -584,6 +585,10 @@ int main(int argc, char **argv)
gNBthreads[sizeof(gNBthreads)-1]=0;
break;
case 'Y':
num_pdsch_symbols_per_thread = atoi(optarg);
break;
case 'Z' :
filename_csv = strdup(optarg);
AssertFatal(filename_csv != NULL, "strdup() error: errno %d\n", errno);
@@ -653,6 +658,7 @@ int main(int argc, char **argv)
printf("-T Enable PTRS, arguments list L_PTRS{0,1,2} K_PTRS{2,4}, e.g. -T 2 0 2 \n");
printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:2} DMRS ConfType{1:2}, e.g. -U 3 0 2 1 \n");
printf("-X gNB thread pool configuration, n => no threads\n");
printf("-Y Number of symbols processed per PDSCH generation thread\n");
printf("-Z Output filename (.csv format) for stats\n");
exit (-1);
break;
@@ -686,6 +692,7 @@ int main(int argc, char **argv)
AssertFatal((gNB->if_inst = NR_IF_Module_init(0)) != NULL, "Cannot register interface");
gNB->if_inst->NR_PHY_config_req = nr_phy_config_request;
gNB->num_pdsch_symbols_per_thread = num_pdsch_symbols_per_thread;
NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(*scc));;
prepare_scc(scc);

View File

@@ -51,6 +51,7 @@ static bool is_xlsch_in_slot(uint64_t bitmap, slot_t slot)
uint32_t target_dl_mcs = 9;
uint32_t target_dl_Nl = 1;
uint32_t target_dl_pmi = 0;
uint32_t target_dl_bw = 50;
uint64_t dlsch_slot_bitmap = (1<<1);
@@ -189,7 +190,7 @@ void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch)
// tbSize further below
.dl_harq_pid = sched_ctrl->retrans_dl_harq.head, // PID of HARQ awaiting retransmission, or -1 otherwise
.pucch_allocation = alloc,
.pm_index = 0,
.pm_index = target_dl_pmi,
.nrOfLayers = target_dl_Nl,
.bwp_info = get_pdsch_bwp_start_size(mac, UE),
.dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, &tda_info, target_dl_Nl),