Commit a0170b8e authored by Raymond Knopp's avatar Raymond Knopp

more cleanup for lte-enb.c

parent 66cd4fdb
...@@ -163,6 +163,163 @@ void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst ...@@ -163,6 +163,163 @@ void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst
void stop_eNB(int nb_inst); void stop_eNB(int nb_inst);
inline void thread_top_init(char *thread_name,
uint64_t runtime,
uint64_t deadline,
uint64_t period) {
MSC_START_USE();
#ifdef DEADLINE_SCHEDULER
struct sched_attr attr;
unsigned int flags = 0;
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_deadline = deadline;
attr.sched_period = period;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] eNB tx thread: sched_setattr failed\n");
return &eNB_thread_rxtx_status;
}
LOG_I( HW, "[SCHED] eNB RXn-TXnp4 deadline thread (TID %ld) started on CPU %d\n", gettid(), sched_getcpu() );
#else //LOW_LATENCY
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD threads */
/* CPU 1 is reserved for all RX_TX threads */
/* Enable CPU Affinity only if number of CPUs >2 */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() > 2)
{
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_setaffinity_np");
exit_fun("Error setting processor affinity");
}
}
#endif //CPU_AFFINITY
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0) {
perror( "pthread_getaffinity_np");
exit_fun("Error getting processor affinity ");
}
memset(cpu_affinity,0,sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset)) {
char temp[1024];
sprintf (temp, " CPU_%d", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0, sizeof(sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0) {
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0) {
perror("pthread_getschedparam : ");
exit_fun("Error getting thread priority");
}
LOG_I(HW, "[SCHED][eNB] %s started on CPU %d TID %ld, sched_policy = %s , priority = %d, CPU Affinity=%s \n",thread_name,sched_getcpu(),gettid(),
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
sparam.sched_priority, cpu_affinity );
#endif //LOW_LATENCY
mlockall(MCL_CURRENT | MCL_FUTURE);
}
inline void wait_sync(char *thread_name) {
printf( "waiting for sync (%s)\n",thread_name);
pthread_mutex_lock( &sync_mutex );
while (sync_var<0)
pthread_cond_wait( &sync_cond, &sync_mutex );
pthread_mutex_unlock(&sync_mutex);
printf( "got sync (%s)\n", thread_name);
}
inline int wait_on_condition(pthread_mutex_t *mutex,pthread_cond_t *cond,int *instance_cnt,char *name) {
struct timespec wait;
wait.tv_sec=0;
wait.tv_nsec=5000000L;
if (pthread_mutex_timedlock(mutex,&wait) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for %s\n",name);
exit_fun("nothing to add");
return(-1);
}
while (*instance_cnt < 0) {
// most of the time the thread is waiting here
// proc->instance_cnt_rxtx is -1
pthread_cond_wait(cond,mutex); // this unlocks mutex_rxtx while waiting and then locks it again
}
if (pthread_mutex_unlock(mutex) != 0) {
LOG_E(PHY,"[SCHED][eNB] error unlocking mutex for %s\n",name);
exit_fun("nothing to add");
return(-1);
}
return(0);
}
inline int release_thread(pthread_mutex_t *mutex,int *instance_cnt,char *name) {
if (pthread_mutex_lock(mutex) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for %s\n",name);
exit_fun("nothing to add");
return(-1);
}
*instance_cnt=*instance_cnt-1;
if (pthread_mutex_unlock(mutex) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for %s\n",name);
exit_fun("nothing to add");
return(-1);
}
return(0);
}
void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) { void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) {
unsigned int aa,slot_offset, slot_offset_F; unsigned int aa,slot_offset, slot_offset_F;
...@@ -419,135 +576,19 @@ static void* eNB_thread_rxtx( void* param ) { ...@@ -419,135 +576,19 @@ static void* eNB_thread_rxtx( void* param ) {
PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id]; PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id];
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
FILE *tx_time_file = NULL; char thread_name[100];
char tx_time_name[101];
if (opp_enabled == 1) {
snprintf(tx_time_name, 100,"/tmp/%s_tx_time_thread_sf", "eNB");
tx_time_file = fopen(tx_time_name,"w");
}
// set default return value // set default return value
eNB_thread_rxtx_status = 0; eNB_thread_rxtx_status = 0;
MSC_START_USE(); sprintf(thread_name,"RXn_TXnp4_%d\n",&eNB->proc.proc_rxtx[0] == proc ? 0 : 1);
thread_top_init(thread_name,850000L,1000000L,2000000L);
#ifdef DEADLINE_SCHEDULER
struct sched_attr attr;
unsigned int flags = 0;
uint64_t runtime = 850000 ;
uint64_t deadline = 1 * 1000000 ; // each tx thread will finish within 1ms
uint64_t period = 1 * 10000000; // each tx thread has a period of 10ms from the starting point
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_deadline = deadline;
attr.sched_period = period;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] eNB tx thread: sched_setattr failed\n");
return &eNB_thread_rxtx_status;
}
LOG_I( HW, "[SCHED] eNB RXn-TXnp4 deadline thread (TID %ld) started on CPU %d\n", gettid(), sched_getcpu() );
#else //LOW_LATENCY
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
struct timespec wait;
wait.tv_sec=0;
wait.tv_nsec=5000000L;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD threads */
/* CPU 1 is reserved for all RX_TX threads */
/* Enable CPU Affinity only if number of CPUs >2 */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() > 2)
{
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_setaffinity_np");
exit_fun("Error setting processor affinity");
}
}
#endif //CPU_AFFINITY
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0) {
perror( "pthread_getaffinity_np");
exit_fun("Error getting processor affinity ");
}
memset(cpu_affinity,0,sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset)) {
char temp[1024];
sprintf (temp, " CPU_%d", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0, sizeof(sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0) {
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0) {
perror("pthread_getschedparam : ");
exit_fun("Error getting thread priority");
}
LOG_I(HW, "[SCHED][eNB] RXn_TXnp4 thread started on CPU %d TID %ld, sched_policy = %s , priority = %d, CPU Affinity=%s \n",sched_getcpu(),gettid(),
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
sparam.sched_priority, cpu_affinity );
#endif //LOW_LATENCY
mlockall(MCL_CURRENT | MCL_FUTURE);
while (!oai_exit) { while (!oai_exit) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
if (pthread_mutex_timedlock(&proc->mutex_rxtx,&wait) != 0) { if (wait_on_condition(&proc->mutex_rxtx,&proc->cond_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) break;
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB RXn-TXnp4\n");
exit_fun("nothing to add");
break;
}
while (proc->instance_cnt_rxtx < 0) {
// most of the time the thread is waiting here
// proc->instance_cnt_rxtx is -1
pthread_cond_wait( &proc->cond_rxtx, &proc->mutex_rxtx ); // this unlocks mutex_rxtx while waiting and then locks it again
}
if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) {
LOG_E(PHY,"[SCHED][eNB] error unlocking mutex for eNB TX\n");
exit_fun("nothing to add");
break;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 1 ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 1 );
...@@ -583,33 +624,10 @@ static void* eNB_thread_rxtx( void* param ) { ...@@ -583,33 +624,10 @@ static void* eNB_thread_rxtx( void* param ) {
} }
if (release_thread(&proc->mutex_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) break;
if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB TX proc\n");
exit_fun("nothing to add");
break;
}
proc->instance_cnt_rxtx--;
if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB TX proc\n");
exit_fun("nothing to add");
break;
}
stop_meas( &softmodem_stats_rxtx_sf ); stop_meas( &softmodem_stats_rxtx_sf );
} // while !oai_exit
if (opp_enabled){
#ifdef DEADLINE_SCHEDULER
if(softmodem_stats_rxtx_sf.diff_now/(cpuf) > attr.sched_runtime){
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_TX_ENB, (softmodem_stats_rxtx_sf.diff_now/cpuf - attr.sched_runtime)/1000000.0);
}
#endif
}
print_meas_now(&softmodem_stats_rxtx_sf,"eNB_TX_SF",tx_time_file);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
...@@ -761,159 +779,54 @@ void fh_if4p5_asynch_DL(PHY_VARS_eNB *eNB,int *frame,int *subframe) { ...@@ -761,159 +779,54 @@ void fh_if4p5_asynch_DL(PHY_VARS_eNB *eNB,int *frame,int *subframe) {
*subframe = subframe_tx; *subframe = subframe_tx;
proc->first_tx = 0; proc->first_tx = 0;
} }
else { else {
if (frame_tx != *frame) { if (frame_tx != *frame) {
LOG_E(PHY,"frame_tx %d is not what we expect %d\n",frame_tx,*frame); LOG_E(PHY,"frame_tx %d is not what we expect %d\n",frame_tx,*frame);
exit_fun("Exiting"); exit_fun("Exiting");
}
if (subframe_tx != *subframe) {
LOG_E(PHY,"subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe);
exit_fun("Exiting");
}
}
if (packet_type == IF4p5_PDLFFT) {
symbol_mask = symbol_mask | (1<<symbol_number);
}
else {
LOG_E(PHY,"Illegal IF4p5 packet type (should only be IF4p5_PDLFFT%d\n",packet_type);
exit_fun("Exiting");
}
} while (symbol_mask != symbol_mask_full);
do_OFDM_mod_rt(subframe_tx, eNB);
}
/*!
* \brief The Asynchronous RX/TX FH thread of RAU/RCC/eNB/RRU.
* This handles the RX FH for an asynchronous RRU/UE
* \param param is a \ref eNB_proc_t structure which contains the info what to process.
* \returns a pointer to an int. The storage is not on the heap and must not be freed.
*/
static void* eNB_thread_asynch_rxtx( void* param ) {
static int eNB_thread_asynch_rxtx_status;
eNB_proc_t *proc = (eNB_proc_t*)param;
PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id];
LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
int subframe=0, frame=0;
#ifdef DEADLINE_SCHEDULER
struct sched_attr attr;
unsigned int flags = 0;
uint64_t runtime = 870000 ;
uint64_t deadline = 1 * 1000000;
uint64_t period = 1 * 10000000; // each rx thread has a period of 10ms from the starting point
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_deadline = deadline;
attr.sched_period = period;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] eNB FH sched_setattr failed\n");
return &eNB_thread_asynch_rx_status;
}
LOG_I( HW, "[SCHED] eNB asynch RX deadline thread (TID %ld) started on CPU %d\n", gettid(), sched_getcpu() );
#else // LOW_LATENCY
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD */
/* CPU 1 is reserved for all TX threads */
/* CPU 2..MAX_CPUS is reserved for all RX threads */
/* Set CPU Affinity only if number of CPUs >2 */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() >2) {
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0) {
perror( "pthread_setaffinity_np");
exit_fun (" Error setting processor affinity :");
} }
if (subframe_tx != *subframe) {
LOG_E(PHY,"subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe);
exit_fun("Exiting");
} }
#endif //CPU_AFFINITY
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0) {
perror ("pthread_getaffinity_np");
exit_fun (" Error getting processor affinity :");
} }
memset(cpu_affinity,0, sizeof(cpu_affinity)); if (packet_type == IF4p5_PDLFFT) {
symbol_mask = symbol_mask | (1<<symbol_number);
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset)) {
char temp[1024];
sprintf (temp, " CPU_%d", j);
strcat(cpu_affinity, temp);
} }
else {
memset(&sparam, 0 , sizeof (sparam)); LOG_E(PHY,"Illegal IF4p5 packet type (should only be IF4p5_PDLFFT%d\n",packet_type);
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO); exit_fun("Exiting");
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0) {
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
} }
} while (symbol_mask != symbol_mask_full);
memset(&sparam, 0 , sizeof (sparam)); do_OFDM_mod_rt(subframe_tx, eNB);
}
s = pthread_getschedparam(pthread_self(), &policy, &sparam); /*!
if (s != 0) { * \brief The Asynchronous RX/TX FH thread of RAU/RCC/eNB/RRU.
perror("pthread_getschedparam"); * This handles the RX FH for an asynchronous RRU/UE
exit_fun("Error getting thread priority"); * \param param is a \ref eNB_proc_t structure which contains the info what to process.
} * \returns a pointer to an int. The storage is not on the heap and must not be freed.
*/
static void* eNB_thread_asynch_rxtx( void* param ) {
LOG_I(HW, "[SCHED][eNB] eNB asynch RX thread started on CPU %d TID %ld, sched_policy = %s, priority = %d, CPU Affinity = %s\n", sched_getcpu(),gettid(), static int eNB_thread_asynch_rxtx_status;
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
sparam.sched_priority, cpu_affinity);
eNB_proc_t *proc = (eNB_proc_t*)param;
PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id];
#endif // DEADLINE_SCHEDULER
int subframe=0, frame=0;
mlockall(MCL_CURRENT | MCL_FUTURE); thread_top_init("thread_asynch",870000L,1000000L,1000000L);
// wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe
printf( "waiting for sync (eNB_thread_asynch_rx)\n");
pthread_mutex_lock( &sync_mutex );
while (sync_var<0)
pthread_cond_wait( &sync_cond, &sync_mutex );
pthread_mutex_unlock(&sync_mutex);
printf( "got sync (eNB_thread_asynch_rx)\n" );
wait_sync("thread_asynch");
// wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe
printf( "waiting for devices (eNB_thread_asynch_rx)\n"); printf( "waiting for devices (eNB_thread_asynch_rx)\n");
pthread_mutex_lock( &proc->mutex_asynch_rxtx);
while (proc->instance_cnt_asynch_rxtx<0) wait_on_condition(&proc->mutex_asynch_rxtx,&proc->cond_asynch_rxtx,&proc->instance_cnt_asynch_rxtx,"thread_asynch");
pthread_cond_wait( &proc->cond_asynch_rxtx, &proc->mutex_asynch_rxtx );
pthread_mutex_unlock(&proc->mutex_asynch_rxtx);
printf( "devices ok (eNB_thread_asynch_rx)\n"); printf( "devices ok (eNB_thread_asynch_rx)\n");
...@@ -1105,17 +1018,11 @@ void rx_fh_slave(PHY_VARS_eNB *eNB,int *frame,int *subframe) { ...@@ -1105,17 +1018,11 @@ void rx_fh_slave(PHY_VARS_eNB *eNB,int *frame,int *subframe) {
// it just waits for an external event. The actual rx_rh is handle by the asynchronous RX thread // it just waits for an external event. The actual rx_rh is handle by the asynchronous RX thread
eNB_proc_t *proc=&eNB->proc; eNB_proc_t *proc=&eNB->proc;
if (pthread_mutex_lock(&proc->mutex_FH) != 0) { if (wait_on_condition(&proc->mutex_FH,&proc->cond_FH,&proc->instance_cnt_FH,"rx_fh_slave") < 0)
LOG_E( PHY, "[SCHED][eNB] error locking mutex for FH Slave\n"); return;
exit_fun( "error locking mutex" );
}
while (proc->instance_cnt_FH < 0) { release_thread(&proc->mutex_FH,&proc->instance_cnt_FH,"rx_fh_slave");
pthread_cond_wait( &proc->cond_FH,&proc->mutex_FH );
}
proc->instance_cnt_FH++;
pthread_mutex_unlock( &proc->mutex_FH );
} }
...@@ -1219,6 +1126,7 @@ void wakeup_slaves(eNB_proc_t *proc) { ...@@ -1219,6 +1126,7 @@ void wakeup_slaves(eNB_proc_t *proc) {
* \param param is a \ref eNB_proc_t structure which contains the info what to process. * \param param is a \ref eNB_proc_t structure which contains the info what to process.
* \returns a pointer to an int. The storage is not on the heap and must not be freed. * \returns a pointer to an int. The storage is not on the heap and must not be freed.
*/ */
static void* eNB_thread_FH( void* param ) { static void* eNB_thread_FH( void* param ) {
static int eNB_thread_FH_status; static int eNB_thread_FH_status;
...@@ -1227,131 +1135,20 @@ static void* eNB_thread_FH( void* param ) { ...@@ -1227,131 +1135,20 @@ static void* eNB_thread_FH( void* param ) {
PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id]; PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id];
LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
FILE *rx_time_file = NULL;
char rx_time_name[101];
int subframe=0, frame=0; int subframe=0, frame=0;
if (opp_enabled == 1) {
snprintf(rx_time_name, 100,"/tmp/%s_rx_time_thread_sf", "eNB");
rx_time_file = fopen(rx_time_name,"w");
}
// set default return value // set default return value
eNB_thread_FH_status = 0; eNB_thread_FH_status = 0;
MSC_START_USE(); thread_top_init("eNB_thread_FH",870000,1000000,1000000);
#ifdef DEADLINE_SCHEDULER
struct sched_attr attr;
unsigned int flags = 0;
uint64_t runtime = 870000 ;
uint64_t deadline = 1 * 1000000;
uint64_t period = 1 * 10000000; // each rx thread has a period of 10ms from the starting point
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_deadline = deadline;
attr.sched_period = period;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] eNB FH sched_setattr failed\n");
return &eNB_thread_FH_status;
}
LOG_I( HW, "[SCHED] eNB FH deadline thread (TID %ld) started on CPU %d\n", gettid(), sched_getcpu() );
#else // LOW_LATENCY
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD */
/* CPU 1 is reserved for all TX threads */
/* CPU 2..MAX_CPUS is reserved for all RX threads */
/* Set CPU Affinity only if number of CPUs >2 */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() >2) {
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0) {
perror( "pthread_setaffinity_np");
exit_fun (" Error setting processor affinity :");
}
}
#endif //CPU_AFFINITY
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0) {
perror ("pthread_getaffinity_np");
exit_fun (" Error getting processor affinity :");
}
memset(cpu_affinity,0, sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset)) {
char temp[1024];
sprintf (temp, " CPU_%d", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0 , sizeof (sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0) {
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
memset(&sparam, 0 , sizeof (sparam));
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0) {
perror("pthread_getschedparam");
exit_fun("Error getting thread priority");
}
LOG_I(HW, "[SCHED][eNB] FH thread started on CPU %d TID %ld, sched_policy = %s, priority = %d, CPU Affinity = %s\n", sched_getcpu(),gettid(),
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
sparam.sched_priority, cpu_affinity);
#endif // DEADLINE_SCHEDULER
mlockall(MCL_CURRENT | MCL_FUTURE);
// wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe
printf( "waiting for sync (eNB_thread_FH)\n");
pthread_mutex_lock( &sync_mutex );
while (sync_var<0)
pthread_cond_wait( &sync_cond, &sync_mutex );
pthread_mutex_unlock(&sync_mutex);
printf( "got sync (eNB_thread_FH)\n" ); wait_sync("eNB_thread_FH");
#if defined(ENABLE_ITTI) #if defined(ENABLE_ITTI)
if (eNB->node_function < NGFI_RRU_IF5) if (eNB->node_function < NGFI_RRU_IF5)
wait_system_ready ("Waiting for eNB application to be ready %s\r", &start_eNB); wait_system_ready ("Waiting for eNB application to be ready %s\r", &start_eNB);
#endif #endif
// Start IF device if any // Start IF device if any
if (eNB->start_if) if (eNB->start_if)
if (eNB->start_if(eNB) != 0) if (eNB->start_if(eNB) != 0)
...@@ -1362,7 +1159,7 @@ static void* eNB_thread_FH( void* param ) { ...@@ -1362,7 +1159,7 @@ static void* eNB_thread_FH( void* param ) {
if (eNB->start_rf(eNB) != 0) if (eNB->start_rf(eNB) != 0)
LOG_E(HW,"Could not start the RF device\n"); LOG_E(HW,"Could not start the RF device\n");
// wakeup asnych_rxtx thread // wakeup asnych_rxtx thread because the devices are ready at this point
pthread_mutex_lock(&proc->mutex_asynch_rxtx); pthread_mutex_lock(&proc->mutex_asynch_rxtx);
proc->instance_cnt_asynch_rxtx=0; proc->instance_cnt_asynch_rxtx=0;
pthread_mutex_unlock(&proc->mutex_asynch_rxtx); pthread_mutex_unlock(&proc->mutex_asynch_rxtx);
...@@ -1371,10 +1168,8 @@ static void* eNB_thread_FH( void* param ) { ...@@ -1371,10 +1168,8 @@ static void* eNB_thread_FH( void* param ) {
// This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
while (!oai_exit) { while (!oai_exit) {
if (oai_exit) break; // these are local subframe/frame counters to check that we are in synch with the fronthaul timing.
// They are set on the first rx/tx in the underly FH routines.
// this is to check that we are in synch with the fronthaul timing
if (subframe==9) { if (subframe==9) {
subframe=0; subframe=0;
frame++; frame++;
...@@ -1399,30 +1194,7 @@ static void* eNB_thread_FH( void* param ) { ...@@ -1399,30 +1194,7 @@ static void* eNB_thread_FH( void* param ) {
if (wakeup_rxtx(proc,&proc->proc_rxtx[proc->subframe_rx&1],fp) < 0) if (wakeup_rxtx(proc,&proc->proc_rxtx[proc->subframe_rx&1],fp) < 0)
break; break;
stop_meas( &softmodem_stats_rxtx_sf ); // artifical sleep for very slow fronthaul
#ifdef DEADLINE_SCHEDULER
if (opp_enabled){
if(softmodem_stats_rxtx_sf.diff_now/(cpuf) > attr.sched_runtime) {
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RUNTIME_RXTX_ENB, (softmodem_stats_rxtx_sf.diff_now/cpuf - attr.sched_runtime)/1000000.0);
}
}
#endif // DEADLINE_SCHEDULER
print_meas_now(&softmodem_stats_rx_sf,"eNB_RX_SF", rx_time_file);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
print_meas_now(&softmodem_stats_rx_sf,"eNB_RX_SF", rx_time_file);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
if (eNB->node_timing == synch_to_ext_device) {
proc->instance_cnt_FH--;
if (pthread_mutex_unlock(&proc->mutex_FH) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for FH\n");
exit_fun( "error unlocking mutex" );
}
}
if (eNB->frame_parms.N_RB_DL==6) if (eNB->frame_parms.N_RB_DL==6)
rt_sleep_ns(800000LL); rt_sleep_ns(800000LL);
} }
...@@ -1444,147 +1216,21 @@ static void* eNB_thread_prach( void* param ) { ...@@ -1444,147 +1216,21 @@ static void* eNB_thread_prach( void* param ) {
eNB_proc_t *proc = (eNB_proc_t*)param; eNB_proc_t *proc = (eNB_proc_t*)param;
PHY_VARS_eNB *eNB= PHY_vars_eNB_g[0][proc->CC_id]; PHY_VARS_eNB *eNB= PHY_vars_eNB_g[0][proc->CC_id];
/*
struct timespec wait;
wait.tv_sec=0;
wait.tv_nsec=5000000L;
*/
// set default return value // set default return value
eNB_thread_prach_status = 0; eNB_thread_prach_status = 0;
MSC_START_USE(); thread_top_init("eNB_thread_prach",500000L,1000000L,20000000L);
#ifdef DEADLINE_SCHEDULER
struct sched_attr attr;
unsigned int flags = 0;
uint64_t runtime = 870000 ;
uint64_t deadline = 1 * 1000000;
uint64_t period = 1 * 10000000; // each prach thread has a period of 10ms from the starting point
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_deadline = deadline;
attr.sched_period = period;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] eNB PRACH sched_setattr failed\n");
return &eNB_thread_prach_status;
}
LOG_I( HW, "[SCHED] eNB PRACH deadline thread (TID %ld) started on CPU %d\n", 0, gettid(), sched_getcpu() );
#else // LOW_LATENCY
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD */
/* CPU 1 is reserved for all TX threads */
/* CPU 2..MAX_CPUS is reserved for all RX threads */
/* Set CPU Affinity only if number of CPUs >2 */
CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY
if (get_nprocs() >2) {
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0) {
perror( "pthread_setaffinity_np");
exit_fun (" Error setting processor affinity :");
}
}
#endif //CPU_AFFINITY
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0) {
perror ("pthread_getaffinity_np");
exit_fun (" Error getting processor affinity :");
}
memset(cpu_affinity,0, sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset)) {
char temp[1024];
sprintf (temp, " CPU_%d", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0 , sizeof (sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-2;
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0) {
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
memset(&sparam, 0 , sizeof (sparam));
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0) {
perror("pthread_getschedparam");
exit_fun("Error getting thread priority");
}
LOG_I(HW, "[SCHED][eNB] PRACH thread started on CPU %d TID %ld, IC %d, sched_policy = %s, priority = %d, CPU Affinity = %s\n", sched_getcpu(),gettid(),proc->instance_cnt_prach,
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
sparam.sched_priority, cpu_affinity);
#endif // DEADLINE_SCHEDULER
mlockall(MCL_CURRENT | MCL_FUTURE);
while (!oai_exit) { while (!oai_exit) {
if (oai_exit) break; if (oai_exit) break;
if (pthread_mutex_lock(&proc->mutex_prach) != 0) { if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break;
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB PRACH\n");
exit_fun( "error locking mutex" );
break;
}
while (proc->instance_cnt_prach < 0) {
// most of the time the thread is waiting here
// proc->instance_cnt_prach is -1
pthread_cond_wait( &proc->cond_prach, &proc->mutex_prach ); // this unlocks mutex_rxtx while waiting and then locks it again
}
if (pthread_mutex_unlock(&proc->mutex_prach) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB PRACH\n");
exit_fun( "error unlocking mutex" );
break;
}
prach_procedures(eNB); prach_procedures(eNB);
if (pthread_mutex_lock(&proc->mutex_prach) != 0) { if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break;
LOG_E( PHY, "[SCHED][eNB] error locking mutex for eNB PRACH proc %d\n");
exit_fun( "error locking mutex" );
break;
}
proc->instance_cnt_prach--;
if (pthread_mutex_unlock(&proc->mutex_prach) != 0) {
LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for eNB RX proc %d\n");
exit_fun( "error unlocking mutex" );
break;
}
} }
printf( "Exiting eNB thread PRACH\n"); printf( "Exiting eNB thread PRACH\n");
......
...@@ -78,8 +78,6 @@ void set_latency_target(void) { ...@@ -78,8 +78,6 @@ void set_latency_target(void) {
} }
#ifndef RTAI
struct timespec interval, next, now, res; struct timespec interval, next, now, res;
clockid_t clock_id = CLOCK_MONOTONIC; //other options are CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID clockid_t clock_id = CLOCK_MONOTONIC; //other options are CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID
RTIME rt_get_time_ns (void) RTIME rt_get_time_ns (void)
...@@ -257,12 +255,7 @@ int sched_getattr(pid_t pid,struct sched_attr *attr,unsigned int size, unsigned ...@@ -257,12 +255,7 @@ int sched_getattr(pid_t pid,struct sched_attr *attr,unsigned int size, unsigned
#endif #endif
#else
int rt_sleep_ns(RTIME x)
{
rt_sleep(nano2count(x));
return(0);
}
#endif
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
*******************************************************************************/ *******************************************************************************/
/*! \file rt_wrapper.h /*! \file rt_wrapper.h
* \brief provides a wrapper for the timing function for real-time opeartions depending on weather RTAI is used or not. It also implements an API for the SCHED_DEADLINE kernel scheduler. * \brief provides a wrapper for the timing function for real-time opeartions. It also implements an API for the SCHED_DEADLINE kernel scheduler.
* \author F. Kaltenberger and Navid Nikaein * \author F. Kaltenberger and Navid Nikaein
* \date 2013 * \date 2013
* \version 0.1 * \version 0.1
...@@ -39,9 +39,8 @@ ...@@ -39,9 +39,8 @@
*/ */
void set_latency_target(void);
#ifndef RTAI #define _GNU_SOURCE
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <stdint.h> #include <stdint.h>
...@@ -52,11 +51,26 @@ void set_latency_target(void); ...@@ -52,11 +51,26 @@ void set_latency_target(void);
#include <linux/types.h> #include <linux/types.h>
#include <syscall.h> #include <syscall.h>
#include <math.h> #include <math.h>
#include <sched.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sched.h>
#include <linux/sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>
#include <sys/sysinfo.h>
#include "UTIL/LOG/log_extern.h"
#include "msc.h"
#define RTIME long long int #define RTIME long long int
#define rt_printk printf #define rt_printk printf
void set_latency_target(void);
RTIME rt_get_time_ns (void); RTIME rt_get_time_ns (void);
int rt_sleep_ns (RTIME x); int rt_sleep_ns (RTIME x);
...@@ -115,12 +129,3 @@ int sched_getattr(pid_t pid,struct sched_attr *attr,unsigned int size, unsigned ...@@ -115,12 +129,3 @@ int sched_getattr(pid_t pid,struct sched_attr *attr,unsigned int size, unsigned
#define gettid() syscall(__NR_gettid) // for gettid #define gettid() syscall(__NR_gettid) // for gettid
#else
#include <rtai_hal.h>
#include <rtai_lxrt.h>
#include <rtai_sem.h>
#include <rtai_msg.h>
int rt_sleep_ns(RTIME x);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment