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