/* * 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> #ifndef PHYSIM #include "common/utils/threadPool/thread-pool.h" #endif // 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__) #define OAI_CPUTIME_TYPE long long #elif defined(__arm__) #define OAI_CPUTIME_TYPE uint32_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_TYPE ts; /*!< \brief time stamp */ meas_printfunc_t displayFunc; /*!< \brief function to call when DISPLAY message is received*/ } time_stats_msg_t; typedef struct { OAI_CPUTIME_TYPE in; /*!< \brief time at measure starting point */ OAI_CPUTIME_TYPE diff; /*!< \brief average difference between time at starting point and time at endpoint*/ OAI_CPUTIME_TYPE p_time; /*!< \brief absolute process duration */ OAI_CPUTIME_TYPE diff_square; /*!< \brief process duration square */ OAI_CPUTIME_TYPE 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*/ #ifndef PHYSIM notifiedFIFO_elt_t *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*/ #endif } 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); 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 int cpumeas(int action); 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(); } } } 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; } } #ifndef PHYSIM extern notifiedFIFO_t measur_fifo; #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) static inline 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); #endif //ifndef PHYSIM #endif