FD.io VPP  v16.06
Vector Packet Processing
elog.c
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 #include <vppinfra/elog.h>
39 #include <vppinfra/cache.h>
40 #include <vppinfra/error.h>
41 #include <vppinfra/format.h>
42 #include <vppinfra/hash.h>
43 #include <vppinfra/math.h>
44 
45 static inline void elog_lock (elog_main_t * em)
46 {
47  if (PREDICT_FALSE(em->lock != 0))
48  while (__sync_lock_test_and_set (em->lock, 1))
49  ;
50 }
51 
52 static inline void elog_unlock (elog_main_t * em)
53 {
54  if (PREDICT_FALSE(em->lock != 0))
55  {
57  *em->lock = 0;
58  }
59 }
60 
61 /* Non-inline version. */
62 void *
65  elog_track_t * track,
66  u64 cpu_time)
67 { return elog_event_data_inline (em, type, track, cpu_time); }
68 
69 static void new_event_type (elog_main_t * em, uword i)
70 {
72 
73  if (! em->event_type_by_format)
74  em->event_type_by_format = hash_create_vec (/* size */ 0, sizeof (u8), sizeof (uword));
75 
77 }
78 
79 static uword
81 {
83  uword i;
84 
85  if (p)
86  i = p[0];
87  else
88  {
89  i = vec_len (em->event_types);
90  vec_add1 (em->event_types, t[0]);
91  new_event_type (em, i);
92  }
93 
94  return i;
95 }
96 
97 /* External function to register types. */
99 {
100  elog_event_type_t * static_type = t;
101  word l;
102 
103  elog_lock (em);
104 
105  l = vec_len (em->event_types);
106 
107  t->type_index_plus_one = 1 + l;
108 
109  ASSERT (t->format);
110 
111  /* If format args are not specified try to be smart about providing defaults
112  so most of the time user does not have to specify them. */
113  if (! t->format_args)
114  {
115  uword i, l;
116  char * this_arg;
117 
118  l = strlen (t->format);
119  for (i = 0; i < l; i++)
120  {
121  if (t->format[i] != '%')
122  continue;
123  if (i + 1 >= l)
124  continue;
125  if (t->format[i+1] == '%') /* %% */
126  continue;
127 
128  switch (t->format[i+1]) {
129  default:
130  case 'd': case 'x': case 'u':
131  this_arg = "i4"; /* size of u32 */
132  break;
133  case 'f':
134  this_arg = "f8"; /* defaults to f64 */
135  break;
136  case 's':
137  this_arg = "s0"; /* defaults to null terminated string. */
138  break;
139  }
140 
141  t->format_args = (char *) format ((u8 *) t->format_args, "%s", this_arg);
142  }
143 
144  /* Null terminate. */
145  vec_add1 (t->format_args, 0);
146  }
147 
148  vec_add1 (em->event_types, t[0]);
149 
150  t = em->event_types + l;
151 
152  /* Make copies of strings for hashing etc. */
153  if (t->function)
154  t->format = (char *) format (0, "%s %s%c", t->function, t->format, 0);
155  else
156  t->format = (char *) format (0, "%s%c", t->format, 0);
157 
158  t->format_args = (char *) format (0, "%s%c", t->format_args, 0);
159 
160  /* Construct string table. */
161  {
162  uword i;
163  t->n_enum_strings = static_type->n_enum_strings;
164  for (i = 0; i < t->n_enum_strings; i++)
165  {
166  if (! static_type->enum_strings[i])
167  static_type->enum_strings[i] = "MISSING";
169  (char *) format (0, "%s%c", static_type->enum_strings[i], 0));
170  }
171  }
172 
173  new_event_type (em, l);
174  elog_unlock(em);
175 
176  return l;
177 }
178 
180 {
181  word l;
182 
183  elog_lock (em);
184 
185  l = vec_len (em->tracks);
186 
187  t->track_index_plus_one = 1 + l;
188 
189  ASSERT (t->name);
190 
191  vec_add1 (em->tracks, t[0]);
192 
193  t = em->tracks + l;
194 
195  t->name = (char *) format (0, "%s%c", t->name, 0);
196 
197  elog_unlock (em);
198 
199  return l;
200 }
201 
202 static uword parse_2digit_decimal (char * p, uword * number)
203 {
204  uword i = 0;
205  u8 digits[2];
206 
207  digits[0] = digits[1] = 0;
208  while (p[i] >= '0' && p[i] <= '9')
209  {
210  if (i >= 2)
211  break;
212  digits[i] = p[i] - '0';
213  i++;
214  }
215 
216  if (i >= 1 && i <= 2)
217  {
218  if (i == 1)
219  *number = digits[0];
220  else
221  *number = 10 * digits[0] + digits[1];
222  return i;
223  }
224  else
225  return 0;
226 }
227 
228 static u8 * fixed_format (u8 * s, char * fmt, char * result, uword * result_len)
229 {
230  char * f = fmt;
231  char * percent;
232  uword l = 0;
233 
234  while (1)
235  {
236  if (f[0] == 0)
237  break;
238  if (f[0] == '%' && f[1] != '%')
239  break;
240  f++;
241  }
242  if (f > fmt)
243  vec_add (s, fmt, f - fmt);
244 
245  if (f[0] != '%')
246  goto done;
247 
248  /* Skip percent. */
249  percent = f++;
250 
251  /* Skip possible +-= justification. */
252  f += f[0] == '+' || f[0] == '-' || f[0] == '=';
253 
254  /* Skip possible X.Y width. */
255  while ((f[0] >= '0' && f[0] <= '9') || f[0] == '.')
256  f++;
257 
258  /* Skip wlL as in e.g. %Ld. */
259  f += f[0] == 'w' || f[0] == 'l' || f[0] == 'L';
260 
261  /* Finally skip format letter. */
262  f += f[0] != 0;
263 
264  ASSERT (*result_len > f - percent);
265  l = clib_min (f - percent, *result_len - 1);
266  clib_memcpy (result, percent, l);
267  result[l] = 0;
268 
269  done:
270  *result_len = f - fmt;
271  return s;
272 }
273 
274 u8 * format_elog_event (u8 * s, va_list * va)
275 {
276  elog_main_t * em = va_arg (*va, elog_main_t *);
277  elog_event_t * e = va_arg (*va, elog_event_t *);
278  elog_event_type_t * t;
279  char * a, * f;
280  void * d = (u8 *) e->data;
281  char arg_format[64];
282 
283  t = vec_elt_at_index (em->event_types, e->type);
284 
285  f = t->format;
286  a = t->format_args;
287  while (1)
288  {
289  uword n_bytes = 0, n_digits, f_bytes = 0;
290 
291  f_bytes = sizeof (arg_format);
292  s = fixed_format (s, f, arg_format, &f_bytes);
293  f += f_bytes;
294 
295  if (a == 0 || a[0] == 0)
296  {
297  /* Format must also be at end. */
298  ASSERT (f[0] == 0);
299  break;
300  }
301 
302  /* Don't go past end of event data. */
303  ASSERT (d < (void *) (e->data + sizeof (e->data)));
304 
305  n_digits = parse_2digit_decimal (a + 1, &n_bytes);
306  switch (a[0])
307  {
308  case 'i':
309  case 't':
310  case 'T':
311  {
312  u32 i = 0;
313  u64 l = 0;
314 
315  if (n_bytes == 1)
316  i = ((u8 *) d)[0];
317  else if (n_bytes == 2)
318  i = clib_mem_unaligned (d, u16);
319  else if (n_bytes == 4)
320  i = clib_mem_unaligned (d, u32);
321  else if (n_bytes == 8)
322  l = clib_mem_unaligned (d, u64);
323  else
324  ASSERT (0);
325  if (a[0] == 't')
326  {
327  char * e = vec_elt (t->enum_strings_vector, n_bytes == 8 ? l : i);
328  s = format (s, arg_format, e);
329  }
330  else if (a[0] == 'T')
331  {
332  char * e = vec_elt_at_index (em->string_table, n_bytes == 8 ? l : i);
333  s = format (s, arg_format, e);
334  }
335  else if (n_bytes == 8)
336  s = format (s, arg_format, l);
337  else
338  s = format (s, arg_format, i);
339  }
340  break;
341 
342  case 'f':
343  {
344  f64 x = 0;
345  if (n_bytes == 4)
346  x = clib_mem_unaligned (d, f32);
347  else if (n_bytes == 8)
348  x = clib_mem_unaligned (d, f64);
349  else
350  ASSERT (0);
351  s = format (s, arg_format, x);
352  }
353  break;
354 
355  case 's':
356  s = format (s, arg_format, d);
357  if (n_bytes == 0)
358  n_bytes = strlen (d) + 1;
359  break;
360 
361  default:
362  ASSERT (0);
363  break;
364  }
365 
366  ASSERT (n_digits > 0 && n_digits <= 2);
367  a += 1 + n_digits;
368  d += n_bytes;
369  }
370 
371  return s;
372 }
373 
374 u8 * format_elog_track (u8 * s, va_list * va)
375 {
376  elog_main_t * em = va_arg (*va, elog_main_t *);
377  elog_event_t * e = va_arg (*va, elog_event_t *);
378  elog_track_t * t = vec_elt_at_index (em->tracks, e->track);
379  return format (s, "%s", t->name);
380 }
381 
383 {
384  u64 cpu_time_now, os_time_now_nsec;
385 
386 #ifdef CLIB_UNIX
387  {
388 #include <sys/syscall.h>
389  struct timespec ts;
390  syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
391  cpu_time_now = clib_cpu_time_now ();
392  os_time_now_nsec = 1e9 * ts.tv_sec + ts.tv_nsec;
393  }
394 #else
395  cpu_time_now = clib_cpu_time_now ();
396  os_time_now_nsec = 0;
397 #endif
398 
399  et->cpu = cpu_time_now;
400  et->os_nsec = os_time_now_nsec;
401 }
402 
405  elog_time_stamp_t * t2)
406 { return (i64) t1->os_nsec - (i64) t2->os_nsec; }
407 
410  elog_time_stamp_t * t2)
411 { return (i64) t1->cpu - (i64) t2->cpu; }
412 
415 {
417  &em->init_time)
419  &em->init_time));
420 }
421 
422 void elog_alloc (elog_main_t * em, u32 n_events)
423 {
424  if (em->event_ring)
425  vec_free (em->event_ring);
426 
427  /* Ring size must be a power of 2. */
428  em->event_ring_size = n_events = max_pow2 (n_events);
429 
430  /* Leave an empty ievent at end so we can always speculatively write
431  and event there (possibly a long form event). */
433 }
434 
435 void elog_init (elog_main_t * em, u32 n_events)
436 {
437  memset (em, 0, sizeof (em[0]));
438 
439  em->lock = 0;
440 
441  if (n_events > 0)
442  elog_alloc (em, n_events);
443 
444  clib_time_init (&em->cpu_timer);
445 
447 
448  /* Make track 0. */
449  em->default_track.name = "default";
451 
452  elog_time_now (&em->init_time);
453 }
454 
455 /* Returns number of events in ring and start index. */
457 {
458  uword l = em->event_ring_size;
459  u64 i = em->n_total_events;
460 
461  /* Ring never wrapped? */
462  if (i <= (u64) l)
463  {
464  if (lo) *lo = 0;
465  return i;
466  }
467  else
468  {
469  if (lo) *lo = i & (l - 1);
470  return l;
471  }
472 }
473 
475 {
476  elog_event_t * e, * f, * es = 0;
477  uword i, j, n;
478 
479  n = elog_event_range (em, &j);
480  for (i = 0; i < n; i++)
481  {
482  vec_add2 (es, e, 1);
483  f = vec_elt_at_index (em->event_ring, j);
484  e[0] = f[0];
485 
486  /* Convert absolute time from cycles to seconds from start. */
488 
489  j = (j + 1) & (em->event_ring_size - 1);
490  }
491 
492  return es;
493 }
494 
495 /* Add a formatted string to the string table. */
496 u32 elog_string (elog_main_t * em, char * fmt, ...)
497 {
498  u32 offset;
499  va_list va;
500 
501  va_start (va, fmt);
502  offset = vec_len (em->string_table);
503  em->string_table = (char *) va_format ((u8 *) em->string_table, fmt, &va);
504  va_end (va);
505 
506  /* Null terminate string if it is not already. */
507  if (vec_end (em->string_table)[-1] != 0)
508  vec_add1 (em->string_table, 0);
509 
510  return offset;
511 }
512 
514 {
515  if (! em->events)
516  em->events = elog_peek_events (em);
517  return em->events;
518 }
519 
521  elog_event_type_t * t,
522  u32 offset)
523 {
524  void * d = (u8 *) e->data;
525  char * a;
526 
527  if (offset == 0)
528  return;
529 
530  a = t->format_args;
531 
532  while (1)
533  {
534  uword n_bytes = 0, n_digits;
535 
536  if (a[0] == 0)
537  break;
538 
539  /* Don't go past end of event data. */
540  ASSERT (d < (void *) (e->data + sizeof (e->data)));
541 
542  n_digits = parse_2digit_decimal (a + 1, &n_bytes);
543  switch (a[0])
544  {
545  case 'T':
546  ASSERT (n_bytes == 4);
547  clib_mem_unaligned (d, u32) += offset;
548  break;
549 
550  case 'i':
551  case 't':
552  case 'f':
553  case 's':
554  break;
555 
556  default:
557  ASSERT (0);
558  break;
559  }
560 
561  ASSERT (n_digits > 0 && n_digits <= 2);
562  a += 1 + n_digits;
563  d += n_bytes;
564  }
565 }
566 
567 static int elog_cmp (void * a1, void * a2)
568 {
569  elog_event_t * e1 = a1;
570  elog_event_t * e2 = a2;
571 
572  return e1->time - e2->time;
573 }
574 
575 void elog_merge (elog_main_t * dst, u8 * dst_tag,
576  elog_main_t * src, u8 * src_tag)
577 {
578  elog_event_t * e;
579  uword l;
580  u32 string_table_offset_for_src_events;
581  u32 track_offset_for_src_tracks;
582  elog_track_t newt;
583  int i;
584 
585  elog_get_events (src);
586  elog_get_events (dst);
587 
588  string_table_offset_for_src_events = vec_len (dst->string_table);
589  vec_append (dst->string_table, src->string_table);
590 
591  l = vec_len (dst->events);
592  vec_add (dst->events, src->events, vec_len (src->events));
593 
594  /* Prepend the supplied tag (if any) to all dst track names */
595  if (dst_tag)
596  {
597  for (i = 0; i < vec_len(dst->tracks); i++)
598  {
599  elog_track_t * t = vec_elt_at_index (dst->tracks, i);
600  char * new_name;
601 
602  new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
603  vec_free (t->name);
604  t->name = new_name;
605  }
606  }
607 
608  track_offset_for_src_tracks = vec_len (dst->tracks);
609 
610  /* Copy / tag source tracks */
611  for (i = 0; i < vec_len (src->tracks); i++)
612  {
613  elog_track_t * t = vec_elt_at_index (src->tracks, i);
614  if (src_tag)
615  newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
616  else
617  newt.name = (char *) format (0, "%s%c", t->name, 0);
618  (void) elog_track_register (dst, &newt);
619  vec_free (newt.name);
620  }
621 
622  /* Across all (copied) src events... */
623  for (e = dst->events + l; e < vec_end (dst->events); e++)
624  {
626 
627  /* Remap type from src -> dst. */
628  e->type = find_or_create_type (dst, t);
629 
630  /* Remap string table offsets for 'T' format args */
631  maybe_fix_string_table_offset (e, t, string_table_offset_for_src_events);
632 
633  /* Remap track */
634  e->track += track_offset_for_src_tracks;
635  }
636 
637  /* Adjust event times for relative starting times of event streams. */
638  {
639  f64 dt_event, dt_os_nsec, dt_clock_nsec;
640 
641  /* Set clock parameters if dst was not generated by unserialize. */
642  if (dst->serialize_time.cpu == 0)
643  {
644  dst->init_time = src->init_time;
645  dst->serialize_time = src->serialize_time;
647  }
648 
649  dt_os_nsec = elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
650 
651  dt_event = dt_os_nsec;
652  dt_clock_nsec = (elog_time_stamp_diff_cpu (&src->init_time, &dst->init_time)
653  * .5*(dst->nsec_per_cpu_clock + src->nsec_per_cpu_clock));
654 
655  /* Heuristic to see if src/dst came from same time source.
656  If frequencies are "the same" and os clock and cpu clock agree
657  to within 100e-9 secs about time difference between src/dst
658  init_time, then we use cpu clock. Otherwise we use OS clock. */
659  if (fabs (src->nsec_per_cpu_clock - dst->nsec_per_cpu_clock) < 1e-2
660  && fabs (dt_os_nsec - dt_clock_nsec) < 100)
661  dt_event = dt_clock_nsec;
662 
663  /* Convert to seconds. */
664  dt_event *= 1e-9;
665 
666  if (dt_event > 0)
667  {
668  /* Src started after dst. */
669  for (e = dst->events + l; e < vec_end (dst->events); e++)
670  e->time += dt_event;
671  }
672  else
673  {
674  /* Dst started after src. */
675  for (e = dst->events + 0; e < dst->events + l; e++)
676  e->time += dt_event;
677  }
678  }
679 
680  /* Sort events by increasing time. */
682 
683  /* Recreate the event ring or the results won't serialize */
684  {
685  int i;
686 
688 
689  elog_alloc (dst, vec_len (dst->events));
690  for (i = 0; i < vec_len(dst->events); i++)
691  {
692  elog_event_t *es, *ed;
693 
694  es = dst->events + i;
695  ed = dst->event_ring + i;
696 
697  ed[0] = es[0];
698 
699  /* Invert elog_peek_events calculation */
700  ed->time_cycles =
701  (es->time/dst->cpu_timer.seconds_per_clock) + dst->init_time.cpu;
702  }
703  dst->n_total_events = vec_len (dst->events);
704  }
705 }
706 
707 static void
709 {
710  elog_main_t * em = va_arg (*va, elog_main_t *);
711  elog_event_t * e = va_arg (*va, elog_event_t *);
713  u8 * d = e->data;
714  u8 * p = (u8 *) t->format_args;
715 
716  serialize_integer (m, e->type, sizeof (e->type));
717  serialize_integer (m, e->track, sizeof (e->track));
718  serialize (m, serialize_f64, e->time);
719 
720  while (*p)
721  {
722  uword n_digits, n_bytes = 0;
723 
724  n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
725 
726  switch (p[0])
727  {
728  case 'i':
729  case 't':
730  case 'T':
731  if (n_bytes == 1)
732  serialize_integer (m, d[0], sizeof (u8));
733  else if (n_bytes == 2)
734  serialize_integer (m, clib_mem_unaligned (d, u16), sizeof (u16));
735  else if (n_bytes == 4)
736  serialize_integer (m, clib_mem_unaligned (d, u32), sizeof (u32));
737  else if (n_bytes == 8)
739  else
740  ASSERT (0);
741  break;
742 
743  case 's':
744  serialize_cstring (m, (char *) d);
745  if (n_bytes == 0)
746  n_bytes = strlen ((char *) d) + 1;
747  break;
748 
749  case 'f':
750  if (n_bytes == 4)
752  else if (n_bytes == 8)
754  else
755  ASSERT (0);
756  break;
757 
758  default:
759  ASSERT (0);
760  break;
761  }
762 
763  p += 1 + n_digits;
764  d += n_bytes;
765  }
766 }
767 
768 static void
770 {
771  elog_main_t * em = va_arg (*va, elog_main_t *);
772  elog_event_t * e = va_arg (*va, elog_event_t *);
773  elog_event_type_t * t;
774  u8 * p, * d;
775 
776  {
777  u16 tmp[2];
778 
779  unserialize_integer (m, &tmp[0], sizeof (e->type));
780  unserialize_integer (m, &tmp[1], sizeof (e->track));
781 
782  e->type = tmp[0];
783  e->track = tmp[1];
784 
785  /* Make sure it fits. */
786  ASSERT (e->type == tmp[0]);
787  ASSERT (e->track == tmp[1]);
788  }
789 
790  t = vec_elt_at_index (em->event_types, e->type);
791 
792  unserialize (m, unserialize_f64, &e->time);
793 
794  d = e->data;
795  p = (u8 *) t->format_args;
796 
797  while (p && *p)
798  {
799  uword n_digits, n_bytes = 0;
800  u32 tmp;
801 
802  n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
803 
804  switch (p[0])
805  {
806  case 'i':
807  case 't':
808  case 'T':
809  if (n_bytes == 1)
810  {
811  unserialize_integer (m, &tmp, sizeof (u8));
812  d[0] = tmp;
813  }
814  else if (n_bytes == 2)
815  {
816  unserialize_integer (m, &tmp, sizeof (u16));
817  clib_mem_unaligned (d, u16) = tmp;
818  }
819  else if (n_bytes == 4)
820  {
821  unserialize_integer (m, &tmp, sizeof (u32));
822  clib_mem_unaligned (d, u32) = tmp;
823  }
824  else if (n_bytes == 8)
825  {
826  u64 x;
827  unserialize (m, unserialize_64, &x);
828  clib_mem_unaligned (d, u64) = x;
829  }
830  else
831  ASSERT (0);
832  break;
833 
834  case 's': {
835  char * t;
836  unserialize_cstring (m, &t);
837  if (n_bytes == 0)
838  n_bytes = strlen (t) + 1;
839  clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
840  vec_free (t);
841  break;
842  }
843 
844  case 'f':
845  if (n_bytes == 4)
846  {
847  f32 x;
848  unserialize (m, unserialize_f32, &x);
849  clib_mem_unaligned (d, f32) = x;
850  }
851  else if (n_bytes == 8)
852  {
853  f64 x;
854  unserialize (m, unserialize_f64, &x);
855  clib_mem_unaligned (d, f64) = x;
856  }
857  else
858  ASSERT (0);
859  break;
860 
861  default:
862  ASSERT (0);
863  break;
864  }
865 
866  p += 1 + n_digits;
867  d += n_bytes;
868  }
869 }
870 
871 static void
873 {
874  elog_event_type_t * t = va_arg (*va, elog_event_type_t *);
875  int n = va_arg (*va, int);
876  int i, j;
877  for (i = 0; i < n; i++)
878  {
879  serialize_cstring (m, t[i].format);
880  serialize_cstring (m, t[i].format_args);
881  serialize_integer (m, t[i].type_index_plus_one, sizeof (t->type_index_plus_one));
882  serialize_integer (m, t[i].n_enum_strings, sizeof (t[i].n_enum_strings));
883  for (j = 0; j < t[i].n_enum_strings; j++)
884  serialize_cstring (m, t[i].enum_strings_vector[j]);
885  }
886 }
887 
888 static void
890 {
891  elog_event_type_t * t = va_arg (*va, elog_event_type_t *);
892  int n = va_arg (*va, int);
893  int i, j;
894  for (i = 0; i < n; i++)
895  {
896  unserialize_cstring (m, &t[i].format);
897  unserialize_cstring (m, &t[i].format_args);
898  unserialize_integer (m, &t[i].type_index_plus_one, sizeof (t->type_index_plus_one));
899  unserialize_integer (m, &t[i].n_enum_strings, sizeof (t[i].n_enum_strings));
900  vec_resize (t[i].enum_strings_vector, t[i].n_enum_strings);
901  for (j = 0; j < t[i].n_enum_strings; j++)
902  unserialize_cstring (m, &t[i].enum_strings_vector[j]);
903  }
904 }
905 
906 static void
908 {
909  elog_track_t * t = va_arg (*va, elog_track_t *);
910  int n = va_arg (*va, int);
911  int i;
912  for (i = 0; i < n; i++)
913  {
914  serialize_cstring (m, t[i].name);
915  }
916 }
917 
918 static void
920 {
921  elog_track_t * t = va_arg (*va, elog_track_t *);
922  int n = va_arg (*va, int);
923  int i;
924  for (i = 0; i < n; i++)
925  {
926  unserialize_cstring (m, &t[i].name);
927  }
928 }
929 
930 static void
932 {
933  elog_time_stamp_t * st = va_arg (*va, elog_time_stamp_t *);
934  serialize (m, serialize_64, st->os_nsec);
935  serialize (m, serialize_64, st->cpu);
936 }
937 
938 static void
940 {
941  elog_time_stamp_t * st = va_arg (*va, elog_time_stamp_t *);
943  unserialize (m, unserialize_64, &st->cpu);
944 }
945 
946 static char * elog_serialize_magic = "elog v0";
947 
948 void
950 {
951  elog_main_t * em = va_arg (*va, elog_main_t *);
952  elog_event_t * e;
953 
955 
956  serialize_integer (m, em->event_ring_size, sizeof (u32));
957 
961 
965 
966  /* Free old events (cached) in case they have changed. */
967  vec_free (em->events);
968  elog_get_events (em);
969 
970  serialize_integer (m, vec_len (em->events), sizeof (u32));
971 
972  /* SMP logs can easily have local time paradoxes... */
974 
975  vec_foreach (e, em->events)
976  serialize (m, serialize_elog_event, em, e);
977 }
978 
979 void
981 {
982  elog_main_t * em = va_arg (*va, elog_main_t *);
983  uword i;
984  u32 rs;
985 
987  strlen (elog_serialize_magic));
988 
989  unserialize_integer (m, &rs, sizeof (u32));
990  em->event_ring_size = rs;
991  elog_init (em, em->event_ring_size);
992 
996 
998  for (i = 0; i < vec_len (em->event_types); i++)
999  new_event_type (em, i);
1000 
1003 
1004  {
1005  u32 ne;
1006  elog_event_t * e;
1007 
1008  unserialize_integer (m, &ne, sizeof (u32));
1009  vec_resize (em->events, ne);
1010  vec_foreach (e, em->events)
1011  unserialize (m, unserialize_elog_event, em, e);
1012  }
1013 }
char ** enum_strings_vector
Definition: elog.h:76
always_inline uword max_pow2(uword x)
Definition: clib.h:245
f64 time
Definition: elog.h:55
elog_time_stamp_t serialize_time
Definition: elog.h:153
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
#define clib_min(x, y)
Definition: clib.h:295
void unserialize_check_magic(serialize_main_t *m, void *magic, u32 magic_bytes)
Definition: serialize.c:588
elog_event_t * elog_get_events(elog_main_t *em)
Definition: elog.c:513
static void maybe_fix_string_table_offset(elog_event_t *e, elog_event_type_t *t, u32 offset)
Definition: elog.c:520
always_inline f64 fabs(f64 x)
Definition: math.h:48
a
Definition: bitmap.h:393
void elog_time_now(elog_time_stamp_t *et)
Definition: elog.c:382
static void(BVT(clib_bihash)*h, BVT(clib_bihash_value)*v)
#define vec_serialize(m, v, f)
Definition: serialize.h:367
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
word elog_track_register(elog_main_t *em, elog_track_t *t)
Definition: elog.c:179
elog_time_stamp_t init_time
Definition: elog.h:153
#define vec_unserialize(m, v, f)
Definition: serialize.h:370
serialize_function_t unserialize_64
Definition: serialize.h:351
u64 time_cycles
Definition: elog.h:52
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
u8 * format_elog_track(u8 *s, va_list *va)
Definition: elog.c:374
char * function
Definition: elog.h:91
always_inline i64 elog_time_stamp_diff_cpu(elog_time_stamp_t *t1, elog_time_stamp_t *t2)
Definition: elog.c:409
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:519
#define hash_set_mem(h, key, value)
Definition: hash.h:257
static void elog_lock(elog_main_t *em)
Definition: elog.c:45
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
char * format
Definition: elog.h:79
static uword find_or_create_type(elog_main_t *em, elog_event_type_t *t)
Definition: elog.c:80
serialize_function_t serialize_64
Definition: serialize.h:351
u8 data[20]
Definition: elog.h:67
static void serialize_elog_time_stamp(serialize_main_t *m, va_list *va)
Definition: elog.c:931
char * enum_strings[]
Definition: elog.h:97
static void unserialize_elog_event_type(serialize_main_t *m, va_list *va)
Definition: elog.c:889
static void new_event_type(elog_main_t *em, uword i)
Definition: elog.c:69
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:557
void unserialize_elog_main(serialize_main_t *m, va_list *va)
Definition: elog.c:980
float f32
Definition: types.h:141
u32 n_enum_strings
Definition: elog.h:94
always_inline f64 elog_nsec_per_clock(elog_main_t *em)
Definition: elog.c:414
serialize_function_t unserialize_f32
Definition: serialize.h:356
static void unserialize_elog_event(serialize_main_t *m, va_list *va)
Definition: elog.c:769
void elog_init(elog_main_t *em, u32 n_events)
Definition: elog.c:435
word elog_event_type_register(elog_main_t *em, elog_event_type_t *t)
Definition: elog.c:98
#define always_inline
Definition: clib.h:84
u32 type_index_plus_one
Definition: elog.h:73
always_inline void unserialize_integer(serialize_main_t *m, void *x, u32 n_bytes)
Definition: serialize.h:181
static void unserialize_elog_time_stamp(serialize_main_t *m, va_list *va)
Definition: elog.c:939
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
uword * lock
Definition: elog.h:156
unsigned long u64
Definition: types.h:89
static uword elog_event_range(elog_main_t *em, uword *lo)
Definition: elog.c:456
char * format_args
Definition: elog.h:88
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:199
#define vec_end(v)
End (last data address) of vector.
uword * event_type_by_format
Definition: elog.h:139
static int elog_cmp(void *a1, void *a2)
Definition: elog.c:567
elog_event_type_t * event_types
Definition: elog.h:136
static uword parse_2digit_decimal(char *p, uword *number)
Definition: elog.c:202
static char * elog_serialize_magic
Definition: elog.c:946
char * name
Definition: elog.h:102
elog_event_t * event_ring
Definition: elog.h:133
static void serialize_elog_event_type(serialize_main_t *m, va_list *va)
Definition: elog.c:872
#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
f64 seconds_per_clock
Definition: time.h:56
static void unserialize_elog_track(serialize_main_t *m, va_list *va)
Definition: elog.c:919
long i64
Definition: types.h:82
void clib_time_init(clib_time_t *c)
Definition: time.c:160
void elog_alloc(elog_main_t *em, u32 n_events)
Definition: elog.c:422
serialize_function_t unserialize_f64
Definition: serialize.h:355
void unserialize_cstring(serialize_main_t *m, char **s)
Definition: serialize.c:148
static void elog_unlock(elog_main_t *em)
Definition: elog.c:52
clib_error_t * serialize(serialize_main_t *m,...)
Definition: serialize.c:627
u8 * va_format(u8 *s, char *fmt, va_list *va)
Definition: format.c:374
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
#define clib_memcpy(a, b, c)
Definition: string.h:63
static void serialize_elog_event(serialize_main_t *m, va_list *va)
Definition: elog.c:708
u32 track_index_plus_one
Definition: elog.h:106
always_inline void serialize_integer(serialize_main_t *m, u64 x, u32 n_bytes)
Definition: serialize.h:165
u32 n_total_events_disable_limit
Definition: elog.h:123
static void serialize_elog_track(serialize_main_t *m, va_list *va)
Definition: elog.c:907
serialize_function_t unserialize_vec_8
Definition: serialize.h:359
void serialize_magic(serialize_main_t *m, void *magic, u32 magic_bytes)
Definition: serialize.c:580
#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
clib_error_t * unserialize(serialize_main_t *m,...)
Definition: serialize.c:639
#define vec_append(v1, v2)
Append v2 after v1.
Definition: vec.h:777
u16 track
Definition: elog.h:64
void elog_merge(elog_main_t *dst, u8 *dst_tag, elog_main_t *src, u8 *src_tag)
Definition: elog.c:575
clib_time_t cpu_timer
Definition: elog.h:151
serialize_function_t serialize_f32
Definition: serialize.h:356
u64 uword
Definition: types.h:112
void serialize_cstring(serialize_main_t *m, char *s)
Definition: serialize.c:135
#define vec_elt(v, i)
Get vector value at index i.
elog_event_t * events
Definition: elog.h:163
unsigned short u16
Definition: types.h:57
#define hash_create_vec(elts, key_bytes, value_bytes)
Definition: hash.h:601
i64 word
Definition: types.h:111
serialize_function_t serialize_vec_8
Definition: serialize.h:359
u32 elog_string(elog_main_t *em, char *fmt,...)
Definition: elog.c:496
#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
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:898
void * elog_event_data(elog_main_t *em, elog_event_type_t *type, elog_track_t *track, u64 cpu_time)
Definition: elog.c:63
elog_track_t * tracks
Definition: elog.h:145
#define clib_mem_unaligned(pointer, type)
Definition: types.h:153
#define hash_get_mem(h, key)
Definition: hash.h:251
static u8 * fixed_format(u8 *s, char *fmt, char *result, uword *result_len)
Definition: elog.c:228
char * string_table
Definition: elog.h:142
#define vec_foreach(var, vec)
Vector iterator.
elog_track_t default_track
Definition: elog.h:148
always_inline i64 elog_time_stamp_diff_os_nsec(elog_time_stamp_t *t1, elog_time_stamp_t *t2)
Definition: elog.c:404
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:101
u32 n_total_events
Definition: elog.h:119
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
always_inline u64 clib_cpu_time_now(void)
Definition: time.h:71
elog_event_t * elog_peek_events(elog_main_t *em)
Definition: elog.c:474
serialize_function_t serialize_f64
Definition: serialize.h:355
#define vec_resize_aligned(V, N, A)
Resize a vector (no header, alignment specified).
Definition: vec.h:212