Repository navigation
Expand file tree
/
Copy pathtime_meas.h
More file actions
369 lines (327 loc) · 13 KB
/
Copy pathtime_meas.h
File metadata and controls
369 lines (327 loc) · 13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
/*
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
*/
#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 cpu_meas_enabled;
extern double cpu_freq_GHz __attribute__ ((aligned(32)));
// structure to store data to compute cpu measurment
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
typedef long long 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;
/**
* \typedef time_stats_sorted_list_t
* \brief sorted list of time stats to get med, q1, q2
* it can be left disabled by leaving size equal to 0
* \var size allocated size of the list
* 0 is the sorted list is disabled
* \var nb_elm number of elements in the list
* \var list pointer to the list
*/
/*
* Marker set only by init_time_stats_sorted_list().
* It prevents an uninitialized time_stats_t from being mistaken for an
* enabled sorted list when its size field contains garbage.
*/
#define TIME_STATS_SORTED_LIST_MAGIC 0x51A7BEEF
typedef struct {
unsigned int size;
unsigned int nb_elm;
uint32_t magic;
oai_cputime_t *list;
} time_stats_sorted_list_t;
/**
* \brief initializes sorted list
* if dst is already initialized then asserts
* \param time_stats_sorted_list sorted list to be initialized
* \param size size of the sorted list
*/
void init_time_stats_sorted_list(time_stats_sorted_list_t *list, unsigned int size);
/**
* \brief free sorted list
* if dst is already free then does nothing
* \param time_stats_sorted_list sorted list to be freed
*/
void free_time_stats_sorted_list(time_stats_sorted_list_t *list);
/**
* \brief returns true if the sorted list is enabled and false otherwise
* \param time_stats_sorted_list sorted list to be tested
*/
int is_enabled_time_stats_sorted_list(const time_stats_sorted_list_t *list);
/**
* \brief empties sorted list
* if dst is not initialized then does nothing
* \param time_stats_sorted_list sorted list to be emptied
*/
void reset_time_stats_sorted_list(time_stats_sorted_list_t *list);
/**
* \brief inserts value sorted list
* if dst is not initialized then does nothing
* if dst is full then does nothing
* \param time_stats_sorted_list sorted list to insert in
* \param time time value to insert
*/
void insert_in_time_stats_sorted_list(time_stats_sorted_list_t *list, oai_cputime_t time);
/**
* \brief copy sorted list src into dst, freeing and replacing dst
* dst and src should be initialized, otherwise does nothing
* \param dst destination sorted list
* should be intitialized even with a dummy size 1 buffer to make sure that copying the list there is expected by the caller
* \param src source sorted list
*/
void copy_time_stats_sorted_list(time_stats_sorted_list_t *dst, const time_stats_sorted_list_t *src);
/**
* \brief inserts the content of sorted list src into dst
* dst and src should be initialized, otherwise does nothing
* if dst is not large enough to copy src then does nothing
* \param dst destination sorted list
* \param src source sorted list
*/
void merge_time_stats_sorted_list(time_stats_sorted_list_t *dst, const time_stats_sorted_list_t *src);
/**
* \brief get the minimum from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_min(time_stats_sorted_list_t *list);
/**
* \brief get the median from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_median(time_stats_sorted_list_t *list);
/**
* \brief get the first quartile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_q1(time_stats_sorted_list_t *list);
/**
* \brief get the third quartile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_q3(time_stats_sorted_list_t *list);
/**
* \brief get the first decile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_d1(time_stats_sorted_list_t *list);
/**
* \brief get the nineth decile from a sorted list
* if the sorted list is not initialized or empty then returns -1
* \param time_stats_sorted_list sorted list to query
*/
oai_cputime_t get_d9(time_stats_sorted_list_t *list);
struct notifiedFIFO_elt_s;
typedef struct time_stats {
oai_cputime_t in; /*!< \brief time at measure starting point */
oai_cputime_t diff; /*!< \brief average difference between time at starting point and time at endpoint*/
oai_cputime_t p_time; /*!< \brief absolute process duration */
double diff_square; /*!< \brief process duration square */
oai_cputime_t max; /*!< \brief maximum difference between time at starting point and time at endpoint*/
int trials; /*!< \brief number of start point - end point iterations */
int meas_flag; /*!< \brief 1: stop_meas not called (consecutive calls of start_meas) */
char *meas_name; /*!< \brief name to use when printing the measure (not used for PHY simulators)*/
int meas_index; /*!< \brief index of this measure in the measure array (not used for PHY simulators)*/
int meas_enabled; /*!< \brief per measure enablement flag. send_meas tests this flag, unused today in start_meas and stop_meas*/
struct notifiedFIFO_elt_s *tpoolmsg; /*!< \brief message pushed to the cpu measurment queue to report a measure START or STOP */
time_stats_msg_t *tstatptr; /*!< \brief pointer to the time_stats_msg_t data in the tpoolmsg, stored here for perf considerations */
time_stats_sorted_list_t time_stats_sorted_list; /*!< \brief optional sorted list to get med, q1, q2 */
} time_stats_t;
#define MEASURE_ENABLED(X) (X->meas_enabled)
static inline void start_meas(time_stats_t *ts) __attribute__((always_inline));
static inline void stop_meas(time_stats_t *ts) __attribute__((always_inline));
/**
* \brief get the standard deviation of a timer
* \param ptr timer to query
*/
double get_std_dev(time_stats_t *ptr);
void print_meas_now(time_stats_t *ts, const char *name, FILE *file_name);
void print_meas(time_stats_t *ts, const char *name, time_stats_t *total_exec_time, time_stats_t *sf_exec_time);
size_t print_meas_log_header(time_stats_t *total_exec_time,
time_stats_t *sf_exec_time,
char *output,
size_t outputlen,
int cpu_meas_enabled);
size_t print_meas_log(time_stats_t *ts,
const char *name,
time_stats_t *total_exec_time,
time_stats_t *sf_exec_time,
char *output,
size_t outputlen);
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(__aarch64__)
static inline uint64_t rdtsc_oai(void) __attribute__((always_inline));
static inline uint64_t rdtsc_oai(void)
{
uint64_t r = 0;
asm volatile("mrs %0, cntvct_el0" : "=r"(r));
return r;
}
#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
static inline long long clock_gettime_oai()
{
struct timespec time;
#ifdef CLOCK_MONOTONIC_RAW
// CLOCK_MONOTONIC_RAW only on linux
// See clock_getres(2)
clock_gettime(CLOCK_MONOTONIC_RAW, &time);
#else
clock_gettime(CLOCK_REALTIME, &time);
#endif
return 1e+9 * time.tv_sec + time.tv_nsec;
}
#define CPUMEAS_DISABLE 0
#define CPUMEAS_ENABLE 1
#define CPUMEAS_GETSTATE 2
static inline int cpumeas(int action) {
switch (action) {
case CPUMEAS_ENABLE:
cpu_meas_enabled = 1;
break;
case CPUMEAS_DISABLE:
cpu_meas_enabled = 0;
break;
case CPUMEAS_GETSTATE:
default:
break;
}
return cpu_meas_enabled;
}
static inline void start_meas(time_stats_t *ts) {
if (cpu_meas_enabled) {
if (ts->meas_flag==0) {
ts->trials++;
ts->in = clock_gettime_oai();
ts->meas_flag=1;
} else {
ts->in = clock_gettime_oai();
}
if ((ts->trials&16383)<10) ts->max=0;
}
}
static inline void stop_meas(time_stats_t *ts) {
if (cpu_meas_enabled) {
long long out = clock_gettime_oai();
if (ts->in) {
ts->diff += (out - ts->in);
/// process duration is the difference between two clock points
ts->p_time = (out - ts->in);
ts->diff_square += ((double)out - ts->in) * ((double)out - ts->in);
if ((out - ts->in) > ts->max)
ts->max = out - ts->in;
insert_in_time_stats_sorted_list(&ts->time_stats_sorted_list, (out - ts->in));
ts->meas_flag = 0;
}
}
}
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;
reset_time_stats_sorted_list(&ts->time_stats_sorted_list);
}
static inline void copy_meas(time_stats_t *dst_ts,time_stats_t *src_ts) {
if (cpu_meas_enabled) {
dst_ts->trials=src_ts->trials;
dst_ts->diff=src_ts->diff;
dst_ts->max=src_ts->max;
copy_time_stats_sorted_list(&dst_ts->time_stats_sorted_list, &src_ts->time_stats_sorted_list);
}
}
static inline void merge_meas(time_stats_t *dst_ts, const time_stats_t *src_ts)
{
if (!cpu_meas_enabled)
return;
dst_ts->trials += src_ts->trials;
dst_ts->diff += src_ts->diff;
dst_ts->diff_square += src_ts->diff_square;
if (src_ts->max > dst_ts->max)
dst_ts->max = src_ts->max;
if (is_enabled_time_stats_sorted_list(&src_ts->time_stats_sorted_list)) {
merge_time_stats_sorted_list(&dst_ts->time_stats_sorted_list, &src_ts->time_stats_sorted_list);
} else if (src_ts->trials == 1) {
insert_in_time_stats_sorted_list(&dst_ts->time_stats_sorted_list, src_ts->max);
}
}
#define TIME_STATS_ADVANCED_MODE 2
static inline void init_sorted_list_meas(time_stats_t *ts, unsigned int size)
{
init_time_stats_sorted_list(&ts->time_stats_sorted_list, size);
}
static inline void free_sorted_list_meas(time_stats_t *ts)
{
free_time_stats_sorted_list(&ts->time_stats_sorted_list);
}
#define CPUMEASUR_SECTION "cpumeasur"
// clang-format off
#define CPUMEASUR_PARAMS_DESC { \
{"max_cpumeasur", "Max number of cpu measur entries", 0, .uptr=&max_cpumeasur, .defintval=100, TYPE_UINT, 0}, \
}
// clang-format on
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);
#define timeIt(a) \
{ \
uint64_t deb = clock_gettime_oai(); \
a; \
LOG_W(UTIL, #a ": %llu\n", (clock_gettime_oai() - deb) / 3000); \
}
#endif