FD.io VPP  v16.06
Vector Packet Processing
elog.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  Copyright (c) 2005,2009 Eliot Dresselhaus
17 
18  Permission is hereby granted, free of charge, to any person obtaining
19  a copy of this software and associated documentation files (the
20  "Software"), to deal in the Software without restriction, including
21  without limitation the rights to use, copy, modify, merge, publish,
22  distribute, sublicense, and/or sell copies of the Software, and to
23  permit persons to whom the Software is furnished to do so, subject to
24  the following conditions:
25 
26  The above copyright notice and this permission notice shall be
27  included in all copies or substantial portions of the Software.
28 
29  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37 
38 /* High speed event logging with much thanks to Dave Barach. */
39 
40 #ifndef included_clib_elog_h
41 #define included_clib_elog_h
42 
43 #include <vppinfra/cache.h>
44 #include <vppinfra/error.h> /* for ASSERT */
45 #include <vppinfra/serialize.h>
46 #include <vppinfra/time.h> /* for clib_cpu_time_now */
47 #include <vppinfra/mhash.h>
48 
49 typedef struct{
50  union {
51  /* Absolute time stamp in CPU clock cycles. */
53 
54  /* Absolute time as floating point number in seconds. */
56  };
57 
58  /* Event type index. */
60 
61  /* Track for this event. Tracks allow events to be sorted and
62  displayed by track. Think of 2 dimensional display with time and
63  track being the x and y axes.*/
65 
66  /* 20-bytes of data follows and pads to 32 bytes. */
67  u8 data[20];
68 } elog_event_t;
69 
70 typedef struct {
71  /* Type index plus one assigned to this type.
72  This is used to mark type as seen. */
74 
75  /* String table as a vector constructed when type is registered. */
77 
78  /* Format string. (example: "my-event (%d,%d)"). */
79  char * format;
80 
81  /* Specifies how arguments to format are parsed from event data.
82  String of characters '0' '1' or '2' '3' to specify log2 size of data
83  (e.g. for u8, u16, u32 or u64),
84  's' means a null-terminated C string
85  't' means argument is an index into enum string table for this type.
86  'e' is a float,
87  'f' is a double. */
88  char * format_args;
89 
90  /* Function name generating event. */
91  char * function;
92 
93  /* Number of elements in string enum table. */
95 
96  /* String table for enum/number to string formatting. */
97  char * enum_strings[];
99 
100 typedef struct {
101  /* Track name vector. */
102  char * name;
103 
104  /* Set to one when track has been added to
105  main structure. */
107 } elog_track_t;
108 
109 typedef struct {
110  /* CPU cycle counter. */
112 
113  /* OS timer in nano secs since epoch Jan 1 1970. */
116 
117 typedef struct {
118  /* Total number of events in buffer. */
120 
121  /* When count reaches limit logging is disabled. This is
122  used for event triggers. */
124 
125  /* Dummy event to use when logger is disabled. */
127 
128  /* Power of 2 number of elements in ring. */
130 
131  /* Vector of events (circular buffer). Power of 2 size.
132  Used when events are being collected. */
134 
135  /* Vector of event types. */
137 
138  /* Hash table mapping type format to type index. */
140 
141  /* Events may refer to strings in string table. */
142  char * string_table;
143 
144  /* Vector of tracks. */
146 
147  /* Default track. */
149 
150  /* Place holder for CPU clock frequency. */
152 
154 
155  /* SMP lock, non-zero means locking required */
157 
158  /* Use serialize_time and init_time to give estimate for
159  cpu clock frequency. */
161 
162  /* Vector of events converted to generic form after collection. */
164 } elog_main_t;
165 
168 { return clib_min (em->n_total_events, em->event_ring_size); }
169 
172 { return em->event_ring_size; }
173 
174 always_inline void
176 {
177  em->n_total_events = 0;
179 }
180 
181 always_inline void
182 elog_enable_disable (elog_main_t * em, int is_enabled)
183 {
184  em->n_total_events = 0;
185  em->n_total_events_disable_limit = is_enabled ? ~0 : 0;
186 }
187 
188 /* Disable logging after specified number of ievents have been logged.
189  This is used as a "debug trigger" when a certain event has occurred.
190  Events will be logged both before and after the "event" but the
191  event will not be lost as long as N < RING_SIZE. */
192 always_inline void
195 
196 /* Signal a trigger. We do this when we encounter an event that we want to save
197  context around (before and after). */
198 always_inline void
201 
202 /* External function to register types/tracks. */
205 
208 { return em->n_total_events < em->n_total_events_disable_limit; }
209 
210 /* Add an event to the log. Returns a pointer to the
211  data for caller to write into. */
212 always_inline void *
215  elog_track_t * track,
216  u64 cpu_time)
217 {
218  elog_event_t * e;
219  uword ei;
220  word type_index, track_index;
221 
222  /* Return the user dummy memory to scribble data into. */
223  if (PREDICT_FALSE (! elog_is_enabled (em)))
224  return em->dummy_event.data;
225 
226  type_index = (word) type->type_index_plus_one - 1;
227  track_index = (word) track->track_index_plus_one - 1;
228  if (PREDICT_FALSE ((type_index | track_index) < 0))
229  {
230  if (type_index < 0)
231  type_index = elog_event_type_register (em, type);
232  if (track_index < 0)
233  track_index = elog_track_register (em, track);
234  }
235 
236  ASSERT (type_index < vec_len (em->event_types));
237  ASSERT (track_index < vec_len (em->tracks));
238  ASSERT (is_pow2 (vec_len (em->event_ring)));
239 
240  if (em->lock)
241  ei = clib_smp_atomic_add (&em->n_total_events, 1);
242  else
243  ei = em->n_total_events++;
244 
245  ei &= em->event_ring_size - 1;
246  e = vec_elt_at_index (em->event_ring, ei);
247 
248  e->time_cycles = cpu_time;
249  e->type = type_index;
250  e->track = track_index;
251 
252  /* Return user data for caller to fill in. */
253  return e->data;
254 }
255 
256 /* External version of inline. */
257 void *
260  elog_track_t * track,
261  u64 cpu_time);
262 
263 /* Non-inline version. */
264 always_inline void *
266  elog_event_type_t * type,
267  elog_track_t * track,
268  u64 cpu_time)
269 {
270  /* Return the user dummy memory to scribble data into. */
271  if (PREDICT_FALSE (! elog_is_enabled (em)))
272  return em->dummy_event.data;
273  return elog_event_data (em, type, track, cpu_time);
274 }
275 
276 /* Most common forms: log a single 32 bit datum, w / w-out track */
277 always_inline void
278 elog (elog_main_t * em, elog_event_type_t * type, u32 data)
279 {
281  (em,
282  type,
283  &em->default_track,
284  clib_cpu_time_now ());
285  d[0] = data;
286 }
287 
288 /* Inline version of above. */
289 always_inline void
291 {
293  (em,
294  type,
295  &em->default_track,
296  clib_cpu_time_now ());
297  d[0] = data;
298 }
299 
300 always_inline void
302  u32 data)
303 {
305  (em,
306  type,
307  track,
308  clib_cpu_time_now ());
309  d[0] = data;
310 }
311 
312 always_inline void
314  elog_track_t *track, u32 data)
315 {
317  (em,
318  type,
319  track,
320  clib_cpu_time_now ());
321  d[0] = data;
322 }
323 
324 always_inline void *
326 {
328  (em, type, track,
329  clib_cpu_time_now ());
330 }
331 
332 always_inline void *
334 {
336  (em, type, track,
337  clib_cpu_time_now ());
338 }
339 
340 /* Macro shorthands for generating/declaring events. */
341 #define __ELOG_TYPE_VAR(f) f
342 #define __ELOG_TRACK_VAR(f) f
343 
344 #define ELOG_TYPE_DECLARE(f) static elog_event_type_t __ELOG_TYPE_VAR(f)
345 
346 #define ELOG_TYPE_INIT_FORMAT_AND_FUNCTION(fmt,func) \
347  { .format = fmt, .function = func, }
348 
349 #define ELOG_TYPE_INIT(fmt) \
350  ELOG_TYPE_INIT_FORMAT_AND_FUNCTION(fmt,(char *) __FUNCTION__)
351 
352 #define ELOG_TYPE_DECLARE_HELPER(f,fmt,func) \
353  static elog_event_type_t __ELOG_TYPE_VAR(f) = \
354  ELOG_TYPE_INIT_FORMAT_AND_FUNCTION (fmt, func)
355 
356 #define ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION(f,fmt) \
357  ELOG_TYPE_DECLARE_HELPER (f, fmt, (char *) __FUNCTION__)
358 
359 #define ELOG_TYPE_DECLARE_FORMAT(f,fmt) \
360  ELOG_TYPE_DECLARE_HELPER (f, fmt, 0)
361 
362 /* Shorthands with and without __FUNCTION__.
363  D for decimal; X for hex. F for __FUNCTION__. */
364 #define ELOG_TYPE(f,fmt) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION(f,fmt)
365 #define ELOG_TYPE_D(f) ELOG_TYPE_DECLARE_FORMAT (f, #f " %d")
366 #define ELOG_TYPE_X(f) ELOG_TYPE_DECLARE_FORMAT (f, #f " 0x%x")
367 #define ELOG_TYPE_DF(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " %d")
368 #define ELOG_TYPE_XF(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " 0x%x")
369 #define ELOG_TYPE_FD(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " %d")
370 #define ELOG_TYPE_FX(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " 0x%x")
371 
372 #define ELOG_TRACK_DECLARE(f) static elog_track_t __ELOG_TRACK_VAR(f)
373 #define ELOG_TRACK(f) ELOG_TRACK_DECLARE(f) = { .name = #f, }
374 
375 /* Log 32 bits of data. */
376 #define ELOG(em,f,data) elog ((em), &__ELOG_TYPE_VAR(f), data)
377 #define ELOG_INLINE(em,f,data) elog_inline ((em), &__ELOG_TYPE_VAR(f), data)
378 
379 /* Return data pointer to fill in. */
380 #define ELOG_TRACK_DATA(em,f,track) \
381  elog_data ((em), &__ELOG_TYPE_VAR(f), &__ELOG_TRACK_VAR(track))
382 #define ELOG_TRACK_DATA_INLINE(em,f,track) \
383  elog_data_inline ((em), &__ELOG_TYPE_VAR(f), &__ELOG_TRACK_VAR(track))
384 
385 /* Shorthand with default track. */
386 #define ELOG_DATA(em,f) elog_data ((em), &__ELOG_TYPE_VAR (f), &(em)->default_track)
387 #define ELOG_DATA_INLINE(em,f) elog_data_inline ((em), &__ELOG_TYPE_VAR (f), &(em)->default_track)
388 
389 u32 elog_string (elog_main_t * em, char * format, ...);
390 void elog_time_now (elog_time_stamp_t * et);
391 
392 /* Convert ievents to events and return them as a vector.
393  Sets em->events to resulting vector. */
395 
396 /* Convert ievents to events and return them as a vector with no side effects. */
398 
399 /* Merge two logs, add supplied track tags. */
400 void elog_merge (elog_main_t * dst, u8 * dst_tag,
401  elog_main_t * src, u8 * src_tag);
402 
403 /* 2 arguments elog_main_t and elog_event_t to format event or track name. */
404 u8 * format_elog_event (u8 * s, va_list * va);
405 u8 * format_elog_track (u8 * s, va_list * va);
406 
407 void serialize_elog_main (serialize_main_t * m, va_list * va);
408 void unserialize_elog_main (serialize_main_t * m, va_list * va);
409 
410 void elog_init (elog_main_t * em, u32 n_events);
411 void elog_alloc (elog_main_t * em, u32 n_events);
412 
413 #ifdef CLIB_UNIX
416 {
418  clib_error_t * error;
419 
420  error = serialize_open_unix_file (&m, unix_file);
421  if (error)
422  return error;
423  error = serialize (&m, serialize_elog_main, em);
424  if (! error)
425  serialize_close (&m);
426  return error;
427 }
428 
431 {
433  clib_error_t * error;
434 
435  error = unserialize_open_unix_file (&m, unix_file);
436  if (error)
437  return error;
438  error = unserialize (&m, unserialize_elog_main, em);
439  if (! error)
440  unserialize_close (&m);
441  return error;
442 }
443 
444 #endif /* CLIB_UNIX */
445 
446 #endif /* included_clib_elog_h */
char ** enum_strings_vector
Definition: elog.h:76
f64 time
Definition: elog.h:55
elog_time_stamp_t serialize_time
Definition: elog.h:153
u32 elog_string(elog_main_t *em, char *format,...)
Definition: elog.c:496
#define clib_min(x, y)
Definition: clib.h:295
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
always_inline uword elog_buffer_capacity(elog_main_t *em)
Definition: elog.h:171
u64 time_cycles
Definition: elog.h:52
always_inline void * elog_data(elog_main_t *em, elog_event_type_t *type, elog_track_t *track)
Definition: elog.h:325
void serialize_elog_main(serialize_main_t *m, va_list *va)
Definition: elog.c:949
u8 * format_elog_event(u8 *s, va_list *va)
Definition: elog.c:274
always_inline void * elog_data_inline(elog_main_t *em, elog_event_type_t *type, elog_track_t *track)
Definition: elog.h:333
always_inline void elog_reset_buffer(elog_main_t *em)
Definition: elog.h:175
word elog_event_type_register(elog_main_t *em, elog_event_type_t *t)
Definition: elog.c:98
always_inline void elog(elog_main_t *em, elog_event_type_t *type, u32 data)
Definition: elog.h:278
elog_event_t dummy_event
Definition: elog.h:126
char * format
Definition: elog.h:79
void unserialize_elog_main(serialize_main_t *m, va_list *va)
Definition: elog.c:980
always_inline void elog_disable_trigger(elog_main_t *em)
Definition: elog.h:199
u8 data[20]
Definition: elog.h:67
always_inline uword elog_is_enabled(elog_main_t *em)
Definition: elog.h:207
u32 n_enum_strings
Definition: elog.h:94
always_inline void elog_enable_disable(elog_main_t *em, int is_enabled)
Definition: elog.h:182
#define clib_smp_atomic_add(addr, increment)
Definition: smp.h:110
clib_error_t * serialize_open_unix_file(serialize_main_t *m, char *file)
Definition: serialize.c:1157
clib_error_t * unserialize_open_unix_file(serialize_main_t *m, char *file)
Definition: serialize.c:1161
#define always_inline
Definition: clib.h:84
u32 type_index_plus_one
Definition: elog.h:73
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
always_inline void elog_inline(elog_main_t *em, elog_event_type_t *type, u32 data)
Definition: elog.h:290
always_inline void elog_track(elog_main_t *em, elog_event_type_t *type, elog_track_t *track, u32 data)
Definition: elog.h:301
uword * lock
Definition: elog.h:156
unsigned long u64
Definition: types.h:89
char * format_args
Definition: elog.h:88
uword * event_type_by_format
Definition: elog.h:139
elog_event_type_t * event_types
Definition: elog.h:136
void elog_init(elog_main_t *em, u32 n_events)
Definition: elog.c:435
char * name
Definition: elog.h:102
always_inline clib_error_t * elog_read_file(elog_main_t *em, char *unix_file)
Definition: elog.h:430
void elog_alloc(elog_main_t *em, u32 n_events)
Definition: elog.c:422
always_inline void elog_disable_after_events(elog_main_t *em, uword n)
Definition: elog.h:193
elog_event_t * event_ring
Definition: elog.h:133
#define PREDICT_FALSE(x)
Definition: clib.h:97
always_inline void * elog_event_data_inline(elog_main_t *em, elog_event_type_t *type, elog_track_t *track, u64 cpu_time)
Definition: elog.h:213
f64 nsec_per_cpu_clock
Definition: elog.h:160
word elog_track_register(elog_main_t *em, elog_track_t *t)
Definition: elog.c:179
always_inline void * elog_event_data_not_inline(elog_main_t *em, elog_event_type_t *type, elog_track_t *track, u64 cpu_time)
Definition: elog.h:265
clib_error_t * serialize(serialize_main_t *m,...)
Definition: serialize.c:627
always_inline uword elog_n_events_in_buffer(elog_main_t *em)
Definition: elog.h:167
u32 track_index_plus_one
Definition: elog.h:106
u32 n_total_events_disable_limit
Definition: elog.h:123
void unserialize_close(serialize_main_t *m)
Definition: serialize.c:825
always_inline uword is_pow2(uword x)
Definition: clib.h:252
void elog_time_now(elog_time_stamp_t *et)
Definition: elog.c:382
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
uword event_ring_size
Definition: elog.h:129
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
void serialize_close(serialize_main_t *m)
Definition: serialize.c:822
clib_error_t * unserialize(serialize_main_t *m,...)
Definition: serialize.c:639
u16 track
Definition: elog.h:64
always_inline void elog_track_inline(elog_main_t *em, elog_event_type_t *type, elog_track_t *track, u32 data)
Definition: elog.h:313
clib_time_t cpu_timer
Definition: elog.h:151
u8 * format_elog_track(u8 *s, va_list *va)
Definition: elog.c:374
u64 uword
Definition: types.h:112
elog_event_t * events
Definition: elog.h:163
unsigned short u16
Definition: types.h:57
i64 word
Definition: types.h:111
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:140
unsigned char u8
Definition: types.h:56
u16 type
Definition: elog.h:59
Definition: unix.h:49
elog_track_t * tracks
Definition: elog.h:145
char * string_table
Definition: elog.h:142
elog_track_t default_track
Definition: elog.h:148
u32 n_total_events
Definition: elog.h:119
elog_event_t * elog_get_events(elog_main_t *em)
Definition: elog.c:513
elog_event_t * elog_peek_events(elog_main_t *em)
Definition: elog.c:474
always_inline u64 clib_cpu_time_now(void)
Definition: time.h:71
always_inline clib_error_t * elog_write_file(elog_main_t *em, char *unix_file)
Definition: elog.h:415
void elog_merge(elog_main_t *dst, u8 *dst_tag, elog_main_t *src, u8 *src_tag)
Definition: elog.c:575
void * elog_event_data(elog_main_t *em, elog_event_type_t *type, elog_track_t *track, u64 cpu_time)
Definition: elog.c:63