Merge remote-tracking branch 'origin/develop' into bupt-ulmimo-4
This commit is contained in:
@@ -473,130 +473,6 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int
|
||||
|
||||
/* @}*/
|
||||
|
||||
static __inline__ uint64_t rdtsc(void) {
|
||||
uint32_t a, d;
|
||||
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
|
||||
return (((uint64_t)d)<<32) | ((uint64_t)a);
|
||||
}
|
||||
|
||||
#define DEBUG_REALTIME 1
|
||||
#if DEBUG_REALTIME
|
||||
|
||||
extern double cpuf;
|
||||
|
||||
static inline uint64_t checkTCPU(int timeout,
|
||||
char *file,
|
||||
int line)
|
||||
{
|
||||
static uint64_t __thread lastCPUTime=0;
|
||||
static uint64_t __thread last=0;
|
||||
uint64_t cur=rdtsc();
|
||||
struct timespec CPUt;
|
||||
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &CPUt);
|
||||
uint64_t CPUTime=CPUt.tv_sec*1000*1000+CPUt.tv_nsec/1000;
|
||||
double microCycles=(double)(cpuf*1000);
|
||||
int duration=(int)((cur-last)/microCycles);
|
||||
|
||||
if ( last!=0 && duration > timeout ) {
|
||||
//struct timespec ts;
|
||||
//clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
printf("%s:%d lte-ue delay %d (exceed %d), CPU for this period: %lld\n", file, line,
|
||||
duration, timeout, (long long)CPUTime-lastCPUTime );
|
||||
}
|
||||
|
||||
last=cur;
|
||||
lastCPUTime=CPUTime;
|
||||
return cur;
|
||||
}
|
||||
|
||||
static inline unsigned long long checkT(int timeout,
|
||||
char *file,
|
||||
int line)
|
||||
{
|
||||
static unsigned long long __thread last=0;
|
||||
unsigned long long cur=rdtsc();
|
||||
int microCycles=(int)(cpuf*1000);
|
||||
int duration=(int)((cur-last)/microCycles);
|
||||
|
||||
if ( last!=0 && duration > timeout )
|
||||
printf("%s:%d lte-ue delay %d (exceed %d)\n", file, line,
|
||||
duration, timeout);
|
||||
|
||||
last=cur;
|
||||
return cur;
|
||||
}
|
||||
|
||||
typedef struct m {
|
||||
uint64_t iterations;
|
||||
uint64_t sum;
|
||||
uint64_t maxArray[11];
|
||||
} Meas;
|
||||
|
||||
static inline void printMeas(char *txt,
|
||||
Meas *M,
|
||||
int period)
|
||||
{
|
||||
if (M->iterations%period == 0 ) {
|
||||
char txt2[512];
|
||||
sprintf(txt2,"%s avg=%" PRIu64 " iterations=%" PRIu64 " max=%"
|
||||
PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 "\n",
|
||||
txt,
|
||||
M->sum/M->iterations,
|
||||
M->iterations,
|
||||
M->maxArray[1],M->maxArray[2], M->maxArray[3],M->maxArray[4], M->maxArray[5],
|
||||
M->maxArray[6],M->maxArray[7], M->maxArray[8],M->maxArray[9],M->maxArray[10]);
|
||||
#if T_TRACER
|
||||
LOG_W(PHY,"%s",txt2);
|
||||
#else
|
||||
printf("%s",txt2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline int cmpint(const void *a,
|
||||
const void *b)
|
||||
{
|
||||
uint64_t *aa=(uint64_t *)a;
|
||||
uint64_t *bb=(uint64_t *)b;
|
||||
return (int)(*aa-*bb);
|
||||
}
|
||||
|
||||
static inline void updateTimes(uint64_t start,
|
||||
Meas *M,
|
||||
int period,
|
||||
char *txt)
|
||||
{
|
||||
if (start!=0) {
|
||||
uint64_t end=rdtsc();
|
||||
long long diff=(end-start)/(cpuf*1000);
|
||||
M->maxArray[0]=diff;
|
||||
M->sum+=diff;
|
||||
M->iterations++;
|
||||
qsort(M->maxArray, 11, sizeof(uint64_t), cmpint);
|
||||
printMeas(txt,M,period);
|
||||
}
|
||||
}
|
||||
|
||||
#define check(a) do { checkT(a,__FILE__,__LINE__); } while (0)
|
||||
#define checkcpu(a) do { checkTCPU(a,__FILE__,__LINE__); } while (0)
|
||||
#define initRefTimes(a) static __thread Meas a= {0}
|
||||
#define pickTime(a) uint64_t a=rdtsc()
|
||||
#define readTime(a) a
|
||||
#define initStaticTime(a) static __thread uint64_t a={0}
|
||||
#define pickStaticTime(a) do { a=rdtsc(); } while (0)
|
||||
|
||||
#else
|
||||
#define check(a) do {} while (0)
|
||||
#define checkcpu(a) do {} while (0)
|
||||
#define initRefTimes(a) do {} while (0)
|
||||
#define initStaticTime(a) do {} while (0)
|
||||
#define pickTime(a) do {} while (0)
|
||||
#define readTime(a) 0
|
||||
#define pickStaticTime(a) do {} while (0)
|
||||
#define updateTimes(a,b,c,d) do {} while (0)
|
||||
#define printMeas(a,b,c) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,27 @@
|
||||
|
||||
const char *duplex_mode[]={"FDD","TDD"};
|
||||
|
||||
int tables_5_3_2[5][11] = {
|
||||
{25, 52, 79, 106, 133, 160, 216, 270, -1, -1, -1}, // 15 FR1
|
||||
{11, 24, 38, 51, 65, 78, 106, 133, 162, 217, 273}, // 30 FR1
|
||||
{-1, 11, 18, 24, 31, 38, 51, 65, 79, 107, 135}, // 60 FR1
|
||||
{66, 132, 264, -1 , -1, -1, -1, -1, -1, -1, -1}, // 60 FR2
|
||||
{32, 66, 132, 264, -1, -1, -1, -1, -1, -1, -1} // 120FR2
|
||||
};
|
||||
|
||||
int get_supported_band_index(int scs, int band, int n_rbs){
|
||||
|
||||
int scs_index = scs;
|
||||
if (band>256)
|
||||
scs_index++;
|
||||
for (int i=0; i<11; i++) {
|
||||
if(n_rbs == tables_5_3_2[scs][i])
|
||||
return i;
|
||||
}
|
||||
return (-1); // not found
|
||||
}
|
||||
|
||||
|
||||
// Table 5.2-1 NR operating bands in FR1 & FR2 (3GPP TS 38.101)
|
||||
// Table 5.4.2.3-1 Applicable NR-ARFCN per operating band in FR1 & FR2 (3GPP TS 38.101)
|
||||
// Notes:
|
||||
|
||||
@@ -80,6 +80,7 @@ void SLIV2SL(int SLIV,int *S,int *L);
|
||||
int get_dmrs_port(int nl, uint16_t dmrs_ports);
|
||||
uint16_t SL_to_bitmap(int startSymbolIndex, int nrOfSymbols);
|
||||
int get_nb_periods_per_frame(uint8_t tdd_period);
|
||||
int get_supported_band_index(int scs, int band, int n_rbs);
|
||||
long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS);
|
||||
|
||||
#define CEILIDIV(a,b) ((a+b-1)/b)
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
|
||||
static char *grouptypes[] = {"ltestats","cpustats"};
|
||||
static double cpufreq;
|
||||
extern notifiedFIFO_t measur_fifo;
|
||||
#define TELNET_NUM_MEASURTYPES (sizeof(grouptypes)/sizeof(char *))
|
||||
|
||||
#define HDR "---------------------------------"
|
||||
|
||||
@@ -43,9 +43,9 @@ int main(int argc, char *argv[]) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint64_t deb=rdtsc();
|
||||
uint64_t deb=rdtsc_oai();
|
||||
usleep(100000);
|
||||
cpuCyclesMicroSec=(rdtsc()-deb)/100000;
|
||||
cpuCyclesMicroSec=(rdtsc_oai()-deb)/100000;
|
||||
printf("Cycles per µs: %lu\n",cpuCyclesMicroSec);
|
||||
printf("Key" SEP "delay to process" SEP "processing time" SEP "delay to be read answer\n");
|
||||
notifiedFIFO_elt_t doneRequest;
|
||||
|
||||
@@ -72,11 +72,11 @@ void *one_thread(void *arg) {
|
||||
do {
|
||||
notifiedFIFO_elt_t *elt=pullNotifiedFifoRemember(&tp->incomingFifo, myThread);
|
||||
|
||||
if (tp->measurePerf) elt->startProcessingTime=rdtsc();
|
||||
if (tp->measurePerf) elt->startProcessingTime=rdtsc_oai();
|
||||
|
||||
elt->processingFunc(NotifiedFifoData(elt));
|
||||
|
||||
if (tp->measurePerf) elt->endProcessingTime=rdtsc();
|
||||
if (tp->measurePerf) elt->endProcessingTime=rdtsc_oai();
|
||||
|
||||
if (elt->reponseFifo) {
|
||||
// Check if the job is still alive, else it has been aborted
|
||||
@@ -97,7 +97,7 @@ void initNamedTpool(char *params,tpool_t *pool, bool performanceMeas, char *name
|
||||
char *measr=getenv("threadPoolMeasurements");
|
||||
pool->measurePerf=performanceMeas;
|
||||
// force measurement if the output is defined
|
||||
pool->measurePerf=measr!=NULL;
|
||||
pool->measurePerf |= measr!=NULL;
|
||||
|
||||
if (measr) {
|
||||
mkfifo(measr,0666);
|
||||
|
||||
@@ -27,11 +27,11 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <assertions.h>
|
||||
#include <LOG/log.h>
|
||||
#include <common/utils/system.h>
|
||||
//#include <stdatomic.h>
|
||||
#include "assertions.h"
|
||||
#include "common/utils/time_meas.h"
|
||||
#include "common/utils/system.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define THREADINIT PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
@@ -60,10 +60,10 @@ typedef struct notifiedFIFO_elt_s {
|
||||
struct notifiedFIFO_s *reponseFifo;
|
||||
void (*processingFunc)(void *);
|
||||
bool malloced;
|
||||
uint64_t creationTime;
|
||||
uint64_t startProcessingTime;
|
||||
uint64_t endProcessingTime;
|
||||
uint64_t returnTime;
|
||||
oai_cputime_t creationTime;
|
||||
oai_cputime_t startProcessingTime;
|
||||
oai_cputime_t endProcessingTime;
|
||||
oai_cputime_t returnTime;
|
||||
void *msgData;
|
||||
} notifiedFIFO_elt_t;
|
||||
|
||||
@@ -97,12 +97,11 @@ static inline void *NotifiedFifoData(notifiedFIFO_elt_t *elt) {
|
||||
|
||||
static inline void delNotifiedFIFO_elt(notifiedFIFO_elt_t *elt) {
|
||||
if (elt->malloced) {
|
||||
elt->malloced=false;
|
||||
elt->malloced = false;
|
||||
free(elt);
|
||||
} else
|
||||
printf("delNotifiedFIFO on something not allocated by newNotifiedFIFO\n");
|
||||
|
||||
//LOG_W(UTIL,"delNotifiedFIFO on something not allocated by newNotifiedFIFO\n");
|
||||
}
|
||||
/* it is allowed to call delNotifiedFIFO_elt when the memory is managed by
|
||||
* the caller */
|
||||
}
|
||||
|
||||
static inline void initNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf) {
|
||||
@@ -141,8 +140,7 @@ static inline notifiedFIFO_elt_t *pullNotifiedFIFO_nothreadSafe(notifiedFIFO_t
|
||||
|
||||
notifiedFIFO_elt_t *ret=nf->outF;
|
||||
|
||||
if (nf->outF==nf->outF->next)
|
||||
LOG_E(UTIL,"Circular list in thread pool: push several times the same buffer is forbidden\n");
|
||||
AssertFatal(nf->outF != nf->outF->next,"Circular list in thread pool: push several times the same buffer is forbidden\n");
|
||||
|
||||
nf->outF=nf->outF->next;
|
||||
|
||||
@@ -174,6 +172,20 @@ static inline notifiedFIFO_elt_t *pollNotifiedFIFO(notifiedFIFO_t *nf) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline time_stats_t exec_time_stats_NotifiedFIFO(const notifiedFIFO_elt_t* elt)
|
||||
{
|
||||
time_stats_t ts = {0};
|
||||
if (elt->startProcessingTime == 0 && elt->endProcessingTime == 0)
|
||||
return ts; /* no measurements done */
|
||||
ts.in = elt->startProcessingTime;
|
||||
ts.diff = elt->endProcessingTime - ts.in;
|
||||
ts.p_time = ts.diff;
|
||||
ts.diff_square = ts.diff * ts.diff;
|
||||
ts.max = ts.diff;
|
||||
ts.trials = 1;
|
||||
return ts;
|
||||
}
|
||||
|
||||
// This function aborts all messages matching the key
|
||||
// If the queue is used in thread pools, it doesn't cancels already running processing
|
||||
// because the message has already been picked
|
||||
@@ -224,18 +236,18 @@ typedef struct thread_pool {
|
||||
} tpool_t;
|
||||
|
||||
static inline void pushTpool(tpool_t *t, notifiedFIFO_elt_t *msg) {
|
||||
if (t->measurePerf) msg->creationTime=rdtsc();
|
||||
if (t->measurePerf) msg->creationTime=rdtsc_oai();
|
||||
|
||||
if ( t->activated)
|
||||
pushNotifiedFIFO(&t->incomingFifo, msg);
|
||||
else {
|
||||
if (t->measurePerf)
|
||||
msg->startProcessingTime=rdtsc();
|
||||
msg->startProcessingTime=rdtsc_oai();
|
||||
|
||||
msg->processingFunc(NotifiedFifoData(msg));
|
||||
|
||||
if (t->measurePerf)
|
||||
msg->endProcessingTime=rdtsc();
|
||||
msg->endProcessingTime=rdtsc_oai();
|
||||
|
||||
if (msg->reponseFifo)
|
||||
pushNotifiedFIFO(msg->reponseFifo, msg);
|
||||
@@ -246,7 +258,7 @@ static inline notifiedFIFO_elt_t *pullTpool(notifiedFIFO_t *responseFifo, tpool_
|
||||
notifiedFIFO_elt_t *msg= pullNotifiedFIFO(responseFifo);
|
||||
AssertFatal(t->traceFd, "Thread pool used while not initialized");
|
||||
if (t->measurePerf)
|
||||
msg->returnTime=rdtsc();
|
||||
msg->returnTime=rdtsc_oai();
|
||||
|
||||
if (t->traceFd > 0)
|
||||
if(write(t->traceFd, msg, sizeof(*msg)));
|
||||
@@ -261,7 +273,7 @@ static inline notifiedFIFO_elt_t *tryPullTpool(notifiedFIFO_t *responseFifo, tpo
|
||||
return NULL;
|
||||
|
||||
if (t->measurePerf)
|
||||
msg->returnTime=rdtsc();
|
||||
msg->returnTime=rdtsc_oai();
|
||||
|
||||
if (t->traceFd)
|
||||
if(write(t->traceFd, msg, sizeof(*msg)));
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include "time_meas.h"
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "assertions.h"
|
||||
#include <pthread.h>
|
||||
#include "common/config/config_userapi.h"
|
||||
#include <common/utils/threadPool/thread-pool.h>
|
||||
// global var for openair performance profiler
|
||||
int opp_enabled = 0;
|
||||
double cpu_freq_GHz __attribute__ ((aligned(32)));
|
||||
|
||||
double cpu_freq_GHz __attribute__ ((aligned(32)))=0.0;
|
||||
static uint32_t max_cpumeasur;
|
||||
static time_stats_t **measur_table;
|
||||
notifiedFIFO_t measur_fifo;
|
||||
double get_cpu_freq_GHz(void)
|
||||
{
|
||||
if (cpu_freq_GHz <1 ) {
|
||||
time_stats_t ts = {0};
|
||||
reset_meas(&ts);
|
||||
ts.trials++;
|
||||
ts.in = rdtsc_oai();
|
||||
sleep(1);
|
||||
ts.diff = (rdtsc_oai()-ts.in);
|
||||
cpu_freq_GHz = (double)ts.diff/1000000000;
|
||||
printf("CPU Freq is %f \n", cpu_freq_GHz);
|
||||
}
|
||||
return cpu_freq_GHz;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void print_meas_now(time_stats_t *ts,
|
||||
const char *name,
|
||||
FILE *file_name)
|
||||
{
|
||||
if (opp_enabled) {
|
||||
//static double cpu_freq_GHz = 3.2;
|
||||
|
||||
//if (cpu_freq_GHz == 0.0)
|
||||
//cpu_freq_GHz = get_cpu_freq_GHz(); // super slow
|
||||
if (ts->trials>0) {
|
||||
//fprintf(file_name,"Name %25s: Processing %15.3f ms for SF %d, diff_now %15.3f \n", name,(ts->p_time/(cpu_freq_GHz*1000000.0)),subframe,ts->p_time);
|
||||
fprintf(file_name,"%15.3f us, diff_now %15.3f \n",(ts->p_time/(cpu_freq_GHz*1000.0)),(double)ts->p_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_meas(time_stats_t *ts,
|
||||
const char *name,
|
||||
time_stats_t *total_exec_time,
|
||||
time_stats_t *sf_exec_time)
|
||||
{
|
||||
if (opp_enabled) {
|
||||
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))
|
||||
fprintf(stderr, "%25s %25s %25s %25s %25s %6f\n","Name","Total","Per Trials", "Num Trials","CPU_F_GHz", cpu_freq_GHz);
|
||||
else
|
||||
fprintf(stderr, "%25s %25s %25s %20s %15s %6f\n","Name","Total","Average/Frame","Trials", "CPU_F_GHz", cpu_freq_GHz);
|
||||
}
|
||||
|
||||
if (ts->trials>0) {
|
||||
//printf("%20s: total: %10.3f ms, average: %10.3f us (%10d trials)\n", name, ts->diff/cpu_freq_GHz/1000000.0, ts->diff/ts->trials/cpu_freq_GHz/1000.0, ts->trials);
|
||||
if ((total_exec_time == NULL) || (sf_exec_time== NULL)) {
|
||||
fprintf(stderr, "%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);
|
||||
} else {
|
||||
fprintf(stderr, "%25s: %15.3f ms (%5.2f%%); %15.3f us (%5.2f%%); %15d;\n",
|
||||
name,
|
||||
(ts->diff/cpu_freq_GHz/1000000.0),
|
||||
((ts->diff/cpu_freq_GHz/1000000.0)/(total_exec_time->diff/cpu_freq_GHz/1000000.0))*100, // percentage
|
||||
(ts->diff/ts->trials/cpu_freq_GHz/1000.0),
|
||||
((ts->diff/ts->trials/cpu_freq_GHz/1000.0)/(sf_exec_time->diff/sf_exec_time->trials/cpu_freq_GHz/1000.0))*100, // percentage
|
||||
ts->trials);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int print_meas_log(time_stats_t *ts,
|
||||
const char *name,
|
||||
time_stats_t *total_exec_time,
|
||||
time_stats_t *sf_exec_time,
|
||||
char *output)
|
||||
{
|
||||
int stroff = 0;
|
||||
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))
|
||||
stroff += sprintf(output, "%25s %25s %25s %25s %25s %6f\n","Name","Total","Per Trials", "Num Trials","CPU_F_GHz", cpu_freq_GHz);
|
||||
else
|
||||
stroff += sprintf(output+stroff, "%25s %25s %25s %20s %15s %6f\n","Name","Total","Average/Frame","Trials", "CPU_F_GHz", cpu_freq_GHz);
|
||||
}
|
||||
|
||||
if (ts->trials>0) {
|
||||
//printf("%20s: total: %10.3f ms, average: %10.3f us (%10d trials)\n", name, ts->diff/cpu_freq_GHz/1000000.0, ts->diff/ts->trials/cpu_freq_GHz/1000.0, ts->trials);
|
||||
if ((total_exec_time == NULL) || (sf_exec_time== NULL)) {
|
||||
stroff += sprintf(output+stroff, "%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);
|
||||
} else {
|
||||
stroff += sprintf(output+stroff, "%25s: %15.3f ms (%5.2f%%); %15.3f us (%5.2f%%); %15d;\n",
|
||||
name,
|
||||
(ts->diff/cpu_freq_GHz/1000000.0),
|
||||
((ts->diff/cpu_freq_GHz/1000000.0)/(total_exec_time->diff/cpu_freq_GHz/1000000.0))*100, // percentage
|
||||
(ts->diff/ts->trials/cpu_freq_GHz/1000.0),
|
||||
((ts->diff/ts->trials/cpu_freq_GHz/1000.0)/(sf_exec_time->diff/sf_exec_time->trials/cpu_freq_GHz/1000.0))*100, // percentage
|
||||
ts->trials);
|
||||
}
|
||||
}
|
||||
return stroff;
|
||||
}
|
||||
|
||||
double get_time_meas_us(time_stats_t *ts)
|
||||
{
|
||||
static double cpu_freq_GHz = 0.0;
|
||||
|
||||
if (cpu_freq_GHz == 0.0)
|
||||
cpu_freq_GHz = get_cpu_freq_GHz();
|
||||
|
||||
if (ts->trials>0)
|
||||
return (ts->diff/ts->trials/cpu_freq_GHz/1000.0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* function for the asynchronous measurment module: cpu stat are sent to a dedicated thread
|
||||
* which is in charge of computing the cpu time spent in a given function/algorithm...
|
||||
*/
|
||||
|
||||
time_stats_t *register_meas(char *name)
|
||||
{
|
||||
for (int i=0; i<max_cpumeasur; i++) {
|
||||
if (measur_table[i] == NULL) {
|
||||
measur_table[i] = (time_stats_t *)malloc(sizeof(time_stats_t));
|
||||
memset(measur_table[i] ,0,sizeof(time_stats_t));
|
||||
measur_table[i]->meas_name = strdup(name);
|
||||
measur_table[i]->meas_index = i;
|
||||
measur_table[i]->tpoolmsg =newNotifiedFIFO_elt(sizeof(time_stats_msg_t),0,NULL,NULL);
|
||||
measur_table[i]->tstatptr = (time_stats_msg_t *)NotifiedFifoData(measur_table[i]->tpoolmsg);
|
||||
return measur_table[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_measurtbl(void) {
|
||||
for (int i=0; i<max_cpumeasur; i++) {
|
||||
if (measur_table[i] != NULL) {
|
||||
free(measur_table[i]->meas_name);
|
||||
delNotifiedFIFO_elt(measur_table[i]->tpoolmsg);
|
||||
free(measur_table[i]);
|
||||
}
|
||||
}
|
||||
//free the fifo...
|
||||
}
|
||||
|
||||
void run_cpumeasur(void) {
|
||||
struct sched_param schedp;
|
||||
pthread_setname_np(pthread_self(), "measur");
|
||||
schedp.sched_priority=0;
|
||||
int rt=pthread_setschedparam(pthread_self(), SCHED_IDLE, &schedp);
|
||||
AssertFatal(rt==0, "couldn't set measur thread priority: %s\n",strerror(errno));
|
||||
initNotifiedFIFO(&measur_fifo);
|
||||
while(1) {
|
||||
notifiedFIFO_elt_t *msg = pullNotifiedFIFO(&measur_fifo);
|
||||
time_stats_msg_t *tsm = (time_stats_msg_t *)NotifiedFifoData(msg);
|
||||
switch(tsm->msgid) {
|
||||
case TIMESTAT_MSGID_START:
|
||||
measur_table[tsm->timestat_id]->in=tsm->ts;
|
||||
(measur_table[tsm->timestat_id]->trials)++;
|
||||
break;
|
||||
case TIMESTAT_MSGID_STOP:
|
||||
/// process duration is the difference between two clock points
|
||||
measur_table[tsm->timestat_id]->p_time = (tsm->ts - measur_table[tsm->timestat_id]->in);
|
||||
measur_table[tsm->timestat_id]->diff += measur_table[tsm->timestat_id]->p_time;
|
||||
if ( measur_table[tsm->timestat_id]->p_time > measur_table[tsm->timestat_id]->max )
|
||||
measur_table[tsm->timestat_id]->max = measur_table[tsm->timestat_id]->p_time;
|
||||
break;
|
||||
case TIMESTAT_MSGID_DISPLAY:
|
||||
{
|
||||
char aline[256];
|
||||
int start, stop;
|
||||
if (tsm->displayFunc != NULL) {
|
||||
if(tsm->timestat_id >= 0) {
|
||||
start=tsm->timestat_id ;
|
||||
stop=start+1;
|
||||
}
|
||||
else {
|
||||
start=0;
|
||||
stop=max_cpumeasur ;
|
||||
}
|
||||
for (int i=start ; i<stop ; i++) {
|
||||
if (measur_table[i] != NULL) {
|
||||
sprintf(aline,"%s: %15.3f us ",measur_table[i]->meas_name, measur_table[i]->trials==0?0:( (measur_table[i]->trials/measur_table[i]->diff )/ cpu_freq_GHz /1000 ));
|
||||
tsm->displayFunc(aline);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TIMESTAT_MSGID_END:
|
||||
free_measurtbl();
|
||||
delNotifiedFIFO_elt(msg);
|
||||
pthread_exit(NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
delNotifiedFIFO_elt(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void init_meas(void) {
|
||||
pthread_t thid;
|
||||
paramdef_t cpumeasur_params[] = CPUMEASUR_PARAMS_DESC;
|
||||
int numparams=sizeof(cpumeasur_params)/sizeof(paramdef_t);
|
||||
int rt = config_get( cpumeasur_params,numparams,CPUMEASUR_SECTION);
|
||||
AssertFatal(rt >= 0, "cpumeasur configuration couldn't be performed");
|
||||
measur_table=calloc(max_cpumeasur,sizeof( time_stats_t *));
|
||||
AssertFatal(measur_table!=NULL, "couldn't allocate %u cpu measurements entries\n",max_cpumeasur);
|
||||
rt=pthread_create(&thid,NULL, (void *(*)(void *))run_cpumeasur, NULL);
|
||||
AssertFatal(rt==0, "couldn't create cpu measurment thread: %s\n",strerror(errno));
|
||||
}
|
||||
|
||||
void send_meas(time_stats_t *ts, int msgid) {
|
||||
if (MEASURE_ENABLED(ts) ) {
|
||||
ts->tstatptr->timestat_id=ts->meas_index;
|
||||
ts->tstatptr->msgid = msgid ;
|
||||
ts->tstatptr->ts = rdtsc_oai();
|
||||
pushNotifiedFIFO(&measur_fifo, ts->tpoolmsg);
|
||||
}
|
||||
}
|
||||
|
||||
void end_meas(void) {
|
||||
notifiedFIFO_elt_t *nfe = newNotifiedFIFO_elt(sizeof(time_stats_msg_t),0,NULL,NULL);
|
||||
time_stats_msg_t *msg = (time_stats_msg_t *)NotifiedFifoData(nfe);
|
||||
msg->msgid = TIMESTAT_MSGID_END ;
|
||||
pushNotifiedFIFO(&measur_fifo, nfe);
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef __TIME_MEAS_DEFS__H__
|
||||
#define __TIME_MEAS_DEFS__H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
// global var to enable openair performance profiler
|
||||
extern int opp_enabled;
|
||||
extern double cpu_freq_GHz __attribute__ ((aligned(32)));;
|
||||
// structure to store data to compute cpu measurment
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
typedef long long oai_cputime_t;
|
||||
#elif defined(__arm__)
|
||||
typedef uint32_t oai_cputime_t;
|
||||
#else
|
||||
#error "building on unsupported CPU architecture"
|
||||
#endif
|
||||
|
||||
#define TIMESTAT_MSGID_START 0 /*!< \brief send time at measure starting point */
|
||||
#define TIMESTAT_MSGID_STOP 1 /*!< \brief send time at measure end point */
|
||||
#define TIMESTAT_MSGID_ENABLE 2 /*!< \brief enable measure point */
|
||||
#define TIMESTAT_MSGID_DISABLE 3 /*!< \brief disable measure point */
|
||||
#define TIMESTAT_MSGID_DISPLAY 10 /*!< \brief display measure */
|
||||
#define TIMESTAT_MSGID_END 11 /*!< \brief stops the measure threads and free assocated resources */
|
||||
typedef void(*meas_printfunc_t)(const char* format, ...);
|
||||
typedef struct {
|
||||
int msgid; /*!< \brief message id, as defined by TIMESTAT_MSGID_X macros */
|
||||
int timestat_id; /*!< \brief points to the time_stats_t entry in cpumeas table */
|
||||
oai_cputime_t ts; /*!< \brief time stamp */
|
||||
meas_printfunc_t displayFunc; /*!< \brief function to call when DISPLAY message is received*/
|
||||
} time_stats_msg_t;
|
||||
|
||||
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 */
|
||||
oai_cputime_t 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_t;
|
||||
#define MEASURE_ENABLED(X) (X->meas_enabled)
|
||||
|
||||
|
||||
|
||||
|
||||
static inline void start_meas(time_stats_t *ts) __attribute__((always_inline));
|
||||
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);
|
||||
int print_meas_log(time_stats_t *ts, const char *name, time_stats_t *total_exec_time, time_stats_t *sf_exec_time, char *output);
|
||||
double get_time_meas_us(time_stats_t *ts);
|
||||
double get_cpu_freq_GHz(void);
|
||||
|
||||
#if defined(__i386__)
|
||||
static inline unsigned long long rdtsc_oai(void) __attribute__((always_inline));
|
||||
static inline unsigned long long rdtsc_oai(void) {
|
||||
unsigned long long int x;
|
||||
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
|
||||
return x;
|
||||
}
|
||||
#elif defined(__x86_64__)
|
||||
static inline unsigned long long rdtsc_oai(void) __attribute__((always_inline));
|
||||
static inline unsigned long long rdtsc_oai(void) {
|
||||
unsigned long long a, d;
|
||||
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
|
||||
return (d<<32) | a;
|
||||
}
|
||||
|
||||
#elif defined(__arm__)
|
||||
static inline uint32_t rdtsc_oai(void) __attribute__((always_inline));
|
||||
static inline uint32_t rdtsc_oai(void) {
|
||||
uint32_t r = 0;
|
||||
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(r) );
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define CPUMEAS_DISABLE 0
|
||||
#define CPUMEAS_ENABLE 1
|
||||
#define CPUMEAS_GETSTATE 2
|
||||
static inline int cpumeas(int action) {
|
||||
switch (action) {
|
||||
case CPUMEAS_ENABLE:
|
||||
opp_enabled = 1;
|
||||
break;
|
||||
|
||||
case CPUMEAS_DISABLE:
|
||||
opp_enabled = 0;
|
||||
break;
|
||||
|
||||
case CPUMEAS_GETSTATE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return opp_enabled;
|
||||
}
|
||||
|
||||
static inline void start_meas(time_stats_t *ts) {
|
||||
if (opp_enabled) {
|
||||
if (ts->meas_flag==0) {
|
||||
ts->trials++;
|
||||
ts->in = rdtsc_oai();
|
||||
ts->meas_flag=1;
|
||||
} else {
|
||||
ts->in = rdtsc_oai();
|
||||
}
|
||||
if ((ts->trials&16383)<10) ts->max=0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void stop_meas(time_stats_t *ts) {
|
||||
if (opp_enabled) {
|
||||
long long out = rdtsc_oai();
|
||||
ts->diff += (out-ts->in);
|
||||
/// process duration is the difference between two clock points
|
||||
ts->p_time = (out-ts->in);
|
||||
ts->diff_square += (out-ts->in)*(out-ts->in);
|
||||
|
||||
if ((out-ts->in) > ts->max)
|
||||
ts->max = out-ts->in;
|
||||
|
||||
ts->meas_flag=0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void reset_meas(time_stats_t *ts) {
|
||||
ts->in=0;
|
||||
ts->diff=0;
|
||||
ts->p_time=0;
|
||||
ts->diff_square=0;
|
||||
ts->max=0;
|
||||
ts->trials=0;
|
||||
ts->meas_flag=0;
|
||||
}
|
||||
|
||||
static inline void copy_meas(time_stats_t *dst_ts,time_stats_t *src_ts) {
|
||||
if (opp_enabled) {
|
||||
dst_ts->trials=src_ts->trials;
|
||||
dst_ts->diff=src_ts->diff;
|
||||
dst_ts->max=src_ts->max;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void merge_meas(time_stats_t *dst_ts, const time_stats_t *src_ts)
|
||||
{
|
||||
if (!opp_enabled)
|
||||
return;
|
||||
dst_ts->trials += src_ts->trials;
|
||||
dst_ts->diff += src_ts->diff;
|
||||
if (src_ts->max > dst_ts->max)
|
||||
dst_ts->max = src_ts->max;
|
||||
}
|
||||
|
||||
#define CPUMEASUR_SECTION "cpumeasur"
|
||||
|
||||
#define CPUMEASUR_PARAMS_DESC { \
|
||||
{"max_cpumeasur", "Max number of cpu measur entries", 0, uptr:&max_cpumeasur, defintval:100, TYPE_UINT, 0},\
|
||||
}
|
||||
|
||||
void init_meas(void);
|
||||
time_stats_t *register_meas(char *name);
|
||||
#define START_MEAS(X) send_meas(X, TIMESTAT_MSGID_START)
|
||||
#define STOP_MEAS(X) send_meas(X, TIMESTAT_MSGID_STOP)
|
||||
void send_meas(time_stats_t *ts, int msgid);
|
||||
void end_meas(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user