From b1a4d4ead4ad82abb0d157ff913f29261c888bba Mon Sep 17 00:00:00 2001 From: Wang Tsu-Han Date: Mon, 5 Nov 2018 15:04:32 +0100 Subject: [PATCH] adding parallel structure --- openair1/PHY/defs_RU.h | 2 - openair2/GNB_APP/gnb_config.c | 36 ++++- openair2/GNB_APP/gnb_paramdef.h | 26 ++++ targets/RT/USER/nr-gnb.c | 174 ++++++++++++++++++++++-- targets/RT/USER/nr-ru.c | 234 +++++++++++++++++++++++++------- 5 files changed, 408 insertions(+), 64 deletions(-) diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 3ad007813e..6f68ee0fb4 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -304,8 +304,6 @@ typedef struct RU_proc_t_s { int instance_pre_scd; #endif /// pipeline ready state - int ru_rx_ready; - int ru_tx_ready; int emulate_rf_busy; } RU_proc_t; diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index ac5c8e8b5a..db1bc52090 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -77,6 +77,10 @@ #include "NR_EUTRA-MBSFN-SubframeConfig.h" extern uint16_t sf_ahead; +extern void set_parallel_conf(char *parallel_conf); +extern void set_worker_conf(char *worker_conf); +extern PARALLEL_CONF_t get_thread_parallel_conf(void); +extern WORKER_CONF_t get_thread_worker_conf(void); void RCconfig_nr_flexran() { @@ -2976,6 +2980,36 @@ int RCconfig_NR_S1(MessageDef *msg_p, uint32_t i) { return 0; } +int RCconfig_nr_parallel(void) { + char *parallel_conf = NULL; + char *worker_conf = NULL; + extern char *parallel_config; + extern char *worker_config; + paramdef_t ThreadParams[] = THREAD_CONF_DESC; + paramlist_def_t THREADParamList = {THREAD_CONFIG_STRING_THREAD_STRUCT,NULL,0}; + config_getlist( &THREADParamList,NULL,0,NULL); + + if(THREADParamList.numelt>0) { + config_getlist( &THREADParamList,ThreadParams,sizeof(ThreadParams)/sizeof(paramdef_t),NULL); + parallel_conf = strdup(*(THREADParamList.paramarray[0][THREAD_PARALLEL_IDX].strptr)); + } else { + parallel_conf = strdup("PARALLEL_RU_L1_TRX_SPLIT"); + } + + if(THREADParamList.numelt>0) { + config_getlist( &THREADParamList,ThreadParams,sizeof(ThreadParams)/sizeof(paramdef_t),NULL); + worker_conf = strdup(*(THREADParamList.paramarray[0][THREAD_WORKER_IDX].strptr)); + } else { + worker_conf = strdup("WORKER_ENABLE"); + } + + if(parallel_config == NULL) set_parallel_conf(parallel_conf); + + if(worker_config == NULL) set_worker_conf(worker_conf); + + return 0; +} + void NRRCConfig(void) { paramlist_def_t MACRLCParamList = {CONFIG_STRING_MACRLC_LIST,NULL,0}; @@ -3016,7 +3050,7 @@ void NRRCConfig(void) { config_getlist( &RUParamList,NULL,0, NULL); RC.nb_RU = RUParamList.numelt; - RCconfig_parallel(); + RCconfig_nr_parallel(); } diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index fd59f83097..a457a3b1a4 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -1099,3 +1099,29 @@ typedef enum { #define MACRLC_REMOTE_S_PORTD_IDX 16 #define MACRLC_SCHED_MODE_IDX 17 #define MACRLC_PHY_TEST_IDX 18 + + +/* thread configuration parameters section name */ +#define THREAD_CONFIG_STRING_THREAD_STRUCT "THREAD_STRUCT" + +/* thread configuration parameters names */ +#define THREAD_CONFIG_STRING_PARALLEL "parallel_config" +#define THREAD_CONFIG_STRING_WORKER "worker_config" + + +#define THREAD_PARALLEL_IDX 0 +#define THREAD_WORKER_IDX 1 + +/*-------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* thread configuration parameters */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*-------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define THREAD_CONF_DESC { \ +{THREAD_CONFIG_STRING_PARALLEL, CONFIG_HLP_PARALLEL, 0, strptr:NULL, defstrval:"PARALLEL_RU_L1_TRX_SPLIT", TYPE_STRING, 0}, \ +{THREAD_CONFIG_STRING_WORKER, CONFIG_HLP_WORKER, 0, strptr:NULL, defstrval:"WORKER_ENABLE", TYPE_STRING, 0} \ +} + + +#define CONFIG_HLP_WORKER "coding and FEP worker thread WORKER_DISABLE or WORKER_ENABLE\n" +#define CONFIG_HLP_PARALLEL "PARALLEL_SINGLE_THREAD, PARALLEL_RU_L1_SPLIT, or PARALLEL_RU_L1_TRX_SPLIT(RU_L1_TRX_SPLIT by defult)\n" +/*-------------------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/targets/RT/USER/nr-gnb.c b/targets/RT/USER/nr-gnb.c index 0f2866cdca..34e9f295fd 100644 --- a/targets/RT/USER/nr-gnb.c +++ b/targets/RT/USER/nr-gnb.c @@ -143,6 +143,11 @@ extern double cpuf; void init_gNB(int,int); void stop_gNB(int nb_inst); +int wakeup_txfh(gNB_L1_rxtx_proc_t *proc,PHY_VARS_gNB *gNB); +int wakeup_tx(PHY_VARS_gNB *gNB); +extern PARALLEL_CONF_t get_thread_parallel_conf(void); +extern WORKER_CONF_t get_thread_worker_conf(void); + void wakeup_prach_gNB(PHY_VARS_gNB *gNB,RU_t *ru,int frame,int subframe); @@ -227,7 +232,9 @@ static inline int rxtx(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc, char *thread_ //if (wait_CCs(proc)<0) return(-1); if (oai_exit) return(-1); - phy_procedures_gNB_TX(gNB, proc, 1); + if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD){ + phy_procedures_gNB_TX(gNB, proc, 1); + } stop_meas( &softmodem_stats_rxtx_sf ); @@ -278,6 +285,44 @@ static inline int rxtx(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc, char *thread_ return(0); } +static void* gNB_L1_thread_tx(void* param) { + + gNB_L1_proc_t *gNB_proc = (gNB_L1_proc_t*)param; + gNB_L1_rxtx_proc_t *proc = &gNB_proc->L1_proc_tx; + PHY_VARS_gNB *gNB = RC.gNB[0][proc->CC_id]; + + char thread_name[100]; + sprintf(thread_name,"TXnp4_%d\n",&gNB->proc.L1_proc == proc ? 0 : 1); + thread_top_init(thread_name,1,470000,500000,500000); + + //wait_sync("tx_thread"); + + while (!oai_exit) { + + + if (wait_on_condition(&proc->mutex,&proc->cond,&proc->instance_cnt,thread_name)<0) break; + if (oai_exit) break; + // ***************************************** + // TX processing for subframe n+4 + // run PHY TX procedures the one after the other for all CCs to avoid race conditions + // (may be relaxed in the future for performance reasons) + // ***************************************** + + phy_procedures_gNB_TX(gNB, proc, 1); + + pthread_mutex_lock( &proc->mutex ); + proc->instance_cnt = -1; + // the thread can now be woken up + if (pthread_cond_signal(&proc->cond) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + } + pthread_mutex_unlock( &proc->mutex ); + wakeup_txfh(proc,gNB); + } + + return 0; +} /*! * \brief The RX UE-specific and TX thread of gNB. @@ -285,11 +330,11 @@ static inline int rxtx(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc, char *thread_ * \returns a pointer to an int. The storage is not on the heap and must not be freed. */ -static void* gNB_thread_rxtx( void* param ) { +static void* gNB_L1_thread( void* param ) { static int gNB_thread_rxtx_status; - - gNB_L1_rxtx_proc_t *proc = (gNB_L1_rxtx_proc_t*)param; + gNB_L1_proc_t *gNB_proc = (gNB_L1_proc_t*)param; + gNB_L1_rxtx_proc_t *proc = &gNB_proc->L1_proc; PHY_VARS_gNB *gNB = RC.gNB[0][proc->CC_id]; char thread_name[100]; @@ -303,11 +348,9 @@ static void* gNB_thread_rxtx( void* param ) { thread_top_init(thread_name,1,850000L,1000000L,2000000L); while (!oai_exit) { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); if (wait_on_condition(&proc->mutex,&proc->cond,&proc->instance_cnt,thread_name)<0) break; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 1 ); if (oai_exit) break; @@ -316,12 +359,19 @@ static void* gNB_thread_rxtx( void* param ) { if (rxtx(gNB,proc,thread_name) < 0) break; } - + if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT){ + phy_procedures_gNB_TX(gNB, proc, 1); + } if (release_thread(&proc->mutex,&proc->instance_cnt,thread_name)<0) break; + if(get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT){ + wakeup_tx(gNB); + } + else if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT){ + wakeup_txfh(proc,gNB); + } } // while !oai_exit - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); LOG_D(PHY, " *** Exiting gNB thread RXn_TXnp4\n"); @@ -379,6 +429,101 @@ void gNB_top(PHY_VARS_gNB *gNB, int frame_rx, int subframe_rx, char *string, str } } +int wakeup_txfh(gNB_L1_rxtx_proc_t *proc,PHY_VARS_gNB *gNB) { + + RU_t *ru; + RU_proc_t *ru_proc; + + + struct timespec wait; + wait.tv_sec=0; + wait.tv_nsec=5000000L; +//printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~inside wakeup_txfh %d.%d IC_RU = %d\n", proc->frame_tx, proc->subframe_tx, proc->instance_cnt_RUs); + + if(wait_on_condition(&proc->mutex_RUs,&proc->cond_RUs,&proc->instance_cnt_RUs,"wakeup_txfh")<0) { + LOG_E(PHY,"Frame %d, subframe %d: TX FH not ready\n", proc->frame_tx, proc->subframe_tx); + return(-1); + } + pthread_mutex_lock(&gNB->proc.mutex_RU_tx); + gNB->proc.RU_mask_tx = 0; + pthread_mutex_unlock(&gNB->proc.mutex_RU_tx); + if (release_thread(&proc->mutex_RUs,&proc->instance_cnt_RUs,"wakeup_txfh")<0) return(-1); + + for(int i=0; inum_RU; i++) + { + ru = gNB->RU_list[i]; + ru_proc = &ru->proc; + if (ru_proc->instance_cnt_gNBs == 0) { + LOG_E(PHY,"Frame %d, subframe %d: TX FH thread busy, dropping Frame %d, subframe %d\n", ru_proc->frame_tx, ru_proc->subframe_tx, proc->frame_rx, proc->subframe_rx); + return(-1); + } + if (pthread_mutex_timedlock(&ru_proc->mutex_gNBs,&wait) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB TX1 thread %d (IC %d)\n", ru_proc->subframe_rx&1,ru_proc->instance_cnt_gNBs ); + exit_fun( "error locking mutex_gNB" ); + return(-1); + } + + ru_proc->instance_cnt_gNBs = 0; + ru_proc->timestamp_tx = proc->timestamp_tx; + ru_proc->subframe_tx = proc->subframe_tx; + ru_proc->frame_tx = proc->frame_tx; + + + // the thread can now be woken up + if (pthread_cond_signal(&ru_proc->cond_gNBs) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + pthread_mutex_unlock( &ru_proc->mutex_gNBs ); + } + + return(0); +} + +int wakeup_tx(PHY_VARS_gNB *gNB) { + + gNB_L1_proc_t *proc=&gNB->proc; + + gNB_L1_rxtx_proc_t *L1_proc_tx = &proc->L1_proc_tx; + gNB_L1_rxtx_proc_t *L1_proc = &proc->L1_proc; + + + struct timespec wait; + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + + if (pthread_mutex_timedlock(&L1_proc_tx->mutex,&wait) != 0) { + LOG_E(PHY, "[SCHED][eNB] ERROR locking mutex for eNB L1_thread_tx\n"); + exit_fun("ERROR pthread_lock"); + return(-1); + } + while(L1_proc_tx->instance_cnt == 0){ + pthread_cond_wait(&L1_proc_tx->cond,&L1_proc_tx->mutex); + } + + L1_proc_tx->instance_cnt = 0; + + + L1_proc_tx->subframe_rx = L1_proc->subframe_rx; + L1_proc_tx->frame_rx = L1_proc->frame_rx; + L1_proc_tx->subframe_tx = L1_proc->subframe_tx; + L1_proc_tx->frame_tx = L1_proc->frame_tx; + L1_proc_tx->timestamp_tx = L1_proc->timestamp_tx; + + // the thread can now be woken up + if (pthread_cond_signal(&L1_proc_tx->cond) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + pthread_mutex_unlock( &L1_proc_tx->mutex); + + return(0); +} int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { @@ -619,13 +764,15 @@ void init_gNB_proc(int inst) { // pthread_attr_init( &proc->attr_te); pthread_attr_init( &L1_proc->attr); pthread_attr_init( &L1_proc_tx->attr); + attr0 = &L1_proc->attr; + attr1 = &L1_proc_tx->attr; LOG_I(PHY,"gNB->single_thread_flag:%d\n", gNB->single_thread_flag); - /*if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) { - pthread_create( &L1_proc->pthread, attr0, L1_thread, proc ); - pthread_create( &L1_proc_tx->pthread, attr1, L1_thread_tx, proc); - }*/ + if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) { + pthread_create( &L1_proc->pthread, attr0, gNB_L1_thread, proc ); + pthread_create( &L1_proc_tx->pthread, attr1, gNB_L1_thread_tx, proc); + } //pthread_create( &proc->pthread_prach, attr_prach, gNB_thread_prach, gNB ); char name[16]; @@ -693,8 +840,7 @@ void kill_gNB_proc(int inst) { LOG_I(PHY, "Destroying UL_INFO mutex\n"); pthread_mutex_destroy(&gNB->UL_INFO_mutex); - int i; - if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && nfapi_mode!=2) { + if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) { LOG_I(PHY, "Joining L1_proc mutex/cond\n"); pthread_join( L1_proc->pthread, (void**)&status ); LOG_I(PHY, "Joining L1_proc_tx mutex/cond\n"); diff --git a/targets/RT/USER/nr-ru.c b/targets/RT/USER/nr-ru.c index e11b8ee781..83410608e6 100644 --- a/targets/RT/USER/nr-ru.c +++ b/targets/RT/USER/nr-ru.c @@ -118,6 +118,9 @@ extern void nr_phy_init_RU(RU_t*); extern void nr_phy_free_RU(RU_t*); extern void nr_phy_config_request(NR_PHY_Config_t *gNB); +extern PARALLEL_CONF_t get_thread_parallel_conf(void); +extern WORKER_CONF_t get_thread_worker_conf(void); + void init_RU(char*); void stop_RU(int nb_ru); void do_ru_sync(RU_t *ru); @@ -1131,12 +1134,12 @@ void do_ru_synch(RU_t *ru) { -void wakeup_gNBs(RU_t *ru) { +void wakeup_gNB_L1s(RU_t *ru) { int i; PHY_VARS_gNB **gNB_list = ru->gNB_list; - LOG_D(PHY,"wakeup_gNBs (num %d) for RU %d ru->gNB_top:%p\n",ru->num_gNB,ru->idx, ru->gNB_top); + LOG_D(PHY,"wakeup_gNB_L1s (num %d) for RU %d ru->gNB_top:%p\n",ru->num_gNB,ru->idx, ru->gNB_top); if (ru->num_gNB==1 && ru->gNB_top!=0) { // call gNB function directly @@ -1378,6 +1381,118 @@ static void* ru_stats_thread(void* param) { return(NULL); } +static void* ru_thread_tx( void* param ) { + RU_t *ru = (RU_t*)param; + RU_proc_t *proc = &ru->proc; + PHY_VARS_gNB *gNB; + gNB_L1_proc_t *gNB_proc; + gNB_L1_rxtx_proc_t *L1_proc; + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + char filename[40]; + int print_frame = 2; + int i = 0; + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + + + thread_top_init("ru_thread_tx",1,400000,500000,500000); + + //CPU_SET(5, &cpuset); + //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + //wait_sync("ru_thread_tx"); + + wait_on_condition(&proc->mutex_FH1,&proc->cond_FH1,&proc->instance_cnt_FH1,"ru_thread_tx"); + + + printf( "ru_thread_tx ready\n"); + while (!oai_exit) { + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD_TX,sched_getcpu()); + if (oai_exit) break; + + + LOG_I(PHY,"ru_thread_tx: Waiting for TX processing\n"); + // wait until eNBs are finished subframe RX n and TX n+4 + wait_on_condition(&proc->mutex_gNBs,&proc->cond_gNBs,&proc->instance_cnt_gNBs,"ru_thread_tx"); + if (oai_exit) break; + + // do TX front-end processing if needed (precoding and/or IDFTs) + if (ru->feptx_prec) ru->feptx_prec(ru); + + // do OFDM if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); + if(!emulate_rf){ + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); + + if (ru->fh_north_out) ru->fh_north_out(ru); + } + else + { + if(proc->frame_tx == print_frame) + { + for (i=0; inb_tx; i++) + { + sprintf(filename,"tx%ddataF_frame%d_sf%d.m", i, print_frame, proc->subframe_tx); + LOG_M(filename,"txdataF_frame",&ru->common.txdataF_BF[i][0],fp->samples_per_subframe_wCP, 1, 1); + if(proc->subframe_tx == 9) + { + sprintf(filename,"tx%ddata_frame%d.m", i, print_frame); + LOG_M(filename,"txdata_frame",&ru->common.txdata[i][0],fp->samples_per_frame, 1, 1); + sprintf(filename,"tx%ddata_frame%d.dat", i, print_frame); + FILE *output_fd = fopen(filename,"w"); + if (output_fd) { + fwrite(&ru->common.txdata[i][0], + sizeof(int32_t), + fp->samples_per_frame, + output_fd); + fclose(output_fd); + } + else { + LOG_E(PHY,"Cannot write to file %s\n",filename); + } + }//if(proc->subframe_tx == 9) + }//for (i=0; inb_tx; i++) + }//if(proc->frame_tx == print_frame) + }//else emulate_rf + release_thread(&proc->mutex_gNBs,&proc->instance_cnt_gNBs,"ru_thread_tx"); + for(i = 0; inum_gNB; i++) + { + gNB = ru->gNB_list[i]; + gNB_proc = &gNB->proc; + L1_proc = (get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)? &gNB_proc->L1_proc_tx : &gNB_proc->L1_proc; + pthread_mutex_lock(&gNB_proc->mutex_RU_tx); + for (int j=0;jnum_RU;j++) { + if (ru == gNB->RU_list[j]) { + if ((gNB_proc->RU_mask_tx&(1< 0) + LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information from RU tx %d (num_RU %d,mask %x) has not been served yet!\n", + gNB->Mod_id,gNB_proc->frame_rx,gNB_proc->subframe_rx,ru->idx,gNB->num_RU,gNB_proc->RU_mask_tx); + gNB_proc->RU_mask_tx |= (1<RU_mask_tx != (1<num_RU)-1) { // not all RUs have provided their information so return + pthread_mutex_unlock(&gNB_proc->mutex_RU_tx); + } + else { // all RUs TX are finished so send the ready signal to eNB processing + gNB_proc->RU_mask_tx = 0; + pthread_mutex_unlock(&gNB_proc->mutex_RU_tx); + + pthread_mutex_lock( &L1_proc->mutex_RUs); + L1_proc->instance_cnt_RUs = 0; + // the thread can now be woken up + if (pthread_cond_signal(&L1_proc->cond_RUs) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + } + pthread_mutex_unlock( &L1_proc->mutex_RUs ); + } + } + } + release_thread(&proc->mutex_FH1,&proc->instance_cnt_FH1,"ru_thread_tx"); + return 0; +} + static void* ru_thread( void* param ) { static int ru_thread_status; @@ -1440,6 +1555,11 @@ static void* ru_thread( void* param ) { RC.ru_mask &= ~(1<idx); pthread_cond_signal(&RC.ru_cond); pthread_mutex_unlock(&RC.ru_mutex); + + pthread_mutex_lock(&proc->mutex_FH1); + proc->instance_cnt_FH1 = 0; + pthread_mutex_unlock(&proc->mutex_FH1); + pthread_cond_signal(&proc->cond_FH1); wait_sync("ru_thread"); @@ -1514,53 +1634,66 @@ static void* ru_thread( void* param ) { wakeup_slaves(proc); // wakeup all gNB processes waiting for this RU - if (ru->num_gNB>0) wakeup_gNBs(ru); + if (ru->num_gNB>0) wakeup_gNB_L1s(ru); - // wait until gNBs are finished subframe RX n and TX n+sf_ahead - wait_on_condition(&proc->mutex_gNBs,&proc->cond_gNBs,&proc->instance_cnt_gNBs,"ru_thread"); - - - // do TX front-end processing if needed (precoding and/or IDFTs) - if (ru->feptx_prec) ru->feptx_prec(ru); - - // do OFDM if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); - if(!emulate_rf) - { - // do outgoing fronthaul (south) if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); - - if (ru->fh_north_out) ru->fh_north_out(ru); - } - else - { - if(proc->frame_tx == print_frame) - { - for (i=0; inb_tx; i++) - { - sprintf(filename,"tx%ddataF_frame%d_sf%d.m", i, print_frame, proc->subframe_tx); - LOG_M(filename,"txdataF_frame",&ru->common.txdataF_BF[i][0],fp->samples_per_subframe_wCP, 1, 1); - if(proc->subframe_tx == 9) - { - sprintf(filename,"tx%ddata_frame%d.m", i, print_frame); - LOG_M(filename,"txdata_frame",&ru->common.txdata[i][0],fp->samples_per_frame, 1, 1); - sprintf(filename,"tx%ddata_frame%d.dat", i, print_frame); - FILE *output_fd = fopen(filename,"w"); - if (output_fd) { - fwrite(&ru->common.txdata[i][0], - sizeof(int32_t), - fp->samples_per_frame, - output_fd); - fclose(output_fd); - } - else { - LOG_E(PHY,"Cannot write to file %s\n",filename); - } - } - } + if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD || ru->num_eNB==0){ + // do TX front-end processing if needed (precoding and/or IDFTs) + if (ru->feptx_prec) ru->feptx_prec(ru); + + // do OFDM if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); + if(!emulate_rf){ + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); + + if (ru->fh_north_out) ru->fh_north_out(ru); } - //else if (proc->frame_tx > print_frame) oai_exit = 1; + proc->emulate_rf_busy = 0; } + + if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) + { + // do TX front-end processing if needed (precoding and/or IDFTs) + if (ru->feptx_prec) ru->feptx_prec(ru); + + // do OFDM if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); + if(!emulate_rf) + { + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); + + if (ru->fh_north_out) ru->fh_north_out(ru); + } + else + { + if(proc->frame_tx == print_frame) + { + for (i=0; inb_tx; i++) + { + sprintf(filename,"tx%ddataF_frame%d_sf%d.m", i, print_frame, proc->subframe_tx); + LOG_M(filename,"txdataF_frame",&ru->common.txdataF_BF[i][0],fp->samples_per_subframe_wCP, 1, 1); + if(proc->subframe_tx == 9) + { + sprintf(filename,"tx%ddata_frame%d.m", i, print_frame); + LOG_M(filename,"txdata_frame",&ru->common.txdata[i][0],fp->samples_per_frame, 1, 1); + sprintf(filename,"tx%ddata_frame%d.dat", i, print_frame); + FILE *output_fd = fopen(filename,"w"); + if (output_fd) { + fwrite(&ru->common.txdata[i][0], + sizeof(int32_t), + fp->samples_per_frame, + output_fd); + fclose(output_fd); + } + else { + LOG_E(PHY,"Cannot write to file %s\n",filename); + } + }//if(proc->subframe_tx == 9) + }//for (i=0; inb_tx; i++) + }//if(proc->frame_tx == print_frame) + }//else emulate_rf + }//if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) } @@ -1680,7 +1813,7 @@ void init_RU_proc(RU_t *ru) { int i=0; RU_proc_t *proc; - pthread_attr_t *attr_FH=NULL,*attr_prach=NULL,*attr_asynch=NULL, *attr_emulateRF=NULL;// *attr_synch=NULL; + pthread_attr_t *attr_FH=NULL, *attr_FH1=NULL,*attr_prach=NULL,*attr_asynch=NULL, *attr_emulateRF=NULL;// *attr_synch=NULL; //pthread_attr_t *attr_fep=NULL; #if (RRC_VERSION >= MAKE_VERSION(14, 0, 0)) //pthread_attr_t *attr_prach_br=NULL; @@ -1697,6 +1830,7 @@ void init_RU_proc(RU_t *ru) { proc->instance_cnt_prach = -1; proc->instance_cnt_synch = -1; ; proc->instance_cnt_FH = -1; + proc->instance_cnt_FH1 = -1; proc->instance_cnt_asynch_rxtx = -1; proc->instance_cnt_emulateRF = -1; proc->first_rx = 1; @@ -1711,17 +1845,20 @@ void init_RU_proc(RU_t *ru) { pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); pthread_mutex_init( &proc->mutex_synch,NULL); pthread_mutex_init( &proc->mutex_FH,NULL); + pthread_mutex_init( &proc->mutex_FH1,NULL); pthread_mutex_init( &proc->mutex_emulateRF,NULL); pthread_mutex_init( &proc->mutex_gNBs, NULL); pthread_cond_init( &proc->cond_prach, NULL); pthread_cond_init( &proc->cond_FH, NULL); + pthread_cond_init( &proc->cond_FH1, NULL); pthread_cond_init( &proc->cond_emulateRF, NULL); pthread_cond_init( &proc->cond_asynch_rxtx, NULL); pthread_cond_init( &proc->cond_synch,NULL); pthread_cond_init( &proc->cond_gNBs, NULL); pthread_attr_init( &proc->attr_FH); + pthread_attr_init( &proc->attr_FH1); pthread_attr_init( &proc->attr_emulateRF); pthread_attr_init( &proc->attr_prach); pthread_attr_init( &proc->attr_synch); @@ -1731,6 +1868,7 @@ void init_RU_proc(RU_t *ru) { #ifndef DEADLINE_SCHEDULER attr_FH = &proc->attr_FH; + attr_FH1 = &proc->attr_FH1; attr_emulateRF = &proc->attr_emulateRF; attr_prach = &proc->attr_prach; //attr_synch = &proc->attr_synch; @@ -1738,6 +1876,8 @@ void init_RU_proc(RU_t *ru) { #endif pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void*)ru ); + if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) + pthread_create( &proc->pthread_FH1, attr_FH1, ru_thread_tx, (void*)ru ); if(emulate_rf) pthread_create( &proc->pthread_emulateRF, attr_emulateRF, emulatedRF_thread, (void*)proc ); if (ru->function == NGFI_RRU_IF4p5) {